Created
February 23, 2015 07:32
-
-
Save predakanga/8f920817127f2811510c to your computer and use it in GitHub Desktop.
GDB PHP stacktraces
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define set_ts | |
set $tsrm_ls = $arg0 | |
end | |
document set_ts | |
set the ts resource, it is impossible for gdb to | |
call ts_resource_ex while no process is running, | |
but we could get the resource from the argument | |
of frame info. | |
end | |
define ____executor_globals | |
if basic_functions_module.zts | |
if !$tsrm_ls | |
set $tsrm_ls = ts_resource_ex(0, 0) | |
end | |
set $eg = ((zend_executor_globals*) (*((void ***) $tsrm_ls))[executor_globals_id-1]) | |
set $cg = ((zend_compiler_globals*) (*((void ***) $tsrm_ls))[compiler_globals_id-1]) | |
else | |
set $eg = executor_globals | |
set $cg = compiler_globals | |
end | |
end | |
document ____executor_globals | |
portable way of accessing executor_globals, set $eg | |
this also sets compiler_globals to $cg | |
ZTS detection is automatically based on ext/standard module struct | |
end | |
define print_cvs | |
____executor_globals | |
set $p = $eg.current_execute_data.CVs | |
set $c = $eg.current_execute_data.op_array.last_var | |
set $v = $eg.current_execute_data.op_array.vars | |
set $i = 0 | |
printf "Compiled variables count: %d\n", $c | |
while $i < $c | |
printf "%d = %s\n", $i, $v[$i].name | |
if $p[$i] != 0 | |
printzv *$p[$i] | |
else | |
printf "*uninitialized*\n" | |
end | |
set $i = $i + 1 | |
end | |
end | |
define dump_bt | |
set $t = $arg0 | |
while $t | |
printf "[%p] ", $t | |
set $fst = $t->function_state | |
if $fst.function->common.function_name | |
if $fst.arguments | |
set $count = (int)*($fst.arguments) | |
if $t->object | |
if $fst.function.common.scope | |
printf "%s->", $fst.function.common.scope->name | |
else | |
if !$eg | |
____executor_globals | |
end | |
set $known_class = 0 | |
if $eg | |
set $handle = $t->object.value.obj.handle | |
set $handlers = $t->object.value.obj.handlers | |
set $zobj = (zend_object *)$eg.objects_store.object_buckets[$handle].bucket.obj.object | |
if $handlers->get_class_entry == &zend_std_object_get_class | |
set $known_class = 1 | |
if $handlers.get_class_name | |
if $handlers.get_class_name != &zend_std_object_get_class_name | |
set $known_class = 0 | |
end | |
end | |
if $known_class | |
printf "%s->", $zobj->ce.name | |
end | |
end | |
end | |
if !$known_class | |
printf "(Unknown)->" | |
end | |
end | |
else | |
if $fst.function.common.scope | |
printf "%s::", $fst.function.common.scope->name | |
end | |
end | |
printf "%s(", $fst.function->common.function_name | |
while $count > 0 | |
set $zvalue = *(zval **)($fst.arguments - $count) | |
set $type = $zvalue->type | |
if $type == 0 | |
printf "NULL" | |
end | |
if $type == 1 | |
printf "%ld", $zvalue->value.lval | |
end | |
if $type == 2 | |
printf "%f", $zvalue->value.dval | |
end | |
if $type == 3 | |
if $zvalue->value.lval | |
printf "true" | |
else | |
printf "false" | |
end | |
end | |
if $type == 4 | |
printf "array(%d)[%p]", $zvalue->value.ht->nNumOfElements, $zvalue | |
end | |
if $type == 5 | |
printf "object[%p]", $zvalue | |
end | |
if $type == 6 | |
____print_str $zvalue->value.str.val $zvalue->value.str.len | |
end | |
if $type == 7 | |
printf "resource(#%d)", $zvalue->value.lval | |
end | |
if $type == 8 | |
printf "constant" | |
end | |
if $type == 9 | |
printf "const_array" | |
end | |
if $type > 9 | |
printf "unknown type %d", $type | |
end | |
set $count = $count -1 | |
if $count > 0 | |
printf ", " | |
end | |
end | |
printf ") " | |
else | |
printf "%s() ", $fst.function->common.function_name | |
end | |
else | |
printf "??? " | |
end | |
if $t->op_array != 0 | |
printf "%s:%d ", $t->op_array->filename, $t->opline->lineno | |
end | |
set $t = $t->prev_execute_data | |
printf "\n" | |
end | |
end | |
document dump_bt | |
dumps the current execution stack. usage: dump_bt executor_globals.current_execute_data | |
end | |
define printzv | |
set $ind = 1 | |
____printzv $arg0 0 | |
end | |
document printzv | |
prints zval contents | |
end | |
define ____printzv_contents | |
set $zvalue = $arg0 | |
set $type = $zvalue->type | |
printf "(refcount=%d", $zvalue->refcount__gc | |
if $zvalue->is_ref__gc | |
printf ",is_ref" | |
end | |
printf ") " | |
if $type == 0 | |
printf "NULL" | |
end | |
if $type == 1 | |
printf "long: %ld", $zvalue->value.lval | |
end | |
if $type == 2 | |
printf "double: %f", $zvalue->value.dval | |
end | |
if $type == 3 | |
printf "bool: " | |
if $zvalue->value.lval | |
printf "true" | |
else | |
printf "false" | |
end | |
end | |
if $type == 4 | |
printf "array(%d): ", $zvalue->value.ht->nNumOfElements | |
if ! $arg1 | |
printf "{\n" | |
set $ind = $ind + 1 | |
____print_ht $zvalue->value.ht 1 | |
set $ind = $ind - 1 | |
set $i = $ind | |
while $i > 0 | |
printf " " | |
set $i = $i - 1 | |
end | |
printf "}" | |
end | |
set $type = 0 | |
end | |
if $type == 5 | |
printf "object" | |
____executor_globals | |
set $handle = $zvalue->value.obj.handle | |
set $handlers = $zvalue->value.obj.handlers | |
if basic_functions_module.zts | |
set $zobj = zend_objects_get_address($zvalue, $tsrm_ls) | |
else | |
set $zobj = zend_objects_get_address($zvalue) | |
end | |
if $handlers->get_class_entry == &zend_std_object_get_class | |
set $cname = $zobj->ce.name | |
else | |
set $cname = "Unknown" | |
end | |
printf "(%s) #%d", $cname, $handle | |
if ! $arg1 | |
if $handlers->get_properties == &zend_std_get_properties | |
set $ht = $zobj->properties | |
if $ht | |
printf "(%d): ", $ht->nNumOfElements | |
printf "{\n" | |
set $ind = $ind + 1 | |
____print_ht $ht 1 | |
set $ind = $ind - 1 | |
set $i = $ind | |
while $i > 0 | |
printf " " | |
set $i = $i - 1 | |
end | |
printf "}" | |
else | |
echo "no properties found" | |
end | |
end | |
end | |
set $type = 0 | |
end | |
if $type == 6 | |
printf "string(%d): ", $zvalue->value.str.len | |
____print_str $zvalue->value.str.val $zvalue->value.str.len | |
end | |
if $type == 7 | |
printf "resource: #%d", $zvalue->value.lval | |
end | |
if $type == 8 | |
printf "constant" | |
end | |
if $type == 9 | |
printf "const_array" | |
end | |
if $type > 9 | |
printf "unknown type %d", $type | |
end | |
printf "\n" | |
end | |
define ____printzv | |
____executor_globals | |
set $zvalue = $arg0 | |
printf "[%p] ", $zvalue | |
if $zvalue == $eg.uninitialized_zval_ptr | |
printf "*uninitialized* " | |
end | |
set $zcontents = (zval*) $zvalue | |
if $arg1 | |
____printzv_contents $zcontents $arg1 | |
else | |
____printzv_contents $zcontents 0 | |
end | |
end | |
define ____print_const_table | |
set $ht = $arg0 | |
set $p = $ht->pListHead | |
while $p != 0 | |
set $const = (zend_constant *) $p->pData | |
set $i = $ind | |
while $i > 0 | |
printf " " | |
set $i = $i - 1 | |
end | |
if $p->nKeyLength > 0 | |
____print_str $p->arKey $p->nKeyLength | |
printf " => " | |
else | |
printf "%d => ", $p->h | |
end | |
____printzv_contents &$const->value 0 | |
set $p = $p->pListNext | |
end | |
end | |
define print_const_table | |
set $ind = 1 | |
printf "[%p] {\n", $arg0 | |
____print_const_table $arg0 | |
printf "}\n" | |
end | |
define ____print_ht | |
set $ht = (HashTable*)$arg0 | |
set $p = $ht->pListHead | |
while $p != 0 | |
set $i = $ind | |
while $i > 0 | |
printf " " | |
set $i = $i - 1 | |
end | |
if $p->nKeyLength > 0 | |
____print_str $p->arKey $p->nKeyLength | |
printf " => " | |
else | |
printf "%d => ", $p->h | |
end | |
if $arg1 == 0 | |
printf "%p\n", (void*)$p->pData | |
end | |
if $arg1 == 1 | |
set $zval = *(zval **)$p->pData | |
____printzv $zval 1 | |
end | |
if $arg1 == 2 | |
printf "%s\n", (char*)$p->pData | |
end | |
set $p = $p->pListNext | |
end | |
end | |
define print_ht | |
set $ind = 1 | |
printf "[%p] {\n", $arg0 | |
____print_ht $arg0 1 | |
printf "}\n" | |
end | |
document print_ht | |
dumps elements of HashTable made of zval | |
end | |
define print_htptr | |
set $ind = 1 | |
printf "[%p] {\n", $arg0 | |
____print_ht $arg0 0 | |
printf "}\n" | |
end | |
document print_htptr | |
dumps elements of HashTable made of pointers | |
end | |
define print_htstr | |
set $ind = 1 | |
printf "[%p] {\n", $arg0 | |
____print_ht $arg0 2 | |
printf "}\n" | |
end | |
document print_htstr | |
dumps elements of HashTable made of strings | |
end | |
define ____print_ft | |
set $ht = $arg0 | |
set $p = $ht->pListHead | |
while $p != 0 | |
set $func = (zend_function*)$p->pData | |
set $i = $ind | |
while $i > 0 | |
printf " " | |
set $i = $i - 1 | |
end | |
if $p->nKeyLength > 0 | |
____print_str $p->arKey $p->nKeyLength | |
printf " => " | |
else | |
printf "%d => ", $p->h | |
end | |
printf "\"%s\"\n", $func->common.function_name | |
set $p = $p->pListNext | |
end | |
end | |
define print_ft | |
set $ind = 1 | |
printf "[%p] {\n", $arg0 | |
____print_ft $arg0 | |
printf "}\n" | |
end | |
document print_ft | |
dumps a function table (HashTable) | |
end | |
define ____print_inh_class | |
set $ce = $arg0 | |
if $ce->ce_flags & 0x10 || $ce->ce_flags & 0x20 | |
printf "abstract " | |
else | |
if $ce->ce_flags & 0x40 | |
printf "final " | |
end | |
end | |
printf "class %s", $ce->name | |
if $ce->parent != 0 | |
printf " extends %s", $ce->parent->name | |
end | |
if $ce->num_interfaces != 0 | |
printf " implements" | |
set $tmp = 0 | |
while $tmp < $ce->num_interfaces | |
printf " %s", $ce->interfaces[$tmp]->name | |
set $tmp = $tmp + 1 | |
if $tmp < $ce->num_interfaces | |
printf "," | |
end | |
end | |
end | |
set $ce = $ce->parent | |
end | |
define ____print_inh_iface | |
set $ce = $arg0 | |
printf "interface %s", $ce->name | |
if $ce->num_interfaces != 0 | |
set $ce = $ce->interfaces[0] | |
printf " extends %s", $ce->name | |
else | |
set $ce = 0 | |
end | |
end | |
define print_inh | |
set $ce = $arg0 | |
set $depth = 0 | |
while $ce != 0 | |
set $tmp = $depth | |
while $tmp != 0 | |
printf " " | |
set $tmp = $tmp - 1 | |
end | |
set $depth = $depth + 1 | |
if $ce->ce_flags & 0x80 | |
____print_inh_iface $ce | |
else | |
____print_inh_class $ce | |
end | |
printf " {\n" | |
end | |
while $depth != 0 | |
set $tmp = $depth | |
while $tmp != 1 | |
printf " " | |
set $tmp = $tmp - 1 | |
end | |
printf "}\n" | |
set $depth = $depth - 1 | |
end | |
end | |
define print_pi | |
set $pi = $arg0 | |
printf "[%p] {\n", $pi | |
printf " h = %lu\n", $pi->h | |
printf " flags = %d (", $pi->flags | |
if $pi->flags & 0x100 | |
printf "ZEND_ACC_PUBLIC" | |
else | |
if $pi->flags & 0x200 | |
printf "ZEND_ACC_PROTECTED" | |
else | |
if $pi->flags & 0x400 | |
printf "ZEND_ACC_PRIVATE" | |
else | |
if $pi->flags & 0x800 | |
printf "ZEND_ACC_CHANGED" | |
end | |
end | |
end | |
end | |
printf ")\n" | |
printf " name = " | |
____print_str $pi->name $pi->name_length | |
printf "\n}\n" | |
end | |
define ____print_str | |
set $tmp = 0 | |
set $str = $arg0 | |
printf "\"" | |
while $tmp < $arg1 | |
if $str[$tmp] > 32 && $str[$tmp] < 127 | |
printf "%c", $str[$tmp] | |
else | |
printf "\\%o", $str[$tmp] | |
end | |
set $tmp = $tmp + 1 | |
end | |
printf "\"" | |
end | |
define printzn | |
____executor_globals | |
set $ind = 0 | |
set $znode = $arg0 | |
if $znode->op_type == 1 | |
set $optype = "IS_CONST" | |
end | |
if $znode->op_type == 2 | |
set $optype = "IS_TMP_VAR" | |
end | |
if $znode->op_type == 4 | |
set $optype = "IS_VAR" | |
end | |
if $znode->op_type == 8 | |
set $optype = "IS_UNUSED" | |
end | |
printf "[%p] %s", $znode, $optype | |
if $znode->op_type == 1 | |
printf ": " | |
____printzv &$znode->u.constant 0 | |
end | |
if $znode->op_type == 2 | |
printf ": " | |
set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var) | |
____printzv ((union _temp_variable *)$tvar)->tmp_var 0 | |
end | |
if $znode->op_type == 4 | |
printf ": " | |
set $tvar = (union _temp_variable *)((char *)$eg.current_execute_data->Ts + $znode->u.var) | |
____printzv *$tvar->var.ptr_ptr 0 | |
end | |
if $znode->op_type == 8 | |
printf "\n" | |
end | |
end | |
document printzn | |
print type and content of znode. | |
usage: printzn &opline->op1 | |
end | |
define printzops | |
printf "op1 => " | |
printzn &execute_data->opline.op1 | |
printf "op2 => " | |
printzn &execute_data->opline.op2 | |
printf "result => " | |
printzn &execute_data->opline.result | |
end | |
document printzops | |
dump operands of the current opline | |
end | |
define zbacktrace | |
____executor_globals | |
dump_bt $eg.current_execute_data | |
end | |
document zbacktrace | |
prints backtrace. | |
This command is almost a short cut for | |
> (gdb) ____executor_globals | |
> (gdb) dump_bt $eg.current_execute_data | |
end | |
define zmemcheck | |
set $p = alloc_globals.head | |
set $stat = "?" | |
set $total_size = 0 | |
if $arg0 != 0 | |
set $not_found = 1 | |
else | |
set $not_found = 0 | |
end | |
printf " block size status file:line\n" | |
printf "-------------------------------------------------------------------------------\n" | |
while $p | |
set $aptr = $p + sizeof(struct _zend_mem_header) + sizeof(align_test) | |
if $arg0 == 0 || (void *)$aptr == (void *)$arg0 | |
if $p->magic == 0x7312f8dc | |
set $stat = "OK" | |
end | |
if $p->magic == 0x99954317 | |
set $stat = "FREED" | |
end | |
if $p->magic == 0xfb8277dc | |
set $stat = "CACHED" | |
end | |
set $filename = strrchr($p->filename, '/') | |
if !$filename | |
set $filename = $p->filename | |
else | |
set $filename = $filename + 1 | |
end | |
printf " %p ", $aptr | |
if $p->size == sizeof(struct _zval_struct) && ((struct _zval_struct *)$aptr)->type >= 0 && ((struct _zval_struct *)$aptr)->type < 10 | |
printf "ZVAL?(%-2d) ", $p->size | |
else | |
printf "%-9d ", $p->size | |
end | |
set $total_size = $total_size + $p->size | |
printf "%-06s %s:%d", $stat, $filename, $p->lineno | |
if $p->orig_filename | |
set $orig_filename = strrchr($p->orig_filename, '/') | |
if !$orig_filename | |
set $orig_filename = $p->orig_filename | |
else | |
set $orig_filename = $orig_filename + 1 | |
end | |
printf " <= %s:%d\n", $orig_filename, $p->orig_lineno | |
else | |
printf "\n" | |
end | |
if $arg0 != 0 | |
set $p = 0 | |
set $not_found = 0 | |
else | |
set $p = $p->pNext | |
end | |
else | |
set $p = $p->pNext | |
end | |
end | |
if $not_found | |
printf "no such block that begins at %p.\n", $aptr | |
end | |
if $arg0 == 0 | |
printf "-------------------------------------------------------------------------------\n" | |
printf " total: %d bytes\n", $total_size | |
end | |
end | |
document zmemcheck | |
show status of a memory block. | |
usage: zmemcheck [ptr]. | |
if ptr is 0, all blocks will be listed. | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage: gdb --batch -x php_trace -p ${PID} | |
source php_gdbinit | |
dump_bt executor_globals.current_execute_data |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment