├── CREDITS ├── EXPERIMENTAL ├── README.md ├── config.m4 ├── config.w32 ├── demo.php ├── opcodedump.c ├── opcodedump.php ├── php_opcodedump.h └── tests └── 001.phpt /CREDITS: -------------------------------------------------------------------------------- 1 | opcodedump 2 | -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phppan/opcodedump/de427fce210423384d5f6910784ab80ea4236482/EXPERIMENTAL -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | php7的opcode dump 2 | 3 | 函数列表: 4 | ## dasm_file 函数 5 | ### 定义和用法 6 | Disassemble file into opcode array by filename 7 | 8 | ### 语法 9 | dasm_file(string filename) 10 | 11 | ## dasm_string 函数 12 | ### 定义和用法 13 | Disassemble php code into opcode array 14 | 15 | ### 语法 16 | dasm_file(string code) 17 | 18 | 19 | 20 | ## 编译 21 | 22 | 1. $ cd ext/opcodedump 23 | 1. $ [phpize-cmd-path] 24 | 1. $ ./configure --with-php-config=[php-config-cmd-path] 25 | 1. $ make && make install 26 | 1. $ [php7-cmd-path] -f ext/opcodedump/opcodedump.php 27 | 28 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension opcodedump 3 | 4 | dnl Comments in this file start with the string 'dnl'. 5 | dnl Remove where necessary. This file will not work 6 | dnl without editing. 7 | 8 | dnl If your extension references something external, use with: 9 | 10 | dnl PHP_ARG_WITH(opcodedump, for opcodedump support, 11 | dnl Make sure that the comment is aligned: 12 | dnl [ --with-opcodedump Include opcodedump support]) 13 | 14 | dnl Otherwise use enable: 15 | 16 | PHP_ARG_ENABLE(opcodedump, whether to enable opcodedump support, 17 | Make sure that the comment is aligned: 18 | [ --enable-opcodedump Enable opcodedump support]) 19 | 20 | if test "$PHP_OPCODEDUMP" != "no"; then 21 | dnl Write more examples of tests here... 22 | 23 | dnl # --with-opcodedump -> check with-path 24 | dnl SEARCH_PATH="/usr/local /usr" # you might want to change this 25 | dnl SEARCH_FOR="/include/opcodedump.h" # you most likely want to change this 26 | dnl if test -r $PHP_OPCODEDUMP/$SEARCH_FOR; then # path given as parameter 27 | dnl OPCODEDUMP_DIR=$PHP_OPCODEDUMP 28 | dnl else # search default path list 29 | dnl AC_MSG_CHECKING([for opcodedump files in default path]) 30 | dnl for i in $SEARCH_PATH ; do 31 | dnl if test -r $i/$SEARCH_FOR; then 32 | dnl OPCODEDUMP_DIR=$i 33 | dnl AC_MSG_RESULT(found in $i) 34 | dnl fi 35 | dnl done 36 | dnl fi 37 | dnl 38 | dnl if test -z "$OPCODEDUMP_DIR"; then 39 | dnl AC_MSG_RESULT([not found]) 40 | dnl AC_MSG_ERROR([Please reinstall the opcodedump distribution]) 41 | dnl fi 42 | 43 | dnl # --with-opcodedump -> add include path 44 | dnl PHP_ADD_INCLUDE($OPCODEDUMP_DIR/include) 45 | 46 | dnl # --with-opcodedump -> check for lib and symbol presence 47 | dnl LIBNAME=opcodedump # you may want to change this 48 | dnl LIBSYMBOL=opcodedump # you most likely want to change this 49 | 50 | dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, 51 | dnl [ 52 | dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $OPCODEDUMP_DIR/$PHP_LIBDIR, OPCODEDUMP_SHARED_LIBADD) 53 | dnl AC_DEFINE(HAVE_OPCODEDUMPLIB,1,[ ]) 54 | dnl ],[ 55 | dnl AC_MSG_ERROR([wrong opcodedump lib version or lib not found]) 56 | dnl ],[ 57 | dnl -L$OPCODEDUMP_DIR/$PHP_LIBDIR -lm 58 | dnl ]) 59 | dnl 60 | dnl PHP_SUBST(OPCODEDUMP_SHARED_LIBADD) 61 | 62 | PHP_NEW_EXTENSION(opcodedump, opcodedump.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) 63 | fi 64 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | // If your extension references something external, use ARG_WITH 5 | // ARG_WITH("opcodedump", "for opcodedump support", "no"); 6 | 7 | // Otherwise, use ARG_ENABLE 8 | // ARG_ENABLE("opcodedump", "enable opcodedump support", "no"); 9 | 10 | if (PHP_OPCODEDUMP != "no") { 11 | EXTENSION("opcodedump", "opcodedump.c", PHP_EXTNAME_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /demo.php: -------------------------------------------------------------------------------- 1 | 'California', 'CO' => 'Colorado',); 33 | echo "In " . __FUNCTION__. "\n"; 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /opcodedump.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2017 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id$ */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include "php.h" 26 | #include "php_ini.h" 27 | #include "ext/standard/info.h" 28 | #include "php_opcodedump.h" 29 | 30 | void dasm_zend_op_array(zval *dst, const zend_op_array *src ); 31 | 32 | /* If you declare any globals in php_opcodedump.h uncomment this: 33 | ZEND_DECLARE_MODULE_GLOBALS(opcodedump) 34 | */ 35 | 36 | /* True global resources - no need for thread safety here */ 37 | static int le_opcodedump; 38 | 39 | 40 | 41 | /* {{{ PHP_INI 42 | */ 43 | /* Remove comments and fill if you need to have entries in php.ini 44 | PHP_INI_BEGIN() 45 | STD_PHP_INI_ENTRY("opcodedump.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_opcodedump_globals, opcodedump_globals) 46 | STD_PHP_INI_ENTRY("opcodedump.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_opcodedump_globals, opcodedump_globals) 47 | PHP_INI_END() 48 | */ 49 | /* }}} */ 50 | 51 | /* Remove the following function when you have successfully modified config.m4 52 | so that your module can be compiled into PHP, it exists only for testing 53 | purposes. */ 54 | 55 | 56 | void dasm_zend_arg_info(zval * dst, const zend_arg_info *src ) 57 | { 58 | 59 | 60 | if (src->name == NULL) { 61 | add_assoc_null(dst, "name"); 62 | add_assoc_long(dst, "name_len", 0); 63 | } else { 64 | add_assoc_string(dst, "name", ZSTR_VAL(src->name)); 65 | add_assoc_long(dst, "name_len", ZSTR_LEN(src->name)); 66 | } 67 | 68 | 69 | if (src->class_name == NULL) { 70 | add_assoc_null(dst, ("class_name")); 71 | add_assoc_long(dst, ("class_name_len"), 0); 72 | } else { 73 | add_assoc_string(dst, ("class_name"), ZSTR_VAL(src->class_name)); 74 | add_assoc_long(dst, ("class_name_len"), ZSTR_LEN(src->class_name)); 75 | } 76 | 77 | add_assoc_long_ex(dst, ("type_hint"), (sizeof("type_hint")), src->type_hint); 78 | add_assoc_bool_ex(dst, ("pass_by_reference"), (sizeof("pass_by_reference")), src->pass_by_reference ? 1 : 0); 79 | add_assoc_bool_ex(dst, ("allow_null"), (sizeof("allow_null")), src->allow_null ? 1 : 0); 80 | add_assoc_bool_ex(dst, ("is_variadic"), (sizeof("is_variadic")), src->is_variadic ? 1 : 0); 81 | } 82 | 83 | void dasm_zend_uint_array(zval *dst, const uint32_t *src ) 84 | { 85 | int len = sizeof(src)/sizeof(uint32_t); 86 | 87 | if (len > 0) { 88 | int i; 89 | 90 | for (i = 0; i < len; i++ ) { 91 | add_next_index_long(dst, src[i]); 92 | } 93 | } 94 | 95 | } 96 | 97 | 98 | static void inline dasm_zend_op(zval *dst, const zend_op *src ) 99 | { 100 | add_assoc_long_ex(dst, ("opcode"), (sizeof("opcode")), src->opcode); 101 | add_assoc_long_ex(dst, ("op1_type"), (sizeof("op1_type")), src->op1_type); 102 | add_assoc_long_ex(dst, ("op2_type"), (sizeof("op2_type")), src->op2_type); 103 | add_assoc_long_ex(dst, ("result_type"), (sizeof("result_type")), src->result_type); 104 | add_assoc_long_ex(dst, ("extended_value"), (sizeof("extended_value")), src->extended_value); 105 | add_assoc_long_ex(dst, ("lineno"), (sizeof("lineno")), src->lineno); 106 | 107 | 108 | add_assoc_long_ex(dst, ("result.constant"), (sizeof("result.constant")), src->result.constant); 109 | add_assoc_long_ex(dst, ("result.var"), (sizeof("result.var")), src->result.var); 110 | add_assoc_long_ex(dst, ("result.num"), (sizeof("result.num")), src->result.num); 111 | add_assoc_long_ex(dst, ("result.opline_num"), (sizeof("result.opline_num")), src->result.opline_num); 112 | 113 | 114 | add_assoc_long_ex(dst, ("op1.constant"), (sizeof("op1.constant")), src->op1.constant); 115 | add_assoc_long_ex(dst, ("op1.var"), (sizeof("op1.var")), src->op1.var); 116 | add_assoc_long_ex(dst, ("op1.num"), (sizeof("op1.num")), src->op1.num); 117 | add_assoc_long_ex(dst, ("op1.opline_num"), (sizeof("op1.opline_num")), src->op1.opline_num); 118 | 119 | 120 | 121 | add_assoc_long_ex(dst, ("op2.constant"), (sizeof("op2.constant")), src->op2.constant); 122 | add_assoc_long_ex(dst, ("op2.var"), (sizeof("op2.var")), src->op2.var); 123 | add_assoc_long_ex(dst, ("op2.num"), (sizeof("op2.num")), src->op2.num); 124 | add_assoc_long_ex(dst, ("op2.opline_num"), (sizeof("op2.opline_num")), src->op2.opline_num); 125 | 126 | } 127 | 128 | 129 | #if defined(ZEND_ENGINE_7_0) 130 | static void inline dasm_zend_brk_cont_element(zval *dst, const zend_brk_cont_element * src) 131 | { 132 | add_assoc_long_ex(dst, ("start"), (sizeof("start")), src->start); 133 | add_assoc_long_ex(dst, ("cont"), (sizeof("cont")), src->cont); 134 | add_assoc_long_ex(dst, ("brk"), (sizeof("brk")), src->brk); 135 | add_assoc_long_ex(dst, ("parent"), (sizeof("parent")), src->parent); 136 | } 137 | #endif 138 | 139 | #if defined(ZEND_ENGINE_7_1) 140 | static void inline dasm_zend_live_range(zval *dst, const zend_live_range *src ) 141 | { 142 | add_assoc_long_ex(dst, ("var"), (sizeof("var")), src->var); 143 | add_assoc_long_ex(dst, ("start"), (sizeof("start")), src->start); 144 | add_assoc_long_ex(dst, ("end"), (sizeof("end")), src->end); 145 | } 146 | #endif 147 | 148 | 149 | static void inline dasm_zend_try_catch_element(zval *dst, const zend_try_catch_element *src) 150 | { 151 | add_assoc_long_ex(dst, ("try_op"), (sizeof("try_op")), src->try_op); 152 | add_assoc_long_ex(dst, ("catch_op"), (sizeof("catch_op")), src->catch_op); 153 | add_assoc_long_ex(dst, ("finally_op"), (sizeof("finally_op")), src->finally_op); 154 | add_assoc_long_ex(dst, ("finally_end"), (sizeof("finally_end")), src->finally_end); 155 | } 156 | 157 | 158 | 159 | 160 | static void inline dasm_HashTable(zval *dst, HashTable *src) 161 | { 162 | ulong num_key; 163 | zend_string *key; 164 | zval *val; 165 | 166 | 167 | ZEND_HASH_FOREACH_KEY_VAL(src, num_key, key, val) { 168 | zval zv; 169 | array_init(&zv); 170 | ZVAL_COPY_VALUE(&zv, val); 171 | add_next_index_zval(dst, &zv); 172 | }ZEND_HASH_FOREACH_END(); 173 | } 174 | /* }}} */ 175 | 176 | 177 | static void inline dasm_function_table(zval *dst, const HashTable *src) 178 | { 179 | zend_function *zif; 180 | 181 | ZEND_HASH_FOREACH_PTR(src, zif) { 182 | if (zif->common.type == ZEND_USER_FUNCTION) { 183 | zval zv; 184 | zend_op_array *op_array; 185 | array_init(&zv); 186 | add_assoc_long(&zv, "type", zif->type); 187 | op_array = &(zif->op_array); 188 | dasm_zend_op_array(&zv, op_array); 189 | 190 | zval array; 191 | array_init(&array); 192 | add_assoc_zval(&array, "op_array", &zv); 193 | add_assoc_zval(dst, ZSTR_VAL(zif->common.function_name), &array); 194 | // add_next_index_zval(dst, &zv); 195 | } 196 | 197 | } ZEND_HASH_FOREACH_END(); 198 | 199 | } 200 | /* }}} */ 201 | 202 | 203 | static void inline _dasm_properties_info(zval *dst, const zend_property_info *src ) 204 | { 205 | if (src->name == NULL) { 206 | add_assoc_null(dst, "name"); 207 | add_assoc_long(dst, "name_len", 0); 208 | } else { 209 | add_assoc_string(dst, "name", ZSTR_VAL(src->name)); 210 | add_assoc_long(dst, "name_len", ZSTR_LEN(src->name)); 211 | } 212 | 213 | 214 | if (src->doc_comment == NULL) { 215 | add_assoc_null(dst, "doc_comment"); 216 | add_assoc_long(dst, "doc_comment_len", 0); 217 | } else { 218 | add_assoc_string(dst, "doc_comment", ZSTR_VAL(src->doc_comment)); 219 | add_assoc_long(dst, "doc_comment_len", ZSTR_LEN(src->doc_comment)); 220 | } 221 | 222 | add_assoc_long(dst, "offset", src->offset); 223 | add_assoc_long(dst, "flags", src->flags); 224 | 225 | if (src->ce->name == NULL) { 226 | add_assoc_null(dst, "ce"); 227 | } else { 228 | add_assoc_string(dst, "ce", ZSTR_VAL(src->ce->name)); 229 | } 230 | 231 | /* 232 | uint32_t offset; 233 | uint32_t flags; 234 | zend_string *name; 235 | zend_string *doc_comment; 236 | zend_class_entry *ce; 237 | */ 238 | } 239 | 240 | 241 | /* {{{ add_class_vars */ 242 | static void inline dasm_properties_info(zval *dst, zend_class_entry *ce, int statics) 243 | { 244 | zend_property_info *prop_info; 245 | zval *prop, prop_copy; 246 | zend_string *key; 247 | 248 | ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) { 249 | if (((prop_info->flags & ZEND_ACC_SHADOW) && 250 | prop_info->ce != ce) || 251 | ((prop_info->flags & ZEND_ACC_PROTECTED) && 252 | !zend_check_protected(prop_info->ce, ce)) || 253 | ((prop_info->flags & ZEND_ACC_PRIVATE) && 254 | prop_info->ce != ce)) { 255 | continue; 256 | } 257 | prop = NULL; 258 | if (statics && (prop_info->flags & ZEND_ACC_STATIC) != 0) { 259 | prop = &ce->default_static_members_table[prop_info->offset]; 260 | } else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) { 261 | prop = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)]; 262 | } 263 | if (!prop) { 264 | continue; 265 | } 266 | 267 | 268 | zval zv; 269 | array_init(&zv); 270 | 271 | _dasm_properties_info(&zv, prop_info); 272 | add_assoc_zval(dst, ZSTR_VAL(prop_info->name), &zv); 273 | } ZEND_HASH_FOREACH_END(); 274 | 275 | } 276 | /* }}} */ 277 | 278 | 279 | static void inline dasm_zend_class_entry(zval *dst, zend_class_entry *src) 280 | { 281 | 282 | add_assoc_long_ex(dst, ("type"), (sizeof("type")), src->type); 283 | if (src->name == NULL) { 284 | add_assoc_null(dst, "name"); 285 | add_assoc_long(dst, "name_len", 0); 286 | } else { 287 | add_assoc_string(dst, "name", ZSTR_VAL(src->name)); 288 | add_assoc_long(dst, "name_len", ZSTR_LEN(src->name)); 289 | } 290 | 291 | 292 | if (src->parent) { 293 | add_assoc_string(dst, "parent", ZSTR_VAL(src->parent->name)); 294 | } else { 295 | add_assoc_null_ex(dst, ("parent"), (sizeof("parent"))); 296 | assert(src->parent == NULL); 297 | } 298 | 299 | add_assoc_long_ex(dst, ("refcount"), (sizeof("refcount")), src->refcount); 300 | add_assoc_long_ex(dst, ("ce_flags"), (sizeof("ce_flags")), src->ce_flags); 301 | add_assoc_long_ex(dst, ("default_properties_count"), (sizeof("default_properties_count")), src->default_properties_count); 302 | 303 | add_assoc_long_ex(dst, ("default_static_members_count"), (sizeof("default_static_members_count")), src->default_static_members_count); 304 | 305 | if (src->default_properties_table) { 306 | zval table; 307 | array_init(&table); 308 | for (int i= 0; i < src->default_properties_count; i++) { 309 | zval zv; 310 | ZVAL_COPY_VALUE(&zv, src->default_properties_table + i); 311 | add_next_index_zval(&table, &zv); 312 | } 313 | add_assoc_zval(dst, "default_properties_table", &table); 314 | }else{ 315 | add_assoc_null_ex(dst, ("default_properties_table"), (sizeof("default_properties_table"))); 316 | } 317 | 318 | if (src->default_static_members_table) { 319 | zval table; 320 | array_init(&table); 321 | for (int i= 0; i < src->default_static_members_count; i++) { 322 | zval zv; 323 | ZVAL_COPY_VALUE(&zv, src->default_static_members_table + i); 324 | add_next_index_zval(&table, &zv); 325 | } 326 | add_assoc_zval(dst, "default_static_members_table", &table); 327 | }else{ 328 | add_assoc_null_ex(dst, ("default_static_members_table"), (sizeof("default_static_members_table"))); 329 | } 330 | 331 | do { 332 | zval zv; 333 | array_init(&zv); 334 | dasm_function_table(&zv, &src->function_table); 335 | add_assoc_zval(dst, "function_table", &zv); 336 | } while(0); 337 | 338 | do { 339 | zval zv; 340 | array_init(&zv); 341 | dasm_properties_info(&zv, src, 0); 342 | dasm_properties_info(&zv, src, 1); 343 | add_assoc_zval(dst, "properties_info", &zv); 344 | } while(0); 345 | 346 | 347 | /* 348 | 349 | struct _zend_class_entry { 350 | char type; 351 | zend_string *name; 352 | struct _zend_class_entry *parent; 353 | int refcount; 354 | uint32_t ce_flags; 355 | 356 | int default_properties_count; 357 | int default_static_members_count; 358 | zval *default_properties_table; 359 | zval *default_static_members_table; 360 | zval *static_members_table; 361 | HashTable function_table; 362 | HashTable properties_info; 363 | HashTable constants_table; 364 | 365 | union _zend_function *constructor; 366 | union _zend_function *destructor; 367 | union _zend_function *clone; 368 | union _zend_function *__get; 369 | union _zend_function *__set; 370 | union _zend_function *__unset; 371 | union _zend_function *__isset; 372 | union _zend_function *__call; 373 | union _zend_function *__callstatic; 374 | union _zend_function *__tostring; 375 | union _zend_function *__debugInfo; 376 | union _zend_function *serialize_func; 377 | union _zend_function *unserialize_func; 378 | 379 | zend_class_iterator_funcs iterator_funcs; 380 | 381 | zend_object* (*create_object)(zend_class_entry *class_type); 382 | zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref); 383 | int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type); 384 | union _zend_function *(*get_static_method)(zend_class_entry *ce, zend_string* method); 385 | 386 | int (*serialize)(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data); 387 | int (*unserialize)(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data); 388 | 389 | uint32_t num_interfaces; 390 | uint32_t num_traits; 391 | zend_class_entry **interfaces; 392 | 393 | zend_class_entry **traits; 394 | zend_trait_alias **trait_aliases; 395 | zend_trait_precedence **trait_precedences; 396 | 397 | union { 398 | struct { 399 | zend_string *filename; 400 | uint32_t line_start; 401 | uint32_t line_end; 402 | zend_string *doc_comment; 403 | } user; 404 | struct { 405 | const struct _zend_function_entry *builtin_functions; 406 | struct _zend_module_entry *module; 407 | } internal; 408 | } info; 409 | }; 410 | */ 411 | 412 | } 413 | /* }}} */ 414 | 415 | static void inline dasm_class_table(zval *dst, const HashTable *src) 416 | { 417 | 418 | zend_class_entry *ce; 419 | 420 | ZEND_HASH_FOREACH_PTR(src, ce) { 421 | if (ce->type == ZEND_USER_CLASS) { 422 | zval zv; 423 | array_init(&zv); 424 | dasm_zend_class_entry(&zv, ce); 425 | add_assoc_zval(dst, ZSTR_VAL(ce->name), &zv); 426 | // add_next_index_zval(dst, &zv); 427 | } 428 | } ZEND_HASH_FOREACH_END(); 429 | } 430 | /* }}} */ 431 | 432 | 433 | 434 | // static void inline dasm_function_table() 435 | // { 436 | // return TG(internal_function_tail) ? TG(internal_function_tail)->pListNext : TG(function_table).pListHead; 437 | // } 438 | 439 | 440 | void dasm_zend_op_array(zval *dst, const zend_op_array *src ) 441 | { 442 | 443 | 444 | assert(sizeof(zend_uchar) == sizeof(src->type)); 445 | 446 | add_assoc_long_ex(dst, ("type"), (sizeof("type")), src->type); 447 | 448 | /* PROC_ZSTRING(,function_name) */ 449 | 450 | /* PROC_ZSTRING_N(,function_name,,strlen) */ 451 | 452 | 453 | if (src->function_name == NULL) { 454 | add_assoc_null(dst, "function_name"); 455 | } else { 456 | add_assoc_string(dst, "function_name", ZSTR_VAL(src->function_name)); 457 | } 458 | 459 | add_assoc_long_ex(dst, ("fn_flags"), (sizeof("fn_flags")), src->fn_flags); 460 | 461 | if (src->arg_info) { 462 | int i; 463 | 464 | zval arr; 465 | array_init(&arr); 466 | 467 | for (i = 0; i < src->num_args; ++i) { 468 | zval zv; 469 | 470 | array_init(&zv); 471 | dasm_zend_arg_info (&zv, &(src->arg_info[i])); 472 | add_next_index_zval(&arr, &zv); 473 | } 474 | add_assoc_zval(dst, "arg_info", &arr); 475 | }else{ 476 | add_assoc_null(dst, ("arg_info")); 477 | } 478 | 479 | 480 | add_assoc_long_ex(dst, ("num_args"), (sizeof("num_args")), src->num_args); 481 | add_assoc_long_ex(dst, ("required_num_args"), (sizeof("required_num_args")), src->required_num_args); 482 | 483 | if (src->refcount) { 484 | do { 485 | zval zv; 486 | array_init(&zv); 487 | dasm_zend_uint_array(&zv, src->refcount); 488 | add_assoc_zval_ex(dst, ("refcount"), (sizeof("refcount")), &zv); 489 | } while (0); 490 | } else { 491 | add_assoc_null_ex(dst, ("refcount"), (sizeof("refcount"))); 492 | assert(src->refcount == NULL); 493 | } 494 | 495 | 496 | if (src->literals) { 497 | int i; 498 | zval arr; 499 | array_init(&arr); 500 | 501 | for (i = 0; i < src->last_literal; ++i) { 502 | zval zv; 503 | array_init(&zv); 504 | ZVAL_COPY_VALUE(&zv, &(src->literals[i])); 505 | add_next_index_zval(&arr, &zv); 506 | } 507 | add_assoc_zval_ex(dst, ("literals"), (sizeof("literals")), &arr); 508 | }else{ 509 | add_assoc_null_ex(dst, ("literals"), (sizeof("literals"))); 510 | } 511 | 512 | add_assoc_long_ex(dst, ("last_literal"), (sizeof("last_literal")), src->last_literal); 513 | 514 | if (src->opcodes) { 515 | int i; 516 | zval arr; 517 | array_init(&arr); 518 | 519 | for (i = 0; i < src->last; ++i) { 520 | zval zv; 521 | array_init(&zv); 522 | dasm_zend_op (&zv, &(src->opcodes[i])); 523 | add_next_index_zval(&arr, &zv); 524 | } 525 | add_assoc_zval_ex(dst, ("opcodes"), (sizeof("opcodes")), &arr); 526 | } else { 527 | add_assoc_null_ex(dst, ("opcodes"), (sizeof("opcodes"))); 528 | 529 | assert(src->opcodes == NULL); 530 | } 531 | 532 | 533 | add_assoc_long_ex(dst, ("last"), (sizeof("last")), src->last); 534 | add_assoc_long_ex(dst, ("T"), (sizeof("T")), src->T); 535 | 536 | 537 | #if defined(ZEND_ENGINE_7_0) 538 | if (src->brk_cont_array) { 539 | int i; 540 | zval arr; 541 | array_init(&arr); 542 | 543 | for (i = 0; i < src->last_brk_cont; ++i) { 544 | zval zv; 545 | array_init(&zv); 546 | dasm_zend_brk_cont_element(&zv, &(src->brk_cont_array[i])); 547 | add_next_index_zval(&arr, &zv); 548 | } 549 | add_assoc_zval_ex(dst, ("brk_cont_array"), (sizeof("brk_cont_array")), &arr); 550 | } else { 551 | add_assoc_null_ex(dst, ("brk_cont_array"), (sizeof("brk_cont_array"))); 552 | assert(src->brk_cont_array == NULL); 553 | } 554 | 555 | add_assoc_long_ex(dst, ("last_brk_cont"), (sizeof("last_brk_cont")), src->last_brk_cont); 556 | 557 | #endif 558 | 559 | #if defined(ZEND_ENGINE_7_1) 560 | if (src->live_range) { 561 | int i; 562 | zval arr; 563 | array_init(&arr); 564 | 565 | for (i = 0; i < src->last_live_range; ++i) { 566 | zval zv; 567 | array_init(&zv); 568 | dasm_zend_live_range(&zv, &(src->live_range[i])); 569 | add_next_index_zval(&arr, &zv); 570 | } 571 | add_assoc_zval_ex(dst, ("live_range"), (sizeof("live_range")), &arr); 572 | } else { 573 | add_assoc_null_ex(dst, ("live_range"), (sizeof("live_range"))); 574 | assert(src->live_range == NULL); 575 | } 576 | 577 | add_assoc_long_ex(dst, ("last_live_range"), (sizeof("last_live_range")), src->last_live_range); 578 | #endif 579 | 580 | if (src->try_catch_array) { 581 | int i; 582 | 583 | zval arr; 584 | array_init(&arr); 585 | 586 | for (i = 0; i < src->last_try_catch; ++i) { 587 | zval zv; 588 | array_init(&zv); 589 | dasm_zend_try_catch_element (&zv, &(src->try_catch_array[i])); 590 | add_next_index_zval(&arr, &zv); 591 | } 592 | add_assoc_zval_ex(dst, ("try_catch_array"), (sizeof("try_catch_array")), &arr); 593 | } else { 594 | add_assoc_null_ex(dst, ("try_catch_array"), (sizeof("try_catch_array"))); 595 | assert(src->try_catch_array == NULL); 596 | } 597 | 598 | assert(sizeof(int) == sizeof(src->last_try_catch)); 599 | add_assoc_long_ex(dst, ("last_try_catch"), (sizeof("last_try_catch")), src->last_try_catch); 600 | 601 | 602 | if (src->static_variables && sizeof(HashTable) == sizeof(( src->static_variables)[0])) { 603 | 604 | do { 605 | zval zv; 606 | array_init(&zv); 607 | dasm_HashTable(&zv, src->static_variables ); 608 | add_assoc_zval_ex(dst, ("static_variables"), (sizeof("static_variables")), &zv); 609 | } while (0); 610 | 611 | } else { 612 | add_assoc_null_ex(dst, ("static_variables"), (sizeof("static_variables"))); 613 | assert(src->static_variables == NULL); 614 | } 615 | 616 | 617 | #if defined(ZEND_ENGINE_7_0) 618 | add_assoc_long_ex(dst, ("this_var"), (sizeof("this_var")), src->this_var); 619 | #endif 620 | 621 | if (src->filename == NULL) { 622 | add_assoc_null(dst, "filename"); 623 | } else { 624 | add_assoc_string(dst, "filename", ZSTR_VAL(src->filename)); 625 | } 626 | 627 | 628 | if (src->doc_comment == NULL) { 629 | add_assoc_null(dst, "doc_comment"); 630 | add_assoc_long(dst, "doc_comment_len", 0); 631 | } else { 632 | add_assoc_string(dst, "doc_comment", ZSTR_VAL(src->doc_comment)); 633 | add_assoc_long(dst, "doc_comment_len", ZSTR_LEN(src->doc_comment)); 634 | } 635 | 636 | 637 | add_assoc_long_ex(dst, ("line_start"), (sizeof("line_start")), src->line_start); 638 | add_assoc_long_ex(dst, ("line_end"), (sizeof("line_end")), src->line_end); 639 | add_assoc_long_ex(dst, ("early_binding"), (sizeof("early_binding")), src->early_binding); 640 | add_assoc_long_ex(dst, ("cache_size"), (sizeof("cache_size")), src->cache_size); 641 | 642 | if (src->vars) { 643 | int i; 644 | zval arr; 645 | array_init(&arr); 646 | 647 | for (i = 0; i < src->last_var; ++i) { 648 | add_next_index_string(&arr, ZSTR_VAL(src->vars[i])); 649 | } 650 | add_assoc_zval_ex(dst, ("vars"), (sizeof("vars")), &arr); 651 | } 652 | else { 653 | add_assoc_null_ex(dst, ("vars"), (sizeof("vars"))); 654 | assert(src->vars == NULL); 655 | } 656 | 657 | add_assoc_long_ex(dst, ("last_var"), (sizeof("last_var")), src->last_var); 658 | 659 | 660 | if (src->prototype) { 661 | zval zv; 662 | zend_op_array *op_array; 663 | array_init(&zv); 664 | add_assoc_long(&zv, "type", src->prototype->type); 665 | op_array = &(src->prototype->op_array); 666 | dasm_zend_op_array(&zv, op_array); 667 | 668 | add_assoc_zval_ex(dst, ("prototype"), (sizeof("prototype")), &zv); 669 | } else { 670 | add_assoc_null_ex(dst, ("prototype"), (sizeof("prototype"))); 671 | assert(src->prototype == NULL); 672 | } 673 | 674 | if (src->scope) { 675 | add_assoc_string(dst, "scope", ZSTR_VAL(src->scope->name)); 676 | } else { 677 | add_assoc_null_ex(dst, ("scope"), (sizeof("scope"))); 678 | assert(src->scope == NULL); 679 | } 680 | 681 | 682 | 683 | /* 684 | zend_uchar arg_flags[3]; 685 | zend_string *function_name; 686 | zend_class_entry *scope; 687 | zend_function *prototype; 688 | uint32_t num_args; 689 | uint32_t required_num_args; 690 | zend_arg_info *arg_info; 691 | 692 | uint32_t *refcount; 693 | 694 | uint32_t this_var; 695 | 696 | uint32_t last; 697 | zend_op *opcodes; 698 | 699 | int last_var; 700 | uint32_t T; 701 | zend_string **vars; 702 | 703 | int last_brk_cont; 704 | int last_try_catch; 705 | zend_brk_cont_element *brk_cont_array; 706 | zend_try_catch_element *try_catch_array; 707 | 708 | HashTable *static_variables; 709 | 710 | zend_string *filename; 711 | uint32_t line_start; 712 | uint32_t line_end; 713 | zend_string *doc_comment; 714 | uint32_t early_binding; 715 | 716 | int last_literal; 717 | zval *literals; 718 | 719 | int cache_size; 720 | void **run_time_cache; 721 | */ 722 | 723 | } 724 | 725 | 726 | /* {{{ proto array dasm_file(string filename) 727 | Disassemble file into opcode array by filename */ 728 | #ifdef ZEND_BEGIN_ARG_INFO_EX 729 | ZEND_BEGIN_ARG_INFO_EX(arginfo_dasm_file, 0, 0, 1) 730 | ZEND_ARG_INFO(0, filename) 731 | ZEND_END_ARG_INFO() 732 | #else 733 | static unsigned char arginfo_dasm_file[] = { 1, BYREF_NONE }; 734 | #endif 735 | 736 | PHP_FUNCTION(dasm_file) 737 | { 738 | char *filename; 739 | size_t filename_len; 740 | 741 | zend_string *strg; 742 | 743 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) { 744 | return; 745 | } 746 | if (!filename_len) RETVAL_FALSE; 747 | 748 | zend_op_array *op_array = NULL; 749 | 750 | zval zfilename; 751 | 752 | ZVAL_STRING(&zfilename, filename); 753 | 754 | op_array = compile_filename(ZEND_REQUIRE, &zfilename); 755 | 756 | zval_ptr_dtor(&zfilename); 757 | 758 | array_init(return_value); 759 | 760 | zval zv; 761 | array_init(&zv); 762 | dasm_zend_op_array(&zv, op_array); 763 | 764 | add_assoc_zval(return_value, "filename", &zfilename); 765 | add_assoc_zval_ex(return_value, ZEND_STRS("op_array"), &zv); 766 | 767 | 768 | if (CG(function_table)) { 769 | do { 770 | zval zv; 771 | array_init(&zv); 772 | dasm_function_table(&zv, CG(function_table)); 773 | add_assoc_zval_ex(return_value, ("function_table"), (sizeof("function_table")), &zv); 774 | } while (0); 775 | 776 | } else { 777 | add_assoc_null_ex(return_value, ("function_table"), (sizeof("function_table"))); 778 | } 779 | 780 | if (CG(class_table)) { 781 | do { 782 | zval zv; 783 | array_init(&zv); 784 | dasm_class_table(&zv, CG(class_table)); 785 | add_assoc_zval_ex(return_value, ("class_table"), (sizeof("class_table")), &zv); 786 | } while (0); 787 | 788 | } else { 789 | add_assoc_null_ex(return_value, ("class_table"), (sizeof("class_table"))); 790 | } 791 | } 792 | 793 | 794 | 795 | /* {{{ proto array dasm_string(string code) 796 | Disassemble php code into opcode array */ 797 | #ifdef ZEND_BEGIN_ARG_INFO_EX 798 | ZEND_BEGIN_ARG_INFO_EX(arginfo_dasm_string, 0, 0, 1) 799 | ZEND_ARG_INFO(0, code) 800 | ZEND_END_ARG_INFO() 801 | #else 802 | static unsigned char arginfo_dasm_string[] = { 1, BYREF_NONE }; 803 | #endif 804 | 805 | PHP_FUNCTION(dasm_string) 806 | { 807 | zval *code; 808 | 809 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &code) == FAILURE) { 810 | return; 811 | } 812 | 813 | zend_op_array *op_array = NULL; 814 | 815 | char *eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC); 816 | 817 | op_array = compile_string(code, eval_name TSRMLS_CC); 818 | 819 | array_init(return_value); 820 | 821 | zval zv; 822 | array_init(&zv); 823 | dasm_zend_op_array(&zv, op_array); 824 | 825 | add_assoc_zval_ex(return_value, ZEND_STRS("op_array"), &zv); 826 | 827 | 828 | if (CG(function_table)) { 829 | do { 830 | zval zv; 831 | array_init(&zv); 832 | dasm_function_table(&zv, CG(function_table)); 833 | add_assoc_zval_ex(return_value, ("function_table"), (sizeof("function_table")), &zv); 834 | } while (0); 835 | 836 | } else { 837 | add_assoc_null_ex(return_value, ("function_table"), (sizeof("function_table"))); 838 | } 839 | 840 | if (CG(class_table)) { 841 | do { 842 | zval zv; 843 | array_init(&zv); 844 | dasm_class_table(&zv, CG(class_table)); 845 | add_assoc_zval_ex(return_value, ("class_table"), (sizeof("class_table")), &zv); 846 | } while (0); 847 | 848 | } else { 849 | add_assoc_null_ex(return_value, ("class_table"), (sizeof("class_table"))); 850 | } 851 | 852 | } 853 | /* }}} */ 854 | 855 | 856 | /* The previous line is meant for vim and emacs, so it can correctly fold and 857 | unfold functions in source code. See the corresponding marks just before 858 | function definition, where the functions purpose is also documented. Please 859 | follow this convention for the convenience of others editing your code. 860 | */ 861 | 862 | 863 | /* {{{ php_opcodedump_init_globals 864 | */ 865 | /* Uncomment this function if you have INI entries 866 | static void php_opcodedump_init_globals(zend_opcodedump_globals *opcodedump_globals) 867 | { 868 | opcodedump_globals->global_value = 0; 869 | opcodedump_globals->global_string = NULL; 870 | } 871 | */ 872 | /* }}} */ 873 | 874 | /* {{{ PHP_MINIT_FUNCTION 875 | */ 876 | PHP_MINIT_FUNCTION(opcodedump) 877 | { 878 | /* If you have INI entries, uncomment these lines 879 | REGISTER_INI_ENTRIES(); 880 | */ 881 | return SUCCESS; 882 | } 883 | /* }}} */ 884 | 885 | /* {{{ PHP_MSHUTDOWN_FUNCTION 886 | */ 887 | PHP_MSHUTDOWN_FUNCTION(opcodedump) 888 | { 889 | /* uncomment this line if you have INI entries 890 | UNREGISTER_INI_ENTRIES(); 891 | */ 892 | return SUCCESS; 893 | } 894 | /* }}} */ 895 | 896 | /* Remove if there's nothing to do at request start */ 897 | /* {{{ PHP_RINIT_FUNCTION 898 | */ 899 | PHP_RINIT_FUNCTION(opcodedump) 900 | { 901 | #if defined(COMPILE_DL_OPCODEDUMP) && defined(ZTS) 902 | ZEND_TSRMLS_CACHE_UPDATE(); 903 | #endif 904 | return SUCCESS; 905 | } 906 | /* }}} */ 907 | 908 | /* Remove if there's nothing to do at request end */ 909 | /* {{{ PHP_RSHUTDOWN_FUNCTION 910 | */ 911 | PHP_RSHUTDOWN_FUNCTION(opcodedump) 912 | { 913 | return SUCCESS; 914 | } 915 | /* }}} */ 916 | 917 | /* {{{ PHP_MINFO_FUNCTION 918 | */ 919 | PHP_MINFO_FUNCTION(opcodedump) 920 | { 921 | php_info_print_table_start(); 922 | php_info_print_table_header(2, "opcodedump support", "enabled"); 923 | php_info_print_table_end(); 924 | 925 | /* Remove comments if you have entries in php.ini 926 | DISPLAY_INI_ENTRIES(); 927 | */ 928 | } 929 | /* }}} */ 930 | 931 | 932 | /* {{{ opcodedump_functions[] 933 | * 934 | * Every user visible function must have an entry in opcodedump_functions[]. 935 | */ 936 | const zend_function_entry opcodedump_functions[] = { 937 | PHP_FE(dasm_file, arginfo_dasm_file) 938 | PHP_FE(dasm_string, arginfo_dasm_string) 939 | 940 | PHP_FE_END /* Must be the last line in opcodedump_functions[] */ 941 | }; 942 | /* }}} */ 943 | 944 | /* {{{ opcodedump_module_entry 945 | */ 946 | zend_module_entry opcodedump_module_entry = { 947 | STANDARD_MODULE_HEADER, 948 | "opcodedump", 949 | opcodedump_functions, 950 | NULL, 951 | NULL, 952 | NULL, 953 | NULL, 954 | //PHP_MINIT(opcodedump), 955 | //PHP_MSHUTDOWN(opcodedump), 956 | //PHP_RINIT(opcodedump), Replace with NULL if there's nothing to do at request start 957 | //PHP_RSHUTDOWN(opcodedump), /* Replace with NULL if there's nothing to do at request end */ 958 | PHP_MINFO(opcodedump), 959 | PHP_OPCODEDUMP_VERSION, 960 | STANDARD_MODULE_PROPERTIES 961 | }; 962 | /* }}} */ 963 | 964 | #ifdef COMPILE_DL_OPCODEDUMP 965 | #ifdef ZTS 966 | ZEND_TSRMLS_CACHE_DEFINE() 967 | #endif 968 | ZEND_GET_MODULE(opcodedump) 969 | #endif 970 | 971 | /* 972 | * Local variables: 973 | * tab-width: 4 974 | * c-basic-offset: 4 975 | * End: 976 | * vim600: noet sw=4 ts=4 fdm=marker 977 | * vim<600: noet sw=4 ts=4 978 | */ 979 | -------------------------------------------------------------------------------- /opcodedump.php: -------------------------------------------------------------------------------- 1 | "; 3 | 4 | if(!extension_loaded('opcodedump')) { 5 | dl('opcodedump.' . PHP_SHLIB_SUFFIX); 6 | } 7 | $module = 'opcodedump'; 8 | $functions = get_extension_funcs($module); 9 | echo "Functions available in the test extension:$br\n"; 10 | foreach($functions as $func) { 11 | echo $func."$br\n"; 12 | } 13 | echo "$br\n"; 14 | 15 | $path = dirname(__FILE__) . "/"; 16 | echo __FILE__, "\r\n"; 17 | if (extension_loaded($module)) { 18 | $rs = dasm_file($path . "demo.php"); 19 | } else { 20 | $rs = "Module $module is not compiled into PHP"; 21 | } 22 | echo 1; 23 | print_r($rs); 24 | echo 2; 25 | -------------------------------------------------------------------------------- /php_opcodedump.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2017 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id$ */ 20 | 21 | #ifndef PHP_OPCODEDUMP_H 22 | #define PHP_OPCODEDUMP_H 23 | 24 | extern zend_module_entry opcodedump_module_entry; 25 | #define phpext_opcodedump_ptr &opcodedump_module_entry 26 | 27 | #define PHP_OPCODEDUMP_VERSION "0.1.0" /* Replace with version number for your extension */ 28 | 29 | #ifdef PHP_WIN32 30 | # define PHP_OPCODEDUMP_API __declspec(dllexport) 31 | #elif defined(__GNUC__) && __GNUC__ >= 4 32 | # define PHP_OPCODEDUMP_API __attribute__ ((visibility("default"))) 33 | #else 34 | # define PHP_OPCODEDUMP_API 35 | #endif 36 | 37 | #ifdef ZTS 38 | #include "TSRM.h" 39 | #endif 40 | 41 | /* 42 | Declare any global variables you may need between the BEGIN 43 | and END macros here: 44 | 45 | ZEND_BEGIN_MODULE_GLOBALS(opcodedump) 46 | zend_long global_value; 47 | char *global_string; 48 | ZEND_END_MODULE_GLOBALS(opcodedump) 49 | */ 50 | 51 | /* Always refer to the globals in your function as OPCODEDUMP_G(variable). 52 | You are encouraged to rename these macros something shorter, see 53 | examples in any other php module directory. 54 | */ 55 | #define OPCODEDUMP_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(opcodedump, v) 56 | 57 | #if defined(ZTS) && defined(COMPILE_DL_OPCODEDUMP) 58 | ZEND_TSRMLS_CACHE_EXTERN() 59 | #endif 60 | 61 | #if (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) 62 | # define ZEND_ENGINE_7_0 63 | #endif 64 | 65 | #if (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION >= 1) 66 | # define ZEND_ENGINE_7_1 67 | #endif 68 | #endif /* PHP_OPCODEDUMP_H */ 69 | 70 | 71 | /* 72 | * Local variables: 73 | * tab-width: 4 74 | * c-basic-offset: 4 75 | * End: 76 | * vim600: noet sw=4 ts=4 fdm=marker 77 | * vim<600: noet sw=4 ts=4 78 | */ 79 | -------------------------------------------------------------------------------- /tests/001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for opcodedump presence 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 20 | --EXPECT-- 21 | opcodedump extension is available 22 | --------------------------------------------------------------------------------