Internal PHP and gdb php core
Agenda
• Overview• PHP lifecycle• Zend Engine 2 & PHP Opcodes• PHP 变量• PHP 函数• PHP OO• Some Details• PHP extensions• gdb php core
Overview
Overview
• Php 5.2.x
– Zend Engine 2.0
• OO的改进
Overview –代码结构
• main – php的核心文件以及基础设施
• Zend– Zend engine2 – 词法语法分析,虚拟机,所有与”php”相关的
• ext– 扩展目录
• sapi– 服务器抽象层(mod_php,fastcgi,etc)
• TSRM– 线程安全相关
PHP lifecycle - CLI
PHP lifecycle – Apache Multiprocess
Individual process life cycle
PHP lifecycle – Apache Multiprocess
Multiprocess life cycles
PHP lifecycle –扩展
• PHP_MINIT_FUNCTION(mysqli);
• PHP_MSHUTDOWN_FUNCTION(mysqli);
• PHP_RINIT_FUNCTION(mysqli);
• PHP_RSHUTDOWN_FUNCTION(mysqli);
PHP lifecycle – execute PHP
• Lexical Analysis
• Syntax Analysis
• Opcodes Generation
• Opcodes Execution
PHP lifecycle – PHP Execution
*.php
lex
Exprs
yacc
opcodesZendvm
zend_language_scanner.l
zend_language_parser.y
eAccelerator(eacc)
eaccelerator.c, PHP_MINIT_FUNCTION(eaccelerator)
PHP lifecycle – tokens
zend_language_scanner.l 中有所有token的定义,php的token_get_all函数可以获得一段php代码的token
Opcodeszend_op_array
Zend Engine 2 & PHP Opcodes
php_execute_script()
zend_execute_scripts()
zend_execute()
user call
(function/method)
包括定义在php中的函数和扩展里的函数
include/require
zend_compile_file()
函数指针
Zend engine 整体流程
Zend Engine 2 - execute_scripts
• PHPAPI int php_execute_script(zend_file_handle *primary_file TSRMLS_DC) (main/main.c)
• ZEND_API int zend_execute_scripts(int type TSRMLS_DC, zval **retval, intfile_count, ...) (Zend/zend.c)
• php_execute_script把auto_prepend_file,primary_file,auto_prepend_file这三个文件传给zend_execute_scripts
Zend Engine 2 - zend_compile_file
• Zend/zend.c zend_startup
• 默认指向compile_file() in zend_language_scanner.c
• ZEND_API zend_op_array *compile_file(zend_file_handle*file_handle, int type TSRMLS_DC)
• Lexical Analysis -> Syntax Analysis -> Opcodes Generation
PHP Opcodes
<?phpecho "hello world!";
通过vld扩展可以查看opcode,space@bb-space-test000/home/space/php5/bin/php -dvld.active=1 test3.php
PHP Opcodes
<?phpfunction testHello(){
return "hello world";}echo testHello();
PHP Opcodesstruct _zend_op {
opcode_handler_t handler; //每一个opcode对应的回调znode result;znode op1;znode op2;ulong extended_value;uint lineno;zend_uchar opcode; // opcode值
};typedef int (*opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);typedef unsigned char zend_uchar;//zend_compile.h( _zend_op_array 也在这里)
PHP Opcodes
• Opcodes由zend_execute来执行
• 默认情况,zend_execute指向zend_vm_execute.h的ZEND_API void execute(zend_op_array *op_arrayTSRMLS_DC)
• 每个opcode的回调都存在全局变量zend_opcode_handlers中,初始化在zend_init_opcodes_handlers()
• 回调命名规则ZEND_[opcode]_SPEC_(变量类型1)_(变量类型2)_HANDLER
PHP 变量
• 弱类型
typedef union _zvalue_value {long lval; /* long value */double dval; /* double value */struct {
char *val;int len;
} str;HashTable *ht; /* hash table value */zend_object_value obj;
} zvalue_value;
//zend.htypedef struct _zval_struct zval;struct _zval_struct {
/* Variable information */zvalue_value value; /* value */zend_uint refcount;zend_uchar type; /* active type */zend_uchar is_ref;
};
PHP 变量 - type
/* data types */ // zval.type/* All data types <= IS_BOOL have their constructor/destructors
skipped */#define IS_NULL 0#define IS_LONG 1#define IS_DOUBLE 2#define IS_BOOL 3#define IS_ARRAY 4#define IS_OBJECT 5#define IS_STRING 6#define IS_RESOURCE 7#define IS_CONSTANT 8#define IS_CONSTANT_ARRAY 9
PHP 变量 - HashTable
• 整个zend engine最核心的数据结构
• 不仅仅是php中的array,ze中大量采用HashTable来实现自己的逻辑,比如OO的逻辑,全局大变量等等
• zend_hash.h
PHP 函数
<?phpfcrypt_hstr_2id("space","aaaa");strstr("abcde","abc");echo "done";
PHP中的user_function和扩展中的函数都是DO_FCALL指令,echo是指令不是函数
PHP 函数
• DO_FCALL最终调到static intzend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)// zend_vm_execute.h
zend_do_fcall_common_helper_SPEC
PHP 函数
• 两种类型函数
– User function(写在php代码中的函数)
– Internal function(扩展中的函数)
• Php代码的函数栈会在zend vm中也体现出来!
–就是zend_do_fcall_common_helper_SPEC形成的栈(还包括execute,zend_execute_internal等)
• abc
PHP 函数 –函数类型
#define ZEND_INTERNAL_FUNCTION 1#define ZEND_USER_FUNCTION 2#define ZEND_OVERLOADED_FUNCTION 3#define ZEND_EVAL_CODE 4#define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
typedef union _zend_function {zend_uchar type; /* MUST be the first element of this struct! */
struct {zend_uchar type; /* never used */char *function_name;zend_class_entry *scope;zend_uint fn_flags;union _zend_function *prototype;zend_uint num_args;zend_uint required_num_args;zend_arg_info *arg_info;zend_bool pass_rest_by_reference;unsigned char return_reference;
} common;
zend_op_array op_array;zend_internal_function internal_function;
} zend_function;
PHP OOstruct _zend_class_entry {
char type;char *name;zend_uint name_length;struct _*parent;int refcozend_class_entry unt;HashTable function_table;HashTable default_properties;HashTable properties_info;HashTable default_static_members;HashTable *static_members;HashTable constants_table;struct _zend_function_entry *builtin_functions;union _zend_function *constructor;union _zend_function *destructor;union _zend_function *clone;union _zend_function *__get;union _zend_function *serialize_func;union _zend_function *unserialize_func;……..
Some Details
• 大量的宏
– # define EG(v) (executor_globals.v) //Zend/zend_globals_macros.h
– #define EX(element) execute_data->element
比较重要的全局变量
• ZEND_API zend_compiler_globalscompiler_globals;
• ZEND_API zend_executor_globalsexecutor_globals;
• 尤其对于executor_globals会有大量的运行时数据
PHP extensions(学习hack php的一些思路)
• eAccelerator
• Xdebug
• Xphrof
PHP extensions - eAccelerator
• PHP_MINIT_FUNCTION(eaccelerator) 中zend_compile_file = eaccelerator_compile_file;
• eaccelerator_compile_file会首先从cache中读opcode,没有cache才会重新生成,cache
• 来实现opcode cache
PHP extensions - xdebug
• 函数调用的性能分析
// PHP_MINIT_FUNCTION old_compile_file = zend_compile_file;zend_compile_file = xdebug_compile_file;xdebug_old_execute = zend_execute;zend_execute = xdebug_execute;
xdebug_orig_header_handler = sapi_module.header_handler;sapi_module.header_handler = xdebug_header_handler;
xdebug_execute做完一堆
事情后,再调回xdebug_old_execute
PHP extensions - xdebug
• 代码覆盖率分析
// PHP_MINIT_FUNCTIONif (XG(coverage_enable)) {
XDEBUG_SET_OPCODE_OVERRIDE_COMMON(ZEND_JMP);XDEBUG_SET_OPCODE_OVERRIDE_COMMON(ZEND_JMPZ);XDEBUG_SET_OPCODE_OVERRIDE_COMMON(ZEND_JMPZ_EX);XDEBUG_SET_OPCODE_OVERRIDE_COMMON(ZEND_JMPNZ);
#define XDEBUG_SET_OPCODE_OVERRIDE_COMMON(oc) \zend_set_user_opcode_handler(oc, xdebug_common_override_handler);
PHP extensions - Xphrof
• PHP_FUNCTION(xhprof_enable) 中进行
_zend_compile_file = zend_compile_file;zend_compile_file = hp_compile_file;/* Replace zend_execute with our proxy */_zend_execute = zend_execute;zend_execute = hp_execute;
gdb php core
类似于下面这种,需要了解php的逻辑来排查问题的
gdb php core
• source ~/php-5.2.10/.gdbinit 初始化一些gdb命令(方便查询hashtable)
• 如果获取当前执行在php的那个函数?
gdb php core –在哪个类?
gdb php core –获取php中的全局变量
• $_SERVER,$_GET,$_POST 等这些php代码中的大变量如何获取?
• executor_globals
• executor_globals->symbol_table 全局的变量在这个符号表里
这次没有涉及到的
• PHP SAPI架构• PHP HashTable细节• PHP内存管理• PHP ZTS & TSRM等线程安全机制• OO的更多细节以及如何编写OO扩展• 变量的作用域• Zend vm更深入的分析• 等等• 这些内容也期待大家共同参与
参考资料
• Php.net
• Extending and Embedding PHP
• http://www.php-internal.com/
• http://www.laruence.com/
Thank you!