mirror of
https://github.com/php/php-src.git
synced 2024-09-24 19:37:26 +00:00
![Xinchen Hui](/assets/img/avatar_default.png)
get(ZTS build): (gdb) zbacktrace You can't do that without a process to debug. (gdb) set_ts 0x4112500 (gdb) zbacktrace [0x2b232e83a1d8] call_user_func(array(2)[0x2b232e879528], array(1)[0x2b232e878fa0]) /tmp/1.php:4 [0x7fffcb2efd80] A->__call("xxx", array(1)[0x2b232e878fa0])
670 lines
13 KiB
Plaintext
670 lines
13 KiB
Plaintext
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 "%lf", $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: %lf", $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
|