I'm playing around with LLDB (debugger) and I did the following experiment.
Run PHP script as:
php -r "sleep(1000);"
or:
php -r "function r(){sleep(1000);}r();"
On another console, I've called directly zif_debug_backtrace()
from lldb
:
echo 'call (void)zif_debug_backtrace()' | lldb -p $(pgrep -fn php)
Above worked, however the process stopped with the following warning:
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
I'm not quite sure why the script had to stop and what I need to do to achieve transparency (without affecting the script)?
P.S. The same happening when calling zif_debug_print_backtrace()
and when calling custom_backtrace()
it is showing: Backtrace null function called
. I'm using xdebug
if that change anything.
Maybe I need to call a different function like zend_fetch_debug_backtrace
(see: image dump symtab
)? Or use the right arguments, if so, which one?
I'm only interested in lldb
/gdb
solutions in order to print the backtrace.
Similar approach works in Ruby, e.g.:
ruby -e 'sleep 1000'
.echo 'call (void)rb_backtrace()' | lldb -p $(pgrep -nf ruby)
.You can't call internal functions like that, internal functions expect things like frame, return value and so on ... don't' do it.
There is a .gdbinit distributed with php, in it there is a function named zbacktrace, you could port that to lldb.
Another thing you could do, which is likely easier, is just call the API function that generates a trace, but call it properly.
Here it is for 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
And for 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)
Since you asked, 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)
I played a bit around with this and found out how it works:
echo 'call (void)zif_debug_print_backtrace(0)' | lldb -p $(pgrep -fn php)
For your example of above this will not print anything because there is no backtrace. But when you run a script like this:
php -r "function r(){sleep(1000);}r();"
Then the lldb command will cause the PHP process to output:
#0 r() called at [Command line code:1]
Voila. Unfortunately this also crashes the script.
It does work with gdb
, though:
echo 'call zif_debug_print_backtrace(0,0,0,0,0)' | gdb -p $(pgrep -fn php)
when detaching the script continues to run. (tested on Debian with PHP 5.6.14 (DEBUG))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With