1*332e220eSStefan Gränitz===================== 2*332e220eSStefan GränitzDebugging JIT-ed Code 3*332e220eSStefan Gränitz===================== 451fc86ddSSean Silva 551fc86ddSSean SilvaBackground 651fc86ddSSean Silva========== 751fc86ddSSean Silva 8*332e220eSStefan GränitzWithout special runtime support, debugging dynamically generated code can be 9*332e220eSStefan Gränitzquite painful. Debuggers generally read debug information from object files on 10*332e220eSStefan Gränitzdisk, but for JITed code there is no such file to look for. 1151fc86ddSSean Silva 12*332e220eSStefan GränitzIn order to hand over the necessary debug info, `GDB established an 13*332e220eSStefan Gränitzinterface <https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html>`_ 14*332e220eSStefan Gränitzfor registering JITed code with debuggers. LLDB implements it in the 15*332e220eSStefan GränitzJITLoaderGDB plugin. On the JIT side, LLVM MCJIT does implement the interface 16*332e220eSStefan Gränitzfor ELF object files. 17*332e220eSStefan Gränitz 18*332e220eSStefan GränitzAt a high level, whenever MCJIT generates new machine code, it does so in an 19*332e220eSStefan Gränitzin-memory object file that contains the debug information in DWARF format. 20*332e220eSStefan GränitzMCJIT then adds this in-memory object file to a global list of dynamically 21*332e220eSStefan Gränitzgenerated object files and calls a special function 22*332e220eSStefan Gränitz``__jit_debug_register_code`` that the debugger knows about. When the debugger 23*332e220eSStefan Gränitzattaches to a process, it puts a breakpoint in this function and associates a 24*332e220eSStefan Gränitzspecial handler with it. Once MCJIT calls the registration function, the 25*332e220eSStefan Gränitzdebugger catches the breakpoint signal, loads the new object file from the 26*332e220eSStefan Gränitzinferior's memory and resumes execution. This way it can obtain debug 27*332e220eSStefan Gränitzinformation for pure in-memory object files. 28*332e220eSStefan Gränitz 2951fc86ddSSean Silva 3051fc86ddSSean SilvaGDB Version 3151fc86ddSSean Silva=========== 3251fc86ddSSean Silva 3351fc86ddSSean SilvaIn order to debug code JIT-ed by LLVM, you need GDB 7.0 or newer, which is 3451fc86ddSSean Silvaavailable on most modern distributions of Linux. The version of GDB that 35*332e220eSStefan GränitzApple ships with Xcode has been frozen at 6.3 for a while. 36*332e220eSStefan Gränitz 37*332e220eSStefan Gränitz 38*332e220eSStefan GränitzLLDB Version 39*332e220eSStefan Gränitz============ 40*332e220eSStefan Gränitz 41*332e220eSStefan GränitzDue to a regression in release 6.0, LLDB didn't support JITed code debugging for 42*332e220eSStefan Gränitza while. The bug was fixed in mainline recently, so that debugging JITed ELF 43*332e220eSStefan Gränitzobjects should be possible again from the upcoming release 12.0 on. On macOS the 44*332e220eSStefan Gränitzfeature must be enabled explicitly using the ``plugin.jit-loader.gdb.enable`` 45*332e220eSStefan Gränitzsetting. 4651fc86ddSSean Silva 4751fc86ddSSean Silva 4851fc86ddSSean SilvaDebugging MCJIT-ed code 4951fc86ddSSean Silva======================= 5051fc86ddSSean Silva 5151fc86ddSSean SilvaThe emerging MCJIT component of LLVM allows full debugging of JIT-ed code with 5251fc86ddSSean SilvaGDB. This is due to MCJIT's ability to use the MC emitter to provide full 5351fc86ddSSean SilvaDWARF debugging information to GDB. 5451fc86ddSSean Silva 55*332e220eSStefan GränitzNote that lli has to be passed the ``--jit-kind=mcjit`` flag to JIT the code 56*332e220eSStefan Gränitzwith MCJIT instead of the newer ORC JIT. 5751fc86ddSSean Silva 5851fc86ddSSean SilvaExample 5951fc86ddSSean Silva------- 6051fc86ddSSean Silva 6151fc86ddSSean SilvaConsider the following C code (with line numbers added to make the example 6251fc86ddSSean Silvaeasier to follow): 6351fc86ddSSean Silva 6451fc86ddSSean Silva.. 6551fc86ddSSean Silva FIXME: 6651fc86ddSSean Silva Sphinx has the ability to automatically number these lines by adding 6751fc86ddSSean Silva :linenos: on the line immediately following the `.. code-block:: c`, but 6851fc86ddSSean Silva it looks like garbage; the line numbers don't even line up with the 6951fc86ddSSean Silva lines. Is this a Sphinx bug, or is it a CSS problem? 7051fc86ddSSean Silva 7151fc86ddSSean Silva.. code-block:: c 7251fc86ddSSean Silva 7351fc86ddSSean Silva 1 int compute_factorial(int n) 7451fc86ddSSean Silva 2 { 7551fc86ddSSean Silva 3 if (n <= 1) 7651fc86ddSSean Silva 4 return 1; 7751fc86ddSSean Silva 5 7851fc86ddSSean Silva 6 int f = n; 7951fc86ddSSean Silva 7 while (--n > 1) 8051fc86ddSSean Silva 8 f *= n; 8151fc86ddSSean Silva 9 return f; 8251fc86ddSSean Silva 10 } 8351fc86ddSSean Silva 11 8451fc86ddSSean Silva 12 8551fc86ddSSean Silva 13 int main(int argc, char** argv) 8651fc86ddSSean Silva 14 { 8751fc86ddSSean Silva 15 if (argc < 2) 8851fc86ddSSean Silva 16 return -1; 8951fc86ddSSean Silva 17 char firstletter = argv[1][0]; 9051fc86ddSSean Silva 18 int result = compute_factorial(firstletter - '0'); 9151fc86ddSSean Silva 19 9251fc86ddSSean Silva 20 // Returned result is clipped at 255... 9351fc86ddSSean Silva 21 return result; 9451fc86ddSSean Silva 22 } 9551fc86ddSSean Silva 9651fc86ddSSean SilvaHere is a sample command line session that shows how to build and run this 97*332e220eSStefan Gränitzcode via ``lli`` inside LLDB: 9851fc86ddSSean Silva 9951fc86ddSSean Silva.. code-block:: bash 10051fc86ddSSean Silva 101*332e220eSStefan Gränitz > export BINPATH=/workspaces/llvm-project/build/bin 102*332e220eSStefan Gränitz > $BINPATH/clang -g -S -emit-llvm --target=x86_64-unknown-unknown-elf showdebug.c 103*332e220eSStefan Gränitz > lldb $BINPATH/lli 104*332e220eSStefan Gränitz (lldb) target create "/workspaces/llvm-project/build/bin/lli" 105*332e220eSStefan Gränitz Current executable set to '/workspaces/llvm-project/build/bin/lli' (x86_64). 106*332e220eSStefan Gränitz (lldb) settings set plugin.jit-loader.gdb.enable on 107*332e220eSStefan Gränitz (lldb) b compute_factorial 108*332e220eSStefan Gränitz Breakpoint 1: no locations (pending). 109*332e220eSStefan Gränitz WARNING: Unable to resolve breakpoint to any actual locations. 110*332e220eSStefan Gränitz (lldb) run --jit-kind=mcjit showdebug.ll 5 111*332e220eSStefan Gränitz 1 location added to breakpoint 1 112*332e220eSStefan Gränitz Process 21340 stopped 113*332e220eSStefan Gränitz * thread #1, name = 'lli', stop reason = breakpoint 1.1 114*332e220eSStefan Gränitz frame #0: 0x00007ffff7fd0007 JIT(0x45c2cb0)`compute_factorial(n=5) at showdebug.c:3:11 115*332e220eSStefan Gränitz 1 int compute_factorial(int n) 116*332e220eSStefan Gränitz 2 { 117*332e220eSStefan Gränitz -> 3 if (n <= 1) 118*332e220eSStefan Gränitz 4 return 1; 119*332e220eSStefan Gränitz 5 int f = n; 120*332e220eSStefan Gränitz 6 while (--n > 1) 121*332e220eSStefan Gränitz 7 f *= n; 122*332e220eSStefan Gränitz (lldb) p n 123*332e220eSStefan Gränitz (int) $0 = 5 124*332e220eSStefan Gränitz (lldb) b showdebug.c:9 125*332e220eSStefan Gränitz Breakpoint 2: where = JIT(0x45c2cb0)`compute_factorial + 60 at showdebug.c:9:1, address = 0x00007ffff7fd003c 126*332e220eSStefan Gränitz (lldb) c 127*332e220eSStefan Gränitz Process 21340 resuming 128*332e220eSStefan Gränitz Process 21340 stopped 129*332e220eSStefan Gränitz * thread #1, name = 'lli', stop reason = breakpoint 2.1 130*332e220eSStefan Gränitz frame #0: 0x00007ffff7fd003c JIT(0x45c2cb0)`compute_factorial(n=1) at showdebug.c:9:1 131*332e220eSStefan Gränitz 6 while (--n > 1) 132*332e220eSStefan Gränitz 7 f *= n; 133*332e220eSStefan Gränitz 8 return f; 134*332e220eSStefan Gränitz -> 9 } 135*332e220eSStefan Gränitz 10 136*332e220eSStefan Gränitz 11 int main(int argc, char** argv) 137*332e220eSStefan Gränitz 12 { 138*332e220eSStefan Gränitz (lldb) p f 139*332e220eSStefan Gränitz (int) $1 = 120 140*332e220eSStefan Gränitz (lldb) bt 141*332e220eSStefan Gränitz * thread #1, name = 'lli', stop reason = breakpoint 2.1 142*332e220eSStefan Gränitz * frame #0: 0x00007ffff7fd003c JIT(0x45c2cb0)`compute_factorial(n=1) at showdebug.c:9:1 143*332e220eSStefan Gränitz frame #1: 0x00007ffff7fd0095 JIT(0x45c2cb0)`main(argc=2, argv=0x00000000046122f0) at showdebug.c:16:18 144*332e220eSStefan Gränitz frame #2: 0x0000000002a8306e lli`llvm::MCJIT::runFunction(this=0x000000000458ed10, F=0x0000000004589ff8, ArgValues=ArrayRef<llvm::GenericValue> @ 0x00007fffffffc798) at MCJIT.cpp:554:31 145*332e220eSStefan Gränitz frame #3: 0x00000000029bdb45 lli`llvm::ExecutionEngine::runFunctionAsMain(this=0x000000000458ed10, Fn=0x0000000004589ff8, argv=size=0, envp=0x00007fffffffe140) at ExecutionEngine.cpp:467:10 146*332e220eSStefan Gränitz frame #4: 0x0000000001f2fc2f lli`main(argc=4, argv=0x00007fffffffe118, envp=0x00007fffffffe140) at lli.cpp:643:18 147*332e220eSStefan Gränitz frame #5: 0x00007ffff788c09b libc.so.6`__libc_start_main(main=(lli`main at lli.cpp:387), argc=4, argv=0x00007fffffffe118, init=<unavailable>, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffe108) at libc-start.c:308:16 148*332e220eSStefan Gränitz frame #6: 0x0000000001f2dc7a lli`_start + 42 149*332e220eSStefan Gränitz (lldb) finish 150*332e220eSStefan Gränitz Process 21340 stopped 151*332e220eSStefan Gränitz * thread #1, name = 'lli', stop reason = step out 152*332e220eSStefan Gränitz Return value: (int) $2 = 120 15351fc86ddSSean Silva 154*332e220eSStefan Gränitz frame #0: 0x00007ffff7fd0095 JIT(0x45c2cb0)`main(argc=2, argv=0x00000000046122f0) at showdebug.c:16:9 155*332e220eSStefan Gränitz 13 if (argc < 2) 156*332e220eSStefan Gränitz 14 return -1; 157*332e220eSStefan Gränitz 15 char firstletter = argv[1][0]; 158*332e220eSStefan Gränitz -> 16 int result = compute_factorial(firstletter - '0'); 159*332e220eSStefan Gränitz 17 160*332e220eSStefan Gränitz 18 // Returned result is clipped at 255... 161*332e220eSStefan Gränitz 19 return result; 162*332e220eSStefan Gränitz (lldb) p result 163*332e220eSStefan Gränitz (int) $3 = 73670648 164*332e220eSStefan Gränitz (lldb) n 165*332e220eSStefan Gränitz Process 21340 stopped 166*332e220eSStefan Gränitz * thread #1, name = 'lli', stop reason = step over 167*332e220eSStefan Gränitz frame #0: 0x00007ffff7fd0098 JIT(0x45c2cb0)`main(argc=2, argv=0x00000000046122f0) at showdebug.c:19:12 168*332e220eSStefan Gränitz 16 int result = compute_factorial(firstletter - '0'); 169*332e220eSStefan Gränitz 17 170*332e220eSStefan Gränitz 18 // Returned result is clipped at 255... 171*332e220eSStefan Gränitz -> 19 return result; 172*332e220eSStefan Gränitz 20 } 173*332e220eSStefan Gränitz (lldb) p result 174*332e220eSStefan Gränitz (int) $4 = 120 175*332e220eSStefan Gränitz (lldb) expr result=42 176*332e220eSStefan Gränitz (int) $5 = 42 177*332e220eSStefan Gränitz (lldb) p result 178*332e220eSStefan Gränitz (int) $6 = 42 179*332e220eSStefan Gränitz (lldb) c 180*332e220eSStefan Gränitz Process 21340 resuming 181*332e220eSStefan Gränitz Process 21340 exited with status = 42 (0x0000002a) 182*332e220eSStefan Gränitz (lldb) exit 183