如何在lldb的实时运行脚本上转储PHP回溯


How to dump PHP backtrace on live running script in lldb?

我正在玩LLDB(调试器),我做了以下实验。

  1. 运行PHP脚本

    php -r "sleep(1000);"
    

    或:

    php -r "function r(){sleep(1000);}r();"
    
  2. 在另一个控制台上,我从lldb直接调用zif_debug_backtrace():

    echo 'call (void)zif_debug_backtrace()' | lldb -p $(pgrep -fn php)
    

以上操作有效,但是进程停止并出现以下警告:

Warning: sleep() expects at most 2 parameters, 1606408648 given in Command line code on line 1
Call Stack:
    0.0016     235152   1. {main}() Command line code:0
    0.0021     235248   2. sleep(1000) Command line code:1

我不太确定为什么脚本必须停止,我需要做些什么来实现透明度(不影响脚本)?

注:调用zif_debug_print_backtrace()和调用custom_backtrace()时也发生同样的情况,它显示:Backtrace null function called。我使用xdebug,如果这改变了什么。

也许我需要调用不同的函数,如zend_fetch_debug_backtrace(见:image dump symtab)?或者使用正确的参数,如果是,哪一个?

我只对lldb/gdb解决方案感兴趣,以便打印回溯。


类似的方法在Ruby中也可以使用,例如:
  1. 运行ruby -e 'sleep 1000' .
  2. 在另一个终端:echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -nf ruby) .

你不能这样调用内部函数,内部函数期望框架,返回值等…别这么做。

php中有一个。gdbinit,其中有一个名为zbacktrace的函数,你可以将它移植到lldb。

您可以做的另一件事可能更容易,那就是调用生成跟踪的API函数,但是要正确调用它。

下面是GDB (PHP7):

define ztrace
    set $var = malloc(sizeof(zval))
    call zend_fetch_debug_backtrace($var, 0, 0, 0)
    call php_var_dump($var, 0)
    call _zval_ptr_dtor($var, 0, 0)
    call free($var)
end
document ztrace
    show a debug backtrace
end 

对于LLDB (PHP7):

(lldb) expr zval $var;
(lldb) expr zend_fetch_debug_backtrace(&$var, 0, 0, 0)
(lldb) expr php_var_dump(&$var, 0)
(lldb) expr _zval_ptr_dtor(&$var, 0, 0)
LLDB for PHP5.6 (no-zts):
(lldb) expr zval *$zp = (zval*) malloc(sizeof(zval))
(lldb) expr zend_fetch_debug_backtrace($zp, 0, 0, 0)
(lldb) expr php_var_dump(&$zp, 0)
(lldb) expr _zval_ptr_dtor(&$zp, 0, 0)
(lldb) expr free($zp)

我玩了一下,发现它是如何工作的:

echo 'call (void)zif_debug_print_backtrace(0)' | lldb -p $(pgrep -fn php)

对于上面的例子,这将不会打印任何东西,因为没有回溯。但是当您运行这样的脚本时:

php -r "function r(){sleep(1000);}r();"

lldb命令将导致PHP进程输出:

#0  r() called at [Command line code:1]

瞧。不幸的是,这也会使脚本崩溃。

它确实适用于gdb:

echo 'call zif_debug_print_backtrace(0,0,0,0,0)' | gdb -p $(pgrep -fn php)

在分离脚本时继续运行。