4

I am trying to debug a php scripts via console with GDB but I am not able to set breakpoints. This is what I've done. I've created a script with this content:

<?php
echo "1";
echo "1";
echo "1";
echo "1";
echo "1";
echo "1";
echo "1";

And this is my temptative to debug it

# gdb php -d CANCELLAMI.php 
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...

warning: /root/CANCELLAMI.php is not a directory.
Reading symbols from /usr/bin/php...(no debugging symbols found)...done.

Now that I am inside gdb, I put a breakpoint in line 2.

(gdb) break CANCELLAMI.php:2
No symbol table is loaded.  Use the "file" command.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (CANCELLAMI.php:2) pending.

But if I run CANCELLAMI script

(gdb) run CANCELLAMI.php 
Starting program: /usr/bin/php CANCELLAMI.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
11111111[Inferior 1 (process 30216) exited normally]

the whole script is executed.

sensorario
  • 20,262
  • 30
  • 97
  • 159
  • Related: [How to get current PHP function name in gdb?](https://reverseengineering.stackexchange.com/q/9558/12021) – kenorb Dec 18 '18 at 23:17

3 Answers3

12

You can trigger a breakpoint from PHP relatively easily:

  1. compile PHP with configure --enable-debug.
  2. find a handy PHP function the script doesn't call. Say, hebrevc (or quotemeta or spl_autoload_extensions -- be creative, PHP has tons of functions). Add a call where you want to trigger.
  3. next, start gdb and put a breakpoint on zif_hebrevc. If you read the PHP source, you will find
    1. PHP_FUNCTION(hebrevc)
    2. #define PHP_FUNCTION ZEND_FUNCTION
    3. define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
    4. #define ZEND_FN(name) zif_##name
    5. #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)

So all this leads to zif_hebrevc (or zif_quotemeta or zif_spl_autoload_extensions).

You probably want source /path/to/the/php/source/checkout/.gdbinit this is also optional but it's very hard to work with PHP without it. This file gives you commands like zbacktrace, printzv, print_ht etc. The best documentation for this .gdbinit is the source.

Finally, http://lxr.php.net/ is your friend to navigate the PHP source.

gdb start

chx
  • 11,270
  • 7
  • 55
  • 129
5

Short answer: If you want to debug PHP scripts use xdebug.


Currently, gdb can only really debug compiled languages. It has a lot of knowledge baked in about executable file formats, debug info formats, how to unwind stack frames, and low-level stuff like that. What it doesn't have is a way to associate these things with higher-level constructs in interpreters.

Now, it is possible to debug scripts this way, if you know enough about the interpreter. You can step through the interpreter and understand what it is doing. I've done this before -- it is doable but not exactly pleasant. It's hard enough that it's only really worth doing if you are trying to find a bug in the interpreter triggered by some particular script.

Occasionally the idea arises that gdb could debug scripts. This is a good idea, but it is a reasonably large amount of work. As far as I know, nobody is currently working on it.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
Tom Tromey
  • 21,507
  • 2
  • 45
  • 63
  • The answer is a bit misleading since it leaves the OP with a feeling that *there is something* or *it might work someday*. Fact is that gdb will never be able to debug scripting languages (how should it?) and you need to use xdebug if you want to debug php scripts. – hek2mgl Jun 05 '15 at 15:34
  • I don't think it is all that misleading. There is one paragraph about the idea, which is something that really does come up a lot. For example it is mentioned here as a goal: https://sourceware.org/gdb/wiki/PythonGdb – Tom Tromey Jun 05 '15 at 18:31
  • Integrate python scripting into gdb and debug python scripts with gdb are complete different things! I mean, how do you expect it should work? Should gdb know how a scripting language works internally? Should gdb getting updated every time a scripting language changes? Do you really think that Mr. Stallman cares about PHP, Python, Perl? – hek2mgl Jun 05 '15 at 18:54
  • This isn't really the place to debate the idea. The short version is that the extensions would be written in Python using the gdb Python API (which would be suitably extended to make this possible); and would be shipped with the interpreters. Stallman's cares don't enter into this at all. – Tom Tromey Jun 05 '15 at 19:27
  • You are right, this is not the place to discuss this. However, I would really like to know a little bit more. Looking at your profile shows that you have a proof understanding of gdb. If you have a few minutes I would really appreciate to [chat](http://chat.stackoverflow.com/rooms/79810/debugging-scripting-languages-with-gdb) a few messages about how you think it could work. Don't be afraid of an endless discussion and only if you like.. – hek2mgl Jun 05 '15 at 19:42
  • 1
    There isn't much out there really. Once I wrote up a roadmap for Python scripting in gdb that went into a bit more detail (but still not much) about how to accomplish this particular goal. It is one of the bullets here: https://sourceware.org/ml/gdb/2010-08/msg00139.html . I can't chat but if you email I'll reply. – Tom Tromey Jun 05 '15 at 19:47
  • There are valid reasons why you would want to debug PHP code with `gdb`; [PHP even provides a `.gdbinit` with helper functions to accomodate this](https://github.com/php/php-src/blob/master/.gdbinit). We've encountered a situation where a missing CURL timeout in our PHP code led to a complete Apache deadlock on a production server (several Apache instances waited endlessly for CURL requests and kept sessions locked, while all other Apache instances were waiting for the session locks). Thanks to `gdb` and the PHP helper function `zbacktrace`, we were easily able to pinpoint the broken code. – Martin von Wittich Jan 20 '21 at 21:14
0

In case you want to understand how, e.g., type conversion works, you can set a breakpoint at execute_ex() function. It sequentially executes operation after operation. The following gdb session:

(gdb) n
54056  HYBRID_SWITCH() {
(gdb)
54383  ZEND_INIT_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
(gdb)
54384  HYBRID_BREAK();
(gdb)
54524  ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
(gdb)
54525  HYBRID_BREAK();
(gdb)
54243  ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
(gdb)
54244  HYBRID_BREAK();
(gdb)
54415  ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);

Corresponds to the following script:

<?php sleep(1); echo 0.1 + 0.2;

The trick is step in at the right moment.

x-yuri
  • 16,722
  • 15
  • 114
  • 161