Я играю с LLDB (отладчик) и я сделал следующий эксперимент.
Запустите PHP скрипт как:
php -r "sleep(1000);"
или же:
php -r "function r(){sleep(1000);}r();"
На другой консоли я звонил напрямую zif_debug_backtrace()
от lldb
:
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, например:
ruby -e 'sleep 1000'
,echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -nf ruby)
,Вы не можете вызывать такие внутренние функции, внутренние функции ожидают такие вещи, как фрейм, возвращаемое значение и так далее … не делайте этого.
Eсть .gdbinit распространяется с php, в нем есть функция с именем 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 для 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)
при отсоединении скрипт продолжает работать. (протестировано на Debian с PHP 5.6.14 (DEBUG))