How do I debug a constructor function in an LD_PRELOAD library?

60 views Asked by At

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?

1

There are 1 answers

0
Joseph Sible-Reinstate Monica On BEST ANSWER

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 my preflight 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:

  1. Do set startup-with-shell off.
  2. Instead of set environment LD_PRELOAD ./preflight.so, do set exec-wrapper env LD_PRELOAD=./preflight.so.

References: GDB's documentation, sections 4.2 Starting your Program and 4.4 Your Program's Environment.