Debugging ELF Loadable Modules
Warning
Migrated from: https://cwiki.apache.org/confluence/display/NUTTX/Debugging+ELF+Loadable+Modules
Debugging ELF modules loaded in memory can be tricky because the load address in memory does not match the addresses in the ELF file. This challenge has long existed for debugging uClinux programs and Linux kernel modules; the same solution can be used with NuttX ELF files (and probably with NxFLAT modules as well). Below is a summary of one way to approach this:
1. Get ELF Module Load Address
Put a change in nuttx/binfmt
so that you print the address where the ELF
text was loaded into memory.
Turning on BINFMT debug (CONFIG_DEBUG_BINFMT=y
) should give you the same
information, although it may also provide more output than you really want.
Alternatively, you could place a printf()
at the beginning of your main()
function so that your ELF module can print its own load address. For example,
the difference between the address of main()
in your object file and the
address of main()
at run time reveals the actual load address.
2. Make the ELF Module Wait for You
Insert an infinite loop in the main()
routine of your ELF program. For
example:
volatile bool waitforme;
int main (int arc, char **argv)
{
while (!waitforme);
...
When you start the ELF program, you will see where it was loaded in memory, and
the ELF program will remain stuck in the infinite loop. It will continue to
wait for waitforme
to become true before proceeding.
3. Start the Debugger
Start the debugger, connect to the GDB server, and halt the program. If your
debugger is well-behaved, it should stop at the infinite loop in main()
.
4. Load Offset Symbols
Load symbols using the offset where the ELF module was loaded:
(gdb) add-symbol-file <myprogram> <load-address>
Here, <myprogram>
is your ELF file containing symbols, and
<load-address>
is the address where the program text was actually loaded (as
determined above). Single-step a couple of times and confirm that you are in the
infinite loop.
5. And Debug
Set waitforme
to a non-zero value. Execution should exit the infinite loop,
and now you can debug the ELF program loaded into RAM in the usual way.
An Easier Way?
There might be an alternative that allows you to step into the ELF module
without modifying the code to include the waitforme
loop. You could place a
breakpoint on the OS function task_start()
. That function runs before your
ELF program starts, so you should be able to single-step from the OS code
directly into your loaded ELF application—no changes to the ELF application
required.
When you step into the application’s main()
, you have the relocated address
of main()
and can use that address (see step #1) to compute the load offset.