Navigation

Without special runtime support, debugging dynamically generated code with
GDB (as well as most debuggers) can be quite painful. Debuggers generally
read debug information from the object file of the code, but for JITed
code, there is no such file to look for.

In order to communicate the necessary debug info to GDB, an interface for
registering JITed code with debuggers has been designed and implemented for
GDB and LLVM MCJIT. At a high level, whenever MCJIT generates new machine code,
it does so in an in-memory object file that contains the debug information in
DWARF format. MCJIT then adds this in-memory object file to a global list of
dynamically generated object files and calls a special function
(__jit_debug_register_code) marked noinline that GDB knows about. When
GDB attaches to a process, it puts a breakpoint in this function and loads all
of the object files in the global list. When MCJIT calls the registration
function, GDB catches the breakpoint signal, loads the new object file from
the inferior’s memory, and resumes the execution. In this way, GDB can get the
necessary debug information.

In order to debug code JIT-ed by LLVM, you need GDB 7.0 or newer, which is
available on most modern distributions of Linux. The version of GDB that
Apple ships with Xcode has been frozen at 6.3 for a while. LLDB may be a
better option for debugging JIT-ed code on Mac OS X.

Consider the following C code (with line numbers added to make the example
easier to follow):

1intcompute_factorial(intn)2{3if(n<=1)4return1;56intf=n;7while(--n>1)8f*=n;9returnf;10}111213intmain(intargc,char**argv)14{15if(argc<2)16return-1;17charfirstletter=argv[1][0];18intresult=compute_factorial(firstletter-'0');1920// Returned result is clipped at 255...21returnresult;22}

Here is a sample command line session that shows how to build and run this
code via lli inside GDB: