WebKit is an engine that uses multiple processes and multiple threads at runtime. There are some very useful generic instructions on how to debug one of its processes on Linux (with focus on the GTK port) in this wiki page. They work pretty well when WebKit is built using the Flatpak SDK and the scripts and gdbserver is installed in the system, but I faced some problems when I wanted to built WebKit with CMake having custom build and installation directories. So in this post, I’m going to describe the easiest way I’ve found so far to debug it when SDK is not being used and a gdbserver is not present in the system. I’ve found this simple solution after having tried a combination of tricks from the WebKit wiki instructions, GDB documentation and a discussion with my colleages at Igalia.
Building WebKit with CMake
To build WebKit I follow the steps I’ve described in my previous post for WPE, and when I build the GTK port I simply set the PORT (-DPORT
CMake option) to be GTK instead of WPE.
Configuring GDB
Supposing that the WebKit MiniBrowser is used for debugging the WebGL or HTML output, there are different ways to use GDB. You can either start the program with GDB attached ( gdb --args ./build/bin/MiniBrowser bar.html) or start MiniBrowser and then attach the WebProcess to GDB. Not all the settings I’ll list below are strictly required in both cases but having them set doesn’t harm.
Settings:
I opened my global
$HOME/.gdbinit and included the WebKit
.gdbinit path as a safe path:
add-auto-load-safe-path /home/eleni/igalia/code/WebKit/.gdbinit
Then, I added the following lines in the WebKit/.gdbinit:
1 2 |
set follow-fork-mode child set detach-on-fork off |
What they are for:
set follow-fork-mode child:
The new process is debugged after a fork. The parent process runs unimpeded.
set detach-on-fork off:
In this mode GDB will be attached to both parent and child processes after a call to fork() or vfork(). One can use the info inferiors command to show details and the inferior command to switch between them.
Running WebKit with GDB and setting a breakpoint in WebGL code.
I opened a terminal (where I’ve set all the required environment variables to build and run WebKit, see my previous post on building WebKit) and ran Minibrowser from the build directory, for me this directory is WebKit/build/
(if you use the flatpak SDK it will be the standard build directory WebKitBuild
and you can modify the paths accordingly):
1 |
./build/bin/MiniBrowser bar.html |
where bar.html
was a customized WebGL test I wanted to debug (most standard WebGL tests can be found under LayoutTests/fast/canvas/webgl
or LayoutTests/webgl/
)
I switched to a different terminal where the environment was identical to the first terminal’s environment (important!):
As I wanted to debug WebGL, I’ve first found the process that contains the WebGL calls. If you check the pstree output, you will notice that WebKit forks 2 processes: the WebKitWebProces and the WebKitNetworkPr that are the Web and the Network processes respectively.
1 2 3 |
ββxtermβββbashβββMiniBrowserββ¬βWebKitNetworkPrβββ10*[{WebKitNetworkPr}] β ββWebKitWebProcesβββ16*[{WebKitWebProces}] β ββ9*[{MiniBrowser}] |
WebGL is part of the WebProcess (you can tell that from the code). So, in order to debug graphics code I had to attach the WebProcess to GDB.
This is how to do it:
1. Enter the directory where you would run MiniBrowser! This is important otherwise some symbols might not be found!!! I run MiniBrowser from my checkout root directory, so the command was:
1 |
cd ~/igalia/code/WebKit |
2. Find the pid of the WebProcess:
1 |
pgrep -i webproc |
a pid will be returned for example 29086
3. Attach GDB to this process:
1 |
gdb ./build/bin/MiniBrowser 29086 |
Note that you must run gdb
and use the path to MiniBrowser that is running, the same way you’d set it to start MiniBrowser inside GDB and simply add the pid at the end. No other parameters should be needed as MiniBrowser is supposed to run at this moment.
4. Set a breakpoint the “usual” way, eg:
1 |
b ExtensionsGLOpenGL.cpp:101 |
5. Press continue (c
in GDB) and reload the webpage in MiniBrowser. You will see that the program stopped when it reached the breakpoint:
Note that symbols are loaded from my custom installation directory ~/igalia/install
where I install every WebKit dependency I need to debug myself as well as WebKit itself! This is why it is important to be in the correct directory when you attach the WebProcess to GDB.
You might not have to worry about this when you’ve built WebKit using the flatpak SDK and simply follow the instructions from the wiki page I’ve mentioned before, but if you do everything manually, running gdb -p
on a new terminal without the path to MiniBrowser and the same environment setup might attach the process, but GDB won’t be able to detect all the available debugging symbols.
What about WEB_PROCESS_CMD_PREFIX
?
If you build WebKit the recommended way (using the flatpak SDK) you might also want to try setting the prefix WEB_PROCESS_CMD_PREFIX
from instructions. Building WebKit inside “non-standard” build directories with CMake and the option -DDEVELOPER_MODE=ON
is tricky as some python scripts involved in the process might crash or complain. In case you build with CMake and don’t use the “standard” paths you’d rather use the steps I’ve just described.
Other experiments
Something else I tried and worked for me was to attach the parent process to gdb ( gdb --args ./build/bin/MiniBrowser bar.html) and switch processes using inferior <num_process>.
BUT! there were other issues when switching between processes and threads: a process or a thread could crash from a bug while I was debugging another, and then I wasn’t always able to switch to it. Also, always following the child process would by default follow the network process and I’d have to switch to the web later. So, I gave up and chose the simple method I described above.
And at least for debugging WebGL tests, attaching the WebProcess to gdb without using the gdbserver or having to set the prefix works well for me so far.
Links
[1]: WebKitGTK Debugging https://trac.webkit.org/wiki/WebKitGTK/Debugging
[2]: Environment Variables that can be used for debugging: https://trac.webkit.org/wiki/EnvironmentVariables (not used in this post, but handy in general!)
[3]: How to build WebKit with CMake (change the port to GTK instead of WPE for GTK builds): Build WebKit/WPE on Linux/X11
See you next time!
Thank you for this tutorial, i was missing this somewhat basic gdb skill.
However i learnt the great power of https://sourceware.org/elfutils/Debuginfod.html
bash
export DEBUGINFOD_URLS="https://debuginfod.debian.net"
and then just use gdb as usual, it will download symbols automatically (and cache them). Checkout the upstream doc to know what url works with your favorite distribution.