When I'm writing a library meant to be used with LD_PRELOAD
, how can I debug its __attribute__((__constructor__))
functions? They always seem to run before GDB can stop the process. As an MCVE, run the following:
cat > preflight.c <<EOF
#include <stdio.h>
#include <stdlib.h>
__attribute__((__constructor__))
void preflight(void) {
puts("Exiting from preflight");
exit(42);
}
EOF
gcc -g -fPIC -shared preflight.c -o preflight.so
gdb /bin/true -ex 'set environment LD_PRELOAD ./preflight.so' \
-ex 'set breakpoint pending on' \
-ex 'break preflight' \
-ex 'starti'
The end of the GDB output will look like this:
Function "preflight" not defined.
Breakpoint 1 (preflight) pending.
Starting program: /usr/bin/true
Exiting from preflight
During startup program exited with code 42.
(gdb)
Observe that the preflight
function ran before GDB stopped the program, even though I tried to set a breakpoint on it, and I used starti
, which is supposed to break on the first instruction. What do I have to do differently to get GDB to break at the preflight
function?
This happens because by default, GDB uses a shell to start the program being debugged, and environment variables provided to
set environment
apply to the shell too, so mypreflight
function ran there. GDB doesn't debug the shell, so when it ran there, it didn't stop it. There are two choices for how to work around this:set startup-with-shell off
.set environment LD_PRELOAD ./preflight.so
, doset exec-wrapper env LD_PRELOAD=./preflight.so
.References: GDB's documentation, sections 4.2 Starting your Program and 4.4 Your Program's Environment.