Search code examples
linuxgdbptrace

Position-independent executables and ptrace


I would like to ptrace a PIE on Linux and e.g. break at a given instruction address. From disassembly, I have the relative address of the instruction - how can I find out the location the executable was loaded at so I can get the absolute address?

GDB is able to trace PIEs - how does it deal with this?


Solution

  • how does it deal with this?

    On Linux, the dynamic loader ld-linux... has a special function: _dl_debug_state(), which the loader calls just before and just after loading shared libraries, and just after setting a global variable: _r_debug.r_state to RT_ADD or RT_CONSISTENT.

    A debugger can set a breakpoint on that function, examine .r_state and _r_debug.r_map, and in doing so discover which ELF binaries are loaded at which address.

    This mechanism was used to discover where e.g. libc.so.6 has been loaded long before PIE binaries were supported. A PIE binary is just a special case of a shared library, so the exact same mechanism works for it as well.

    This begs the question: how does GDB discover where ld-linux itself has been loaded (so the breakpoint on _dl_debug_state() can be set). The kernel tells it via the auxiliary vector, AT_BASE entry. More info on aux vector here.