From 46b6ad6daeb84ef47d17ca190dc960f604a493ca Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 16 Apr 2024 15:10:01 +0200 Subject: [PATCH] Inline GDB scripts in the PHP binary (#13600) This inlines .gdbinit and php_gdb.py in the .debug_gdb_scripts section of the PHP binary so that GDB can auto-load them regardless of the current directory or the availability of the PHP source code (albeit some functionalities of php_gdb.py currently rely on the source being available). --- .gitattributes | 1 + .../actions/verify-generated-files/action.yml | 1 + configure.ac | 11 + main/debug_gdb_scripts.c | 1018 +++++++++++++++++ scripts/gdb/debug_gdb_scripts_gen.php | 53 + .gdb.py => scripts/gdb/php_gdb.py | 9 +- 6 files changed, 1091 insertions(+), 2 deletions(-) create mode 100644 main/debug_gdb_scripts.c create mode 100755 scripts/gdb/debug_gdb_scripts_gen.php rename .gdb.py => scripts/gdb/php_gdb.py (96%) diff --git a/.gitattributes b/.gitattributes index 0682b67ecb6..86797917210 100644 --- a/.gitattributes +++ b/.gitattributes @@ -21,6 +21,7 @@ # Collapse generated files within git and pull request diff. **/*_arginfo.h linguist-generated -diff +/main/gdb_inlined_script.c linguist-generated -diff /Zend/zend_vm_execute.h linguist-generated -diff /Zend/zend_vm_handlers.h linguist-generated -diff /Zend/zend_vm_opcodes.[ch] linguist-generated -diff diff --git a/.github/actions/verify-generated-files/action.yml b/.github/actions/verify-generated-files/action.yml index f9264686375..1f5a7f3535f 100644 --- a/.github/actions/verify-generated-files/action.yml +++ b/.github/actions/verify-generated-files/action.yml @@ -8,6 +8,7 @@ runs: [[ "$OSTYPE" == "darwin"* ]] && export PATH="$(brew --prefix)/opt/bison/bin:$PATH" scripts/dev/credits scripts/dev/genfiles + scripts/gdb/debug_gdb_scripts_gen.php Zend/zend_vm_gen.php ext/tokenizer/tokenizer_data_gen.php build/gen_stub.php -f --generate-optimizer-info --verify diff --git a/configure.ac b/configure.ac index a7a455bddf7..db5fd69f6c1 100644 --- a/configure.ac +++ b/configure.ac @@ -1700,6 +1700,17 @@ PHP_ADD_SOURCES(main, main.c snprintf.c spprintf.c \ network.c php_open_temporary_file.c php_odbc_utils.c safe_bcmp.c \ output.c getopt.c php_syslog.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) +if printf "#if __ELF__\nelf\n#endif\n" | $CC -E - | grep elf > /dev/null; then + PHP_ADD_SOURCES(main, debug_gdb_scripts.c) + + cat >> Makefile.objects <func\\n\"\n" + ".ascii \" if $func\\n\"\n" + ".ascii \" if $ex->This->value.obj\\n\"\n" + ".ascii \" if $func->common.scope\\n\"\n" + ".ascii \" printf \\\"%s->\\\", (char*)$func->common.scope->name->val\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"%s->\\\", (char*)$ex->This->value.obj->ce.name->val\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" if $func->common.scope\\n\"\n" + ".ascii \" printf \\\"%s::\\\", (char*)$func->common.scope->name->val\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" if $func->common.function_name\\n\"\n" + ".ascii \" printf \\\"%s(\\\", (char*)$func->common.function_name->val\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"(main\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" set $callFrameSize = (sizeof(zend_execute_data) + sizeof(zval) - 1) / sizeof(zval)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" set $count = $ex->This.u2.num_args\\n\"\n" + ".ascii \" set $arg = 0\\n\"\n" + ".ascii \" while $arg < $count\\n\"\n" + ".ascii \" if $arg > 0\\n\"\n" + ".ascii \" printf \\\", \\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" set $zvalue = (zval *) $ex + $callFrameSize + $arg\\n\"\n" + ".ascii \" set $type = $zvalue->u1.v.type\\n\"\n" + ".ascii \" if $type == 1\\n\"\n" + ".ascii \" printf \\\"NULL\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 2\\n\"\n" + ".ascii \" printf \\\"false\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 3\\n\"\n" + ".ascii \" printf \\\"true\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 4\\n\"\n" + ".ascii \" printf \\\"%ld\\\", $zvalue->value.lval\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 5\\n\"\n" + ".ascii \" printf \\\"%f\\\", $zvalue->value.dval\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 6\\n\"\n" + ".ascii \" ____print_str (char*)$zvalue->value.str->val $zvalue->value.str->len\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 7\\n\"\n" + ".ascii \" printf \\\"array(%d)[%p]\\\", $zvalue->value.arr->nNumOfElements, $zvalue\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 8\\n\"\n" + ".ascii \" printf \\\"object[%p]\\\", $zvalue\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 9\\n\"\n" + ".ascii \" printf \\\"resource(#%d)\\\", $zvalue->value.lval\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 10\\n\"\n" + ".ascii \" printf \\\"reference\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type > 10\\n\"\n" + ".ascii \" printf \\\"unknown type %d\\\", $type\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $arg = $arg + 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" printf \\\") \\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"??? \\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $func != 0\\n\"\n" + ".ascii \" if $func->type == 2\\n\"\n" + ".ascii \" printf \\\"%s:%d \\\", (char*)$func->op_array.filename->val, $ex->opline->lineno\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"[internal function]\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $ex = $ex->prev_execute_data\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\n\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document dump_bt\\n\"\n" + ".ascii \" dumps the current execution stack. usage: dump_bt executor_globals.current_execute_data\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define printzv\\n\"\n" + ".ascii \" set $ind = 1\\n\"\n" + ".ascii \" ____printzv $arg0 0\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document printzv\\n\"\n" + ".ascii \" prints zval contents\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define ____printzv_contents\\n\"\n" + ".ascii \" set $zvalue = $arg0\\n\"\n" + ".ascii \" set $type = $zvalue->u1.v.type\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" # 15 == IS_INDIRECT\\n\"\n" + ".ascii \" if $type > 5 && $type < 12\\n\"\n" + ".ascii \" printf \\\"(refcount=%d) \\\", $zvalue->value.counted->gc.refcount\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" if $type == 0\\n\"\n" + ".ascii \" printf \\\"UNDEF\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 1\\n\"\n" + ".ascii \" printf \\\"NULL\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 2\\n\"\n" + ".ascii \" printf \\\"bool: false\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 3\\n\"\n" + ".ascii \" printf \\\"bool: true\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 4\\n\"\n" + ".ascii \" printf \\\"long: %ld\\\", $zvalue->value.lval\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 5\\n\"\n" + ".ascii \" printf \\\"double: %f\\\", $zvalue->value.dval\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 6\\n\"\n" + ".ascii \" printf \\\"string: %s\\\", (char*)$zvalue->value.str->val\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 7\\n\"\n" + ".ascii \" printf \\\"array: \\\"\\n\"\n" + ".ascii \" if ! $arg1\\n\"\n" + ".ascii \" set $ind = $ind + 1\\n\"\n" + ".ascii \" ____print_ht $zvalue->value.arr 1\\n\"\n" + ".ascii \" set $ind = $ind - 1\\n\"\n" + ".ascii \" set $i = $ind\\n\"\n" + ".ascii \" while $i > 0\\n\"\n" + ".ascii \" printf \\\" \\\"\\n\"\n" + ".ascii \" set $i = $i - 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $type = 0\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 8\\n\"\n" + ".ascii \" printf \\\"object\\\"\\n\"\n" + ".ascii \" ____executor_globals\\n\"\n" + ".ascii \" set $handle = $zvalue->value.obj.handle\\n\"\n" + ".ascii \" set $handlers = $zvalue->value.obj.handlers\\n\"\n" + ".ascii \" set $zobj = $zvalue->value.obj\\n\"\n" + ".ascii \" set $cname = (char*)$zobj->ce->name->val\\n\"\n" + ".ascii \" printf \\\"(%s) #%d\\\", $cname, $handle\\n\"\n" + ".ascii \" if ! $arg1\\n\"\n" + ".ascii \" if $handlers->get_properties == &zend_std_get_properties\\n\"\n" + ".ascii \" if $zobj->properties\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\nProperties \\\"\\n\"\n" + ".ascii \" set $ht = $zobj->properties\\n\"\n" + ".ascii \" set $ind = $ind + 1\\n\"\n" + ".ascii \" ____print_ht $ht 1\\n\"\n" + ".ascii \" set $ind = $ind - 1\\n\"\n" + ".ascii \" set $i = $ind\\n\"\n" + ".ascii \" while $i > 0\\n\"\n" + ".ascii \" printf \\\" \\\"\\n\"\n" + ".ascii \" set $i = $i - 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\" {\\\\\\\\n\\\"\\n\"\n" + ".ascii \" set $ht = &$zobj->ce->properties_info\\n\"\n" + ".ascii \" set $k = 0\\n\"\n" + ".ascii \" set $num = $ht->nNumUsed\\n\"\n" + ".ascii \" while $k < $num\\n\"\n" + ".ascii \" set $p = (Bucket*)($ht->arData + $k)\\n\"\n" + ".ascii \" set $name = $p->key\\n\"\n" + ".ascii \" set $prop = (zend_property_info*)$p->val.value.ptr\\n\"\n" + ".ascii \" set $val = (zval*)((char*)$zobj + $prop->offset)\\n\"\n" + ".ascii \" printf \\\"%s => \\\", (char*)$name->val\\n\"\n" + ".ascii \" printzv $val\\n\"\n" + ".ascii \" set $k = $k + 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $type = 0\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 9\\n\"\n" + ".ascii \" printf \\\"resource: #%d\\\", $zvalue->value.res->handle\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 10\\n\"\n" + ".ascii \" printf \\\"reference: \\\"\\n\"\n" + ".ascii \" ____printzv &$zvalue->value.ref->val $arg1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 11\\n\"\n" + ".ascii \" printf \\\"CONSTANT_AST\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 12\\n\"\n" + ".ascii \" printf \\\"indirect: \\\"\\n\"\n" + ".ascii \" ____printzv $zvalue->value.zv $arg1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 13\\n\"\n" + ".ascii \" printf \\\"pointer: %p\\\", $zvalue->value.ptr\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 15\\n\"\n" + ".ascii \" printf \\\"_ERROR\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 16\\n\"\n" + ".ascii \" printf \\\"_BOOL\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type == 17\\n\"\n" + ".ascii \" printf \\\"_NUMBER\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $type > 17\\n\"\n" + ".ascii \" printf \\\"unknown type %d\\\", $type\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\n\\\"\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define ____printzv\\n\"\n" + ".ascii \" ____executor_globals\\n\"\n" + ".ascii \" set $zvalue = $arg0\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" printf \\\"[%p] \\\", $zvalue\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" set $zcontents = (zval*) $zvalue\\n\"\n" + ".ascii \" if $arg1\\n\"\n" + ".ascii \" ____printzv_contents $zcontents $arg1\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" ____printzv_contents $zcontents 0\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_global_vars\\n\"\n" + ".ascii \" ____executor_globals\\n\"\n" + ".ascii \" set $symtable = ((HashTable *)&($eg_ptr->symbol_table))\\n\"\n" + ".ascii \" print_ht $symtable\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_global_vars\\n\"\n" + ".ascii \" Prints the global variables\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_const_table\\n\"\n" + ".ascii \" set $ind = 1\\n\"\n" + ".ascii \" printf \\\"[%p] {\\\\\\\\n\\\", $arg0\\n\"\n" + ".ascii \" ____print_ht $arg0 4\\n\"\n" + ".ascii \" printf \\\"}\\\\\\\\n\\\"\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_const_table\\n\"\n" + ".ascii \" Dumps elements of Constants HashTable\\n\"\n" + ".ascii \" Example: print_const_table executor_globals.zend_constants\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define ____print_ht\\n\"\n" + ".ascii \" set $ht = (HashTable*)$arg0\\n\"\n" + ".ascii \" set $n = $ind\\n\"\n" + ".ascii \" while $n > 0\\n\"\n" + ".ascii \" printf \\\" \\\"\\n\"\n" + ".ascii \" set $n = $n - 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" set $packed = $ht->u.v.flags & 4\\n\"\n" + ".ascii \" if $packed\\n\"\n" + ".ascii \" printf \\\"Packed\\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"Hash\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\"(%d)[%p]: {\\\\\\\\n\\\", $ht->nNumOfElements, $ht\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" set $num = $ht->nNumUsed\\n\"\n" + ".ascii \" set $i = 0\\n\"\n" + ".ascii \" set $ind = $ind + 1\\n\"\n" + ".ascii \" while $i < $num\\n\"\n" + ".ascii \" if $packed\\n\"\n" + ".ascii \" set $val = (zval*)($ht->arPacked + $i)\\n\"\n" + ".ascii \" set $key = (zend_string*)0\\n\"\n" + ".ascii \" set $h = $i\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" set $bucket = (Bucket*)($ht->arData + $i)\\n\"\n" + ".ascii \" set $val = &$bucket->val\\n\"\n" + ".ascii \" set $key = $bucket->key\\n\"\n" + ".ascii \" set $h = $bucket->h\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $n = $ind\\n\"\n" + ".ascii \" if $val->u1.v.type > 0\\n\"\n" + ".ascii \" while $n > 0\\n\"\n" + ".ascii \" printf \\\" \\\"\\n\"\n" + ".ascii \" set $n = $n - 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\"[%d] \\\", $i\\n\"\n" + ".ascii \" if $key\\n\"\n" + ".ascii \" ____print_str (char*)$key->val $key->len\\n\"\n" + ".ascii \" printf \\\" => \\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"%d => \\\", $h\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $arg1 == 0\\n\"\n" + ".ascii \" printf \\\"%p\\\\\\\\n\\\", $val\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $arg1 == 1\\n\"\n" + ".ascii \" set $zval = $val\\n\"\n" + ".ascii \" ____printzv $zval 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $arg1 == 2\\n\"\n" + ".ascii \" printf \\\"%s\\\\\\\\n\\\", (char*)$val->value.ptr\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $arg1 == 3\\n\"\n" + ".ascii \" set $func = (zend_function*)$val->value.ptr\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\\\\"%s\\\\\\\\\\\"\\\\\\\\n\\\", (char*)$func->common.function_name->val\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $arg1 == 4\\n\"\n" + ".ascii \" set $const = (zend_constant *)$val->value.ptr\\n\"\n" + ".ascii \" ____printzv $const 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $i = $i + 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $ind = $ind - 1\\n\"\n" + ".ascii \" printf \\\"}\\\\\\\\n\\\"\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_ht\\n\"\n" + ".ascii \" set $ind = 0\\n\"\n" + ".ascii \" ____print_ht $arg0 1\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_ht\\n\"\n" + ".ascii \" dumps elements of HashTable made of zval\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_htptr\\n\"\n" + ".ascii \" set $ind = 0\\n\"\n" + ".ascii \" ____print_ht $arg0 0\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_htptr\\n\"\n" + ".ascii \" dumps elements of HashTable made of pointers\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_htstr\\n\"\n" + ".ascii \" set $ind = 0\\n\"\n" + ".ascii \" ____print_ht $arg0 2\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_htstr\\n\"\n" + ".ascii \" dumps elements of HashTable made of strings\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_ft\\n\"\n" + ".ascii \" set $ind = 0\\n\"\n" + ".ascii \" ____print_ht $arg0 3\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_ft\\n\"\n" + ".ascii \" dumps a function table (HashTable)\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define ____print_inh_class\\n\"\n" + ".ascii \" set $ce = $arg0\\n\"\n" + ".ascii \" if $ce->ce_flags & 0x10 || $ce->ce_flags & 0x20\\n\"\n" + ".ascii \" printf \\\"abstract \\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" if $ce->ce_flags & 0x40\\n\"\n" + ".ascii \" printf \\\"final \\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\"class %s\\\", (char*)$ce->name->val\\n\"\n" + ".ascii \" if $ce->parent != 0\\n\"\n" + ".ascii \" printf \\\" extends %s\\\", (char*)$ce->parent->name->val\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $ce->num_interfaces != 0\\n\"\n" + ".ascii \" printf \\\" implements\\\"\\n\"\n" + ".ascii \" set $tmp = 0\\n\"\n" + ".ascii \" while $tmp < $ce->num_interfaces\\n\"\n" + ".ascii \" printf \\\" %s\\\", (char*)$ce->interfaces[$tmp]->name->val\\n\"\n" + ".ascii \" set $tmp = $tmp + 1\\n\"\n" + ".ascii \" if $tmp < $ce->num_interfaces\\n\"\n" + ".ascii \" printf \\\",\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $ce = $ce->parent\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define ____print_inh_iface\\n\"\n" + ".ascii \" set $ce = $arg0\\n\"\n" + ".ascii \" printf \\\"interface %s\\\", (char*)$ce->name->val\\n\"\n" + ".ascii \" if $ce->num_interfaces != 0\\n\"\n" + ".ascii \" set $ce = $ce->interfaces[0]\\n\"\n" + ".ascii \" printf \\\" extends %s\\\", (char*)$ce->name->val\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" set $ce = 0\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_inh\\n\"\n" + ".ascii \" set $ce = $arg0\\n\"\n" + ".ascii \" set $depth = 0\\n\"\n" + ".ascii \" while $ce != 0\\n\"\n" + ".ascii \" set $tmp = $depth\\n\"\n" + ".ascii \" while $tmp != 0\\n\"\n" + ".ascii \" printf \\\" \\\"\\n\"\n" + ".ascii \" set $tmp = $tmp - 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $depth = $depth + 1\\n\"\n" + ".ascii \" if $ce->ce_flags & 0x80\\n\"\n" + ".ascii \" ____print_inh_iface $ce\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" ____print_inh_class $ce\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\" {\\\\\\\\n\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" while $depth != 0\\n\"\n" + ".ascii \" set $tmp = $depth\\n\"\n" + ".ascii \" while $tmp != 1\\n\"\n" + ".ascii \" printf \\\" \\\"\\n\"\n" + ".ascii \" set $tmp = $tmp - 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\"}\\\\\\\\n\\\"\\n\"\n" + ".ascii \" set $depth = $depth - 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_pi\\n\"\n" + ".ascii \" set $pi = (zend_property_info *)$arg0\\n\"\n" + ".ascii \" set $initial_offset = ((uint32_t)(uintptr_t)(&((zend_object*)0)->properties_table[(0)]))\\n\"\n" + ".ascii \" set $ptr_to_val = (zval*)((char*)$pi->ce->default_properties_table + $pi->offset - $initial_offset)\\n\"\n" + ".ascii \" printf \\\"[%p] {\\\\\\\\n\\\", $pi\\n\"\n" + ".ascii \" printf \\\" offset = %p\\\\\\\\n\\\", $pi->offset\\n\"\n" + ".ascii \" printf \\\" ce = [%p] %s\\\\\\\\n\\\", $pi->ce, (char*)$pi->ce->name->val\\n\"\n" + ".ascii \" printf \\\" flags = 0x%x (\\\", $pi->flags\\n\"\n" + ".ascii \" if $pi->flags & 0x100\\n\"\n" + ".ascii \" printf \\\"ZEND_ACC_PUBLIC\\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" if $pi->flags & 0x200\\n\"\n" + ".ascii \" printf \\\"ZEND_ACC_PROTECTED\\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" if $pi->flags & 0x400\\n\"\n" + ".ascii \" printf \\\"ZEND_ACC_PRIVATE\\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" if $pi->flags & 0x800\\n\"\n" + ".ascii \" printf \\\"ZEND_ACC_EARLY_BINDING\\\"\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" if $pi->flags & 0x20000\\n\"\n" + ".ascii \" printf \\\"ZEND_ACC_SHADOW\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\")\\\\\\\\n\\\"\\n\"\n" + ".ascii \" printf \\\" name = \\\"\\n\"\n" + ".ascii \" print_zstr $pi->name\\n\"\n" + ".ascii \" printf \\\" default value: \\\"\\n\"\n" + ".ascii \" printzv $ptr_to_val\\n\"\n" + ".ascii \" printf \\\"}\\\\\\\\n\\\"\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_pi\\n\"\n" + ".ascii \" Takes a pointer to an object\\\\'s property and prints the property information\\n\"\n" + ".ascii \" usage: print_pi \\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define ____print_str\\n\"\n" + ".ascii \" set $tmp = 0\\n\"\n" + ".ascii \" set $str = $arg0\\n\"\n" + ".ascii \" if $argc > 2\\n\"\n" + ".ascii \" set $maxlen = $arg2\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" set $maxlen = 256\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\\\\"\\\"\\n\"\n" + ".ascii \" while $tmp < $arg1 && $tmp < $maxlen\\n\"\n" + ".ascii \" if $str[$tmp] > 31 && $str[$tmp] < 127\\n\"\n" + ".ascii \" printf \\\"%c\\\", $str[$tmp]\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\\\\\\\\\%o\\\", $str[$tmp]\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $tmp = $tmp + 1\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $tmp != $arg1\\n\"\n" + ".ascii \" printf \\\"...\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\\\\"\\\"\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define printzn\\n\"\n" + ".ascii \" ____executor_globals\\n\"\n" + ".ascii \" set $ind = 0\\n\"\n" + ".ascii \" set $znode = $arg0\\n\"\n" + ".ascii \" if $znode->op_type == 1\\n\"\n" + ".ascii \" set $optype = \\\"IS_CONST\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $znode->op_type == 2\\n\"\n" + ".ascii \" set $optype = \\\"IS_TMP_VAR\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $znode->op_type == 4\\n\"\n" + ".ascii \" set $optype = \\\"IS_VAR\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $znode->op_type == 8\\n\"\n" + ".ascii \" set $optype = \\\"IS_UNUSED\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" printf \\\"[%p] %s\\\", $znode, $optype\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" if $znode->op_type == 1\\n\"\n" + ".ascii \" printf \\\": \\\"\\n\"\n" + ".ascii \" ____printzv &$znode->u.constant 0\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $znode->op_type == 2\\n\"\n" + ".ascii \" printf \\\": \\\"\\n\"\n" + ".ascii \" set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var)\\n\"\n" + ".ascii \" ____printzv ((union _temp_variable *)$tvar)->tmp_var 0\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $znode->op_type == 4\\n\"\n" + ".ascii \" printf \\\": \\\"\\n\"\n" + ".ascii \" set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var)\\n\"\n" + ".ascii \" ____printzv *$tvar->var.ptr_ptr 0\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $znode->op_type == 8\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\n\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document printzn\\n\"\n" + ".ascii \" print type and content of znode.\\n\"\n" + ".ascii \" usage: printzn &opline->op1\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define printzops\\n\"\n" + ".ascii \" printf \\\"op1 => \\\"\\n\"\n" + ".ascii \" printzn &execute_data->opline.op1\\n\"\n" + ".ascii \" printf \\\"op2 => \\\"\\n\"\n" + ".ascii \" printzn &execute_data->opline.op2\\n\"\n" + ".ascii \" printf \\\"result => \\\"\\n\"\n" + ".ascii \" printzn &execute_data->opline.result\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document printzops\\n\"\n" + ".ascii \" dump operands of the current opline\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define print_zstr\\n\"\n" + ".ascii \" set $zstr = (zend_string *)$arg0\\n\"\n" + ".ascii \" if $argc == 2\\n\"\n" + ".ascii \" set $maxlen = $arg1\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" set $maxlen = $zstr->len\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" printf \\\"string(%d) \\\", $zstr->len\\n\"\n" + ".ascii \" ____print_str (char*)$zstr->val $zstr->len $maxlen\\n\"\n" + ".ascii \" printf \\\"\\\\\\\\n\\\"\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document print_zstr\\n\"\n" + ".ascii \" print the length and contents of a zend string\\n\"\n" + ".ascii \" usage: print_zstr [max length]\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define zbacktrace\\n\"\n" + ".ascii \" ____executor_globals\\n\"\n" + ".ascii \" dump_bt $eg.current_execute_data\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document zbacktrace\\n\"\n" + ".ascii \" prints backtrace.\\n\"\n" + ".ascii \" This command is almost a short cut for\\n\"\n" + ".ascii \" > (gdb) ____executor_globals\\n\"\n" + ".ascii \" > (gdb) dump_bt $eg.current_execute_data\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"define lookup_root\\n\"\n" + ".ascii \" set $found = 0\\n\"\n" + ".ascii \" if gc_globals->roots\\n\"\n" + ".ascii \" set $current = gc_globals->roots->next\\n\"\n" + ".ascii \" printf \\\"looking ref %p in roots\\\\\\\\n\\\", $arg0\\n\"\n" + ".ascii \" while $current != &gc_globals->roots\\n\"\n" + ".ascii \" if $current->ref == $arg0\\n\"\n" + ".ascii \" set $found = $current\\n\"\n" + ".ascii \" break\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" set $current = $current->next\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" if $found != 0\\n\"\n" + ".ascii \" printf \\\"found root %p\\\\\\\\n\\\", $found\\n\"\n" + ".ascii \" else\\n\"\n" + ".ascii \" printf \\\"not found\\\\\\\\n\\\"\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \" end\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"document lookup_root\\n\"\n" + ".ascii \" lookup a refcounted in root\\n\"\n" + ".ascii \" usage: lookup_root [ptr].\\n\"\n" + ".ascii \"end\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"''')\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"\\\"\\\"\\\"GDB support for PHP types\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"This is auto-loaded by GDB if Python Auto-loading is enabled (the default), and\\n\"\n" + ".ascii \"the PHP binary is in the auto load safe path:\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" # ~/.config/gdb/gdbinit (not ~/.gdbinit)\\n\"\n" + ".ascii \" add-auto-load-safe-path /path/to/php-src\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"See https://sourceware.org/gdb/current/onlinedocs/gdb.html/Python-Auto_002dloading.html\\n\"\n" + ".ascii \"See https://sourceware.org/gdb/current/onlinedocs/gdb.html/Auto_002dloading-safe-path.html#Auto_002dloading-safe-path\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"If needed, pretty printers can be by-passed by using the /r flag:\\n\"\n" + ".ascii \" (gdb) p /r any_variable\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"Use |set print pretty| to enable multi-line printing and indentation:\\n\"\n" + ".ascii \" (gdb) set print pretty on\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"Use |set print max-depth| to control the maximum print depth for nested\\n\"\n" + ".ascii \"structures:\\n\"\n" + ".ascii \" (gdb) set print pretty on\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"To interactively type Python for development of the printers, use\\n\"\n" + ".ascii \" (gdb) python foo = gdb.parse_and_eval('bar')\\n\"\n" + ".ascii \"to put the C value 'bar' in the current scope into a Python variable 'foo'.\\n\"\n" + ".ascii \"Then you can interact with that variable:\\n\"\n" + ".ascii \" (gdb) python print foo['impl_']\\n\"\n" + ".ascii \"\\\"\\\"\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"import gdb\\n\"\n" + ".ascii \"import re\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set = gdb.printing.RegexpCollectionPrettyPrinter(\\\"php\\\")\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"class ZendStringPrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" + ".ascii \" \\\"Print a zend_string\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def __init__(self, val):\\n\"\n" + ".ascii \" self.val = val\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def to_string(self):\\n\"\n" + ".ascii \" return self.format_string()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def children(self):\\n\"\n" + ".ascii \" for field in self.val.type.fields():\\n\"\n" + ".ascii \" if field.name == 'val':\\n\"\n" + ".ascii \" yield ('val', self.format_string())\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" yield (field.name, self.val[field.name])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def format_string(self):\\n\"\n" + ".ascii \" len = int(self.val['len'])\\n\"\n" + ".ascii \" truncated = False\\n\"\n" + ".ascii \" if len > 50:\\n\"\n" + ".ascii \" len = 50\\n\"\n" + ".ascii \" truncated = True\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" ptr_type = gdb.lookup_type('char').pointer()\\n\"\n" + ".ascii \" ary_type = gdb.lookup_type('char').array(len)\\n\"\n" + ".ascii \" str = self.val['val'].cast(ptr_type).dereference().cast(ary_type)\\n\"\n" + ".ascii \" str = str.format_string()\\n\"\n" + ".ascii \" if truncated:\\n\"\n" + ".ascii \" str += ' (%d bytes total)' % int(self.val['len'])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" return str\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set.add_printer('zend_string', '^_zend_string$', ZendStringPrettyPrinter)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"class ZendTypePrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" + ".ascii \" \\\"Print a zend_type\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def __init__(self, val):\\n\"\n" + ".ascii \" self.val = val\\n\"\n" + ".ascii \" load_type_bits()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def to_string(self):\\n\"\n" + ".ascii \" return self.format_type(self.val)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def children(self):\\n\"\n" + ".ascii \" for field in self.val.type.fields():\\n\"\n" + ".ascii \" yield (field.name, self.val[field.name])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def format_type(self, t):\\n\"\n" + ".ascii \" type_mask = int(t['type_mask'])\\n\"\n" + ".ascii \" type_mask_size = t['type_mask'].type.sizeof * 8\\n\"\n" + ".ascii \" separator = '|'\\n\"\n" + ".ascii \" parts = []\\n\"\n" + ".ascii \" meta = []\\n\"\n" + ".ascii \" for bit in range(0, type_mask_size):\\n\"\n" + ".ascii \" if type_mask & (1 << bit):\\n\"\n" + ".ascii \" type_name = type_bit_to_name.get(bit)\\n\"\n" + ".ascii \" match type_name:\\n\"\n" + ".ascii \" case None:\\n\"\n" + ".ascii \" parts.append('(1<<%d)' % bit)\\n\"\n" + ".ascii \" case 'list':\\n\"\n" + ".ascii \" list = t['ptr'].cast(gdb.lookup_type('zend_type_list').pointer())\\n\"\n" + ".ascii \" num_types = int(list['num_types'])\\n\"\n" + ".ascii \" types = list['types'].dereference().cast(gdb.lookup_type('zend_type').array(num_types))\\n\"\n" + ".ascii \" for i in range(0, num_types):\\n\"\n" + ".ascii \" str = self.format_type(types[i])\\n\"\n" + ".ascii \" if any((c in set('|&()')) for c in str):\\n\"\n" + ".ascii \" str = '(%s)' % str\\n\"\n" + ".ascii \" parts.append(str)\\n\"\n" + ".ascii \" case 'union' | 'arena':\\n\"\n" + ".ascii \" meta.append(type_name)\\n\"\n" + ".ascii \" case 'intersection':\\n\"\n" + ".ascii \" meta.append(type_name)\\n\"\n" + ".ascii \" separator = '&'\\n\"\n" + ".ascii \" case 'name':\\n\"\n" + ".ascii \" str = t['ptr'].cast(gdb.lookup_type('zend_string').pointer())\\n\"\n" + ".ascii \" parts.append(ZendStringPrettyPrinter(str).to_string())\\n\"\n" + ".ascii \" case _:\\n\"\n" + ".ascii \" parts.append(type_name)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" str = separator.join(parts)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" if len(meta) > 0:\\n\"\n" + ".ascii \" str = '[%s] %s' % (','.join(meta), str)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" return str\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set.add_printer('zend_type', '^zend_type$', ZendTypePrettyPrinter)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"class ZendAstKindPrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" + ".ascii \" \\\"Print a zend_ast_kind\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def __init__(self, val):\\n\"\n" + ".ascii \" self.val = val\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def to_string(self):\\n\"\n" + ".ascii \" return self.val.cast(gdb.lookup_type('enum _zend_ast_kind'))\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set.add_printer('zend_ast_kind', '^zend_ast_kind$', ZendAstKindPrettyPrinter)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"class ZendAstPrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" + ".ascii \" \\\"Print a zend_ast\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def __init__(self, val):\\n\"\n" + ".ascii \" self.val = val\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def to_string(self):\\n\"\n" + ".ascii \" return '((%s*)0x%x)' % (str(self.cast().type), self.val.address)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def children(self):\\n\"\n" + ".ascii \" val = self.cast()\\n\"\n" + ".ascii \" for field in val.type.fields():\\n\"\n" + ".ascii \" if field.name == 'child':\\n\"\n" + ".ascii \" children = val[field.name]\\n\"\n" + ".ascii \" num_children = self.num_children()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" ptr_type = gdb.lookup_type('zend_ast').pointer().pointer()\\n\"\n" + ".ascii \" children = children.cast(ptr_type)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" for i in range(0, num_children):\\n\"\n" + ".ascii \" c = children[i]\\n\"\n" + ".ascii \" if int(c) != 0:\\n\"\n" + ".ascii \" c = c.dereference()\\n\"\n" + ".ascii \" yield ('child[%d]' % i, c)\\n\"\n" + ".ascii \" elif field.name == 'name':\\n\"\n" + ".ascii \" yield (field.name, ZendStringPrettyPrinter(val[field.name].dereference()).to_string())\\n\"\n" + ".ascii \" elif field.name == 'val':\\n\"\n" + ".ascii \" yield (field.name, ZvalPrettyPrinter(val[field.name]).to_string())\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" yield (field.name, val[field.name])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def is_special(self):\\n\"\n" + ".ascii \" special_shift = 6 # ZEND_AST_SPECIAL_SHIFT\\n\"\n" + ".ascii \" kind = self.val['kind']\\n\"\n" + ".ascii \" return (kind >> special_shift) & 1\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def is_decl(self):\\n\"\n" + ".ascii \" return self.is_special() and int(self.val['kind']) >= enum_value('ZEND_AST_FUNC_DECL')\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def is_list(self):\\n\"\n" + ".ascii \" list_shift = 7 # ZEND_AST_IS_LIST_SHIFT\\n\"\n" + ".ascii \" kind = self.val['kind']\\n\"\n" + ".ascii \" return (kind >> list_shift) & 1\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def cast(self):\\n\"\n" + ".ascii \" kind = int(self.val['kind'])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" if kind == enum_value('ZEND_AST_ZVAL') or kind == enum_value('ZEND_AST_CONSTANT'):\\n\"\n" + ".ascii \" return self.val.cast(gdb.lookup_type('zend_ast_zval'))\\n\"\n" + ".ascii \" if kind == enum_value('ZEND_AST_ZNODE'):\\n\"\n" + ".ascii \" return self.val.cast(gdb.lookup_type('zend_ast_znode'))\\n\"\n" + ".ascii \" if self.is_decl():\\n\"\n" + ".ascii \" return self.val.cast(gdb.lookup_type('zend_ast_decl'))\\n\"\n" + ".ascii \" if self.is_list():\\n\"\n" + ".ascii \" return self.val.cast(gdb.lookup_type('zend_ast_list'))\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" return self.val\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def num_children(self):\\n\"\n" + ".ascii \" if self.is_decl():\\n\"\n" + ".ascii \" decl_type = gdb.lookup_type('zend_ast_decl')\\n\"\n" + ".ascii \" child_type = decl_type['child'].type\\n\"\n" + ".ascii \" return array_size(child_type)\\n\"\n" + ".ascii \" if self.is_special():\\n\"\n" + ".ascii \" return 0\\n\"\n" + ".ascii \" elif self.is_list():\\n\"\n" + ".ascii \" return int(self.cast()['children'])\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" num_children_shift = 8 # ZEND_AST_NUM_CHILDREN_SHIFT\\n\"\n" + ".ascii \" kind = self.val['kind']\\n\"\n" + ".ascii \" return kind >> num_children_shift\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set.add_printer('zend_ast', '^_zend_ast$', ZendAstPrettyPrinter)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"class ZvalPrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" + ".ascii \" \\\"Print a zval\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def __init__(self, val):\\n\"\n" + ".ascii \" self.val = val\\n\"\n" + ".ascii \" load_type_bits()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def to_string(self):\\n\"\n" + ".ascii \" return self.value_to_string()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def value_to_string(self):\\n\"\n" + ".ascii \" t = int(self.val['u1']['v']['type'])\\n\"\n" + ".ascii \" if t == type_name_to_bit['undef']:\\n\"\n" + ".ascii \" return 'undef'\\n\"\n" + ".ascii \" elif t == type_name_to_bit['null']:\\n\"\n" + ".ascii \" return 'null'\\n\"\n" + ".ascii \" elif t == type_name_to_bit['false']:\\n\"\n" + ".ascii \" return 'false'\\n\"\n" + ".ascii \" elif t == type_name_to_bit['true']:\\n\"\n" + ".ascii \" return 'true'\\n\"\n" + ".ascii \" elif t == type_name_to_bit['long']:\\n\"\n" + ".ascii \" return str(self.val['value']['lval'])\\n\"\n" + ".ascii \" elif t == type_name_to_bit['double']:\\n\"\n" + ".ascii \" return str(self.val['value']['dval'])\\n\"\n" + ".ascii \" elif t == type_name_to_bit['string']:\\n\"\n" + ".ascii \" return ZendStringPrettyPrinter(self.val['value']['str'].dereference()).to_string()\\n\"\n" + ".ascii \" elif t == type_name_to_bit['array']:\\n\"\n" + ".ascii \" return 'array'\\n\"\n" + ".ascii \" elif t == type_name_to_bit['object']:\\n\"\n" + ".ascii \" return 'object(%s)' % ZendStringPrettyPrinter(self.val['value']['obj']['ce']['name'].dereference()).to_string()\\n\"\n" + ".ascii \" elif t == type_name_to_bit['resource']:\\n\"\n" + ".ascii \" return 'resource'\\n\"\n" + ".ascii \" elif t == type_name_to_bit['reference']:\\n\"\n" + ".ascii \" return 'reference'\\n\"\n" + ".ascii \" elif t == type_name_to_bit['constant_ast']:\\n\"\n" + ".ascii \" return 'constant_ast'\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" return 'zval of type %d' % int(self.val['u1']['v']['type'])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def children(self):\\n\"\n" + ".ascii \" for field in self.val.type.fields():\\n\"\n" + ".ascii \" if field.name == 'value':\\n\"\n" + ".ascii \" value = self.val['value']\\n\"\n" + ".ascii \" t = int(self.val['u1']['v']['type'])\\n\"\n" + ".ascii \" if t == type_name_to_bit['undef']:\\n\"\n" + ".ascii \" value = value['lval']\\n\"\n" + ".ascii \" elif t == type_name_to_bit['null']:\\n\"\n" + ".ascii \" value = value['lval']\\n\"\n" + ".ascii \" elif t == type_name_to_bit['false']:\\n\"\n" + ".ascii \" value = value['lval']\\n\"\n" + ".ascii \" elif t == type_name_to_bit['true']:\\n\"\n" + ".ascii \" value = value['lval']\\n\"\n" + ".ascii \" elif t == type_name_to_bit['long']:\\n\"\n" + ".ascii \" value = value['lval']\\n\"\n" + ".ascii \" elif t == type_name_to_bit['double']:\\n\"\n" + ".ascii \" value = value['dval']\\n\"\n" + ".ascii \" elif t == type_name_to_bit['string']:\\n\"\n" + ".ascii \" value = value['str'].dereference()\\n\"\n" + ".ascii \" elif t == type_name_to_bit['array']:\\n\"\n" + ".ascii \" value = value['ht'].dereference()\\n\"\n" + ".ascii \" elif t == type_name_to_bit['object']:\\n\"\n" + ".ascii \" value = value['obj'].dereference()\\n\"\n" + ".ascii \" elif t == type_name_to_bit['resource']:\\n\"\n" + ".ascii \" value = value['res'].dereference()\\n\"\n" + ".ascii \" elif t == type_name_to_bit['reference']:\\n\"\n" + ".ascii \" value = value['ref'].dereference()\\n\"\n" + ".ascii \" elif t == type_name_to_bit['constant_ast']:\\n\"\n" + ".ascii \" value = value['ast'].dereference()\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" value = value['ptr']\\n\"\n" + ".ascii \" yield (field.name, value)\\n\"\n" + ".ascii \" elif field.name == 'u2':\\n\"\n" + ".ascii \" yield ('u2', self.val[field.name]['extra'])\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" yield (field.name, self.val[field.name])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set.add_printer('zval', '^_zval_struct$', ZvalPrettyPrinter)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"type_bit_to_name = None\\n\"\n" + ".ascii \"type_name_to_bit = None\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"def load_type_bits():\\n\"\n" + ".ascii \" global type_bit_to_name\\n\"\n" + ".ascii \" global type_name_to_bit\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" if type_bit_to_name != None:\\n\"\n" + ".ascii \" return\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" (symbol,_) = gdb.lookup_symbol(\\\"zend_gc_refcount\\\")\\n\"\n" + ".ascii \" if symbol == None:\\n\"\n" + ".ascii \" raise \\\"Could not find zend_types.h: symbol zend_gc_refcount not found\\\"\\n\"\n" + ".ascii \" filename = symbol.symtab.fullname()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" bits = {}\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" with open(filename, 'r') as file:\\n\"\n" + ".ascii \" content = file.read()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" pattern = re.compile(r'#define _ZEND_TYPE_([^\\\\s]+)_BIT\\\\s+\\\\(1u << (\\\\d+)\\\\)')\\n\"\n" + ".ascii \" matches = pattern.findall(content)\\n\"\n" + ".ascii \" for name, bit in matches:\\n\"\n" + ".ascii \" bits[int(bit)] = name.lower()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" pattern = re.compile(r'#define IS_([^\\\\s]+)\\\\s+(\\\\d+)')\\n\"\n" + ".ascii \" matches = pattern.findall(content)\\n\"\n" + ".ascii \" for name, bit in matches:\\n\"\n" + ".ascii \" if not int(bit) in bits:\\n\"\n" + ".ascii \" bits[int(bit)] = name.lower()\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" types = {}\\n\"\n" + ".ascii \" for bit in bits:\\n\"\n" + ".ascii \" types[bits[bit]] = bit\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" type_bit_to_name = bits\\n\"\n" + ".ascii \" type_name_to_bit = types\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"def lookup_symbol(name):\\n\"\n" + ".ascii \" (symbol, _) = gdb.lookup_symbol(name)\\n\"\n" + ".ascii \" if symbol == None:\\n\"\n" + ".ascii \" raise Exception(\\\"Could not lookup symbol %s\\\" % name)\\n\"\n" + ".ascii \" return symbol\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"def enum_value(name):\\n\"\n" + ".ascii \" symbol = lookup_symbol(name)\\n\"\n" + ".ascii \" return int(symbol.value())\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"def array_size(ary_type):\\n\"\n" + ".ascii \" # array types have a single field whose type represents its range\\n\"\n" + ".ascii \" return ary_type.fields()[0].type.range()[1]+1\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"gdb.printing.register_pretty_printer(gdb, pp_set, replace=True)\\n\"\n" + ".ascii \"\\n\"\n" + ".byte 0\n" + ".popsection\n" +); diff --git a/scripts/gdb/debug_gdb_scripts_gen.php b/scripts/gdb/debug_gdb_scripts_gen.php new file mode 100755 index 00000000000..e5f4ff1b434 --- /dev/null +++ b/scripts/gdb/debug_gdb_scripts_gen.php @@ -0,0 +1,53 @@ +#!/usr/bin/env php +