Debug PHP without extensions?
44sReveals a surprising debugging technique that most developers don't know, sparking curiosity.
▶ Play Clip"Delivers a solid, practical debugging technique with a clear example, though the title could be more specific."
This video demonstrates a powerful debugging technique for PHP: attaching the GNU debugger (GDB) to a running PHP process to inspect its state, especially when the process appears to hang. The method uses GDB macros from the PHP source code to obtain a PHP-level backtrace and inspect variables, without needing to modify code or install extensions.
The presenter introduces a debugging approach for PHP that was shown by a colleague, Tim. It requires no PHP extension and no code modifications, and is effective for finding hangs like infinite loops or excessive computation.
The example is a Fibonacci service that calculates Fibonacci numbers. With large inputs, it takes a long time, making it a good candidate for debugging.
To debug, run a curl command with a large number (e.g., 44), then find the process ID of the PHP process and attach GDB to it using 'gdb -p PID'.
After attaching, GDB stops the process. Running 'backtrace' shows the C-level stack, which in this case is in the Tideways observer API called by execute callbacks.
To get a PHP-level backtrace, source the gdb script from the PHP source code (e.g., for PHP 8.2). This script defines functions like 'zbacktrace'.
Calling 'zbacktrace' shows the PHP backtrace, revealing the recursive Fibonacci calculation. You can print local variables of a frame (e.g., frame 33) and global variables using 'print global_vars'.
The technique is powerful for inspecting the state of a running PHP process, especially with PHP-FPM. The downside is that you can't set breakpoints; you only see the current state when attaching.
Attaching GDB to a running PHP process and using the PHP source's GDB macros is a powerful, low-effort way to diagnose hangs and performance issues, providing insights that are otherwise hard to obtain.
What tool is used to attach to a running PHP process for debugging?
GDB (GNU Debugger)
00:31
What is the name of the GDB script that ships with PHP source code?
gdb (a script in the PHP source)
03:26
What command in GDB shows the PHP-level backtrace?
zbacktrace
04:09
What is the main limitation of attaching GDB to a running process?
You cannot set breakpoints; you only see the current state when attaching.
07:13
What type of problems is this debugging method particularly effective for?
Problems where PHP seems to hang, such as infinite loops or excessive computation.
00:31
No extensions or code changes needed
This makes the technique immediately applicable to any PHP setup.
00:31PHP backtrace via GDB macros
Shows how to get a high-level view of the PHP execution stack, which is crucial for debugging.
03:12Powerful for PHP-FPM
Highlights the advantage of attaching to a running process, which is especially useful with PHP-FPM's multiple children.
06:04[00:02] a widespread skill. In fact, what I will show you in this video was news to me and to most of my colleagues. In this video, I'm going to discuss a debugging approach to PHP that my colleague Tim showed us, and I'm fairly certain that
[00:17] you can impress your colleagues with this, too. It even requires no PHP extension to be installed and configured, and it does not require you to litter the code with Wump statements. This method is particularly effective to
[00:31] This method is particularly effective to find problems where PHP seems to hang without knowing why. Think infinite loops or code that does just way too much. The tool I'm talking about is GDB, the GNU debugger. And with some
[00:46] dynamically loaded macros, it becomes a powerhouse that you wouldn't expect. Let's go into the example that Tim has thought um up in his blog post uh that I will also link in the description. Um it's a Fibonacci service. So it
[01:01] calculates uh the Fibonacci numbers and um with a very large input this can take quite um a long time. So we have um the Fibonacci service here. We um have a
[01:13] Fibonacci service here. We um have a server that requires a number parameter to be given. If it's given we run this um uh with a number and run this service uh against that. So on my server I have started the PHP local um um server on
[01:32] port uh 8888 and then I can run a curl script for and then I can run a curl script for example um against this with any number example um against this with any number uh number seven is the result 13
[01:44] uh number seven is the result 13 number 10 is and then I can see that it will take progressively longer to calculate This number 40 for example already takes quite some time.
[01:59] So how can we debug this? Let's uh run the curl command again for quite some the curl command again for quite some time. Uh let's say um 44 repetitions. Then we go into a different terminal and we check for any process running with
[02:16] we check for any process running with the Fibonacci name in it. So we have the the Fibonacci name in it. So we have the process ID here. Then we start a GDB and then we attach it to the running process.
[02:28] And this is uh sort of the magic happening here. You see it stops somewhere. In this case, it uh stops in a tightways um uh hook. We can run the a tightways um uh hook. We can run the back trace command and we can see where
[02:43] in the code this hangs the back trace on the C level. It's in the observer API which is called by the execute callbacks. So um on the server running P um Tideways and PHP local web server um
[02:58] this is where we stopped the process. So it's not running anymore. It's hanging it's not running anymore. It's hanging now and we can debug the state that it's currently in. So the C trace is a little bit boring or maybe we can't understand
[03:12] exactly what's happening here. Can we see the PHP ST trace? And yes, actually that's possible. We can include a script that ships with the PHP source code. that ships with the PHP source code. Opening the browser, we see that in the
[03:26] PHP source, there's a script. GDB in it. And then you need to find the correct And then you need to find the correct version for your PHP process. So in my version for your PHP process. So in my case, I have on the server running PHP
[03:39] 8.2. I'm switching to I'm switching to uh PHP 8.2. And then I can download uh this script and um use this to analyze um this um
[03:55] this running GDB. I already downloaded it in our case. Um I can source it with this script and then I with this sort of function in GDB source and then
[04:09] what I can call is the function Zback trace and what it will do is it will show me the PHP back trace. You can see here it's the PHP back trace. It's uh
[04:21] here it's the PHP back trace. It's uh currently running at um invoke number 45. So it's uh like very deep in the recursive um Fibonacci number calculation. We can now go and print all local variables of a frame. So for
[04:36] local variables of a frame. So for example, let's pick the frame 33 and we example, let's pick the frame 33 and we can say print
[04:49] and it will show us the variables here. So n is 33, n1 and n2 you can see are these numbers here. One of them is undefined. The other one is like very large. So we see we are computing this. Now this is already computed for this
[05:04] run. And in this run we are computing this value here. Maybe we want to find out what like global variables this uh script was called with because maybe the Fibonacci number is like way deeper than 400 uh 45
[05:20] or something. So we want to find out some information about the global variables. Let's call print global vars and it will show the different variables. Here we have dollar get post
[05:34] cookie file server and dollar n. We see n here is 45. But we can also print what the get variable had using print zv. And then we
[05:46] need to specify the memory address of that. And we can see in the get variable we have the key n with the number 45. So have the key n with the number 45. So this is how the script was called.
[06:04] macros, there are more of them, but um it allows you to debug the state of your PHP process using GDB. This was quite powerful and I was amazed
[06:16] seeing this. I knew that I could run GDB against the PHP process um or running the PHP process started by GDB, but that's clumsy um and um it's hard to
[06:28] reproduce, especially with web servers. you can't really know how to GDB into a running process. This is even more complicated with PHP FBM which has lots of children running. So, it's hard to like get this working with GDB attach.
[06:45] It's super easy to just attach to a running PHP process or PHP FBM process and then start debugging from there. And then including the macros and having all this information available makes it really powerful to like find out what
[06:59] the state of the PHP process is. The only downside really is that you don't have like very good break points running. The you if you attach with the script it will stop at the point that it's
[07:13] currently at. So it's not as simple as like setting a break point and waiting for it to hit. But I guess like you can't have everything. If you like this video and PHP performance content in general, please follow this channel,
[07:28] subscribe, and uh you can also subscribe to our newsletter. The link is in the to our newsletter. The link is in the description. Bye.
⚡ Saved you 0h 07m reading this? Transcribe any YouTube video for free — no signup needed.