1===================== 2Debugging JIT-ed Code 3===================== 4 5Background 6========== 7 8Without special runtime support, debugging dynamically generated code can be 9quite painful. Debuggers generally read debug information from object files on 10disk, but for JITed code there is no such file to look for. 11 12In order to hand over the necessary debug info, `GDB established an 13interface <https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html>`_ 14for registering JITed code with debuggers. LLDB implements it in the 15JITLoaderGDB plugin. On the JIT side, LLVM MCJIT does implement the interface 16for ELF object files. 17 18At a high level, whenever MCJIT generates new machine code, it does so in an 19in-memory object file that contains the debug information in DWARF format. 20MCJIT then adds this in-memory object file to a global list of dynamically 21generated object files and calls a special function 22``__jit_debug_register_code`` that the debugger knows about. When the debugger 23attaches to a process, it puts a breakpoint in this function and associates a 24special handler with it. Once MCJIT calls the registration function, the 25debugger catches the breakpoint signal, loads the new object file from the 26inferior's memory and resumes execution. This way it can obtain debug 27information for pure in-memory object files. 28 29 30GDB Version 31=========== 32 33In order to debug code JIT-ed by LLVM, you need GDB 7.0 or newer, which is 34available on most modern distributions of Linux. The version of GDB that 35Apple ships with Xcode has been frozen at 6.3 for a while. 36 37 38LLDB Version 39============ 40 41Due to a regression in release 6.0, LLDB didn't support JITed code debugging for 42a while. The bug was fixed in mainline recently, so that debugging JITed ELF 43objects should be possible again from the upcoming release 12.0 on. On macOS the 44feature must be enabled explicitly using the ``plugin.jit-loader.gdb.enable`` 45setting. 46 47 48Debugging MCJIT-ed code 49======================= 50 51The emerging MCJIT component of LLVM allows full debugging of JIT-ed code with 52GDB. This is due to MCJIT's ability to use the MC emitter to provide full 53DWARF debugging information to GDB. 54 55Note that lli has to be passed the ``--jit-kind=mcjit`` flag to JIT the code 56with MCJIT instead of the newer ORC JIT. 57 58Example 59------- 60 61Consider the following C code (with line numbers added to make the example 62easier to follow): 63 64.. 65 FIXME: 66 Sphinx has the ability to automatically number these lines by adding 67 :linenos: on the line immediately following the `.. code-block:: c`, but 68 it looks like garbage; the line numbers don't even line up with the 69 lines. Is this a Sphinx bug, or is it a CSS problem? 70 71.. code-block:: c 72 73 1 int compute_factorial(int n) 74 2 { 75 3 if (n <= 1) 76 4 return 1; 77 5 78 6 int f = n; 79 7 while (--n > 1) 80 8 f *= n; 81 9 return f; 82 10 } 83 11 84 12 85 13 int main(int argc, char** argv) 86 14 { 87 15 if (argc < 2) 88 16 return -1; 89 17 char firstletter = argv[1][0]; 90 18 int result = compute_factorial(firstletter - '0'); 91 19 92 20 // Returned result is clipped at 255... 93 21 return result; 94 22 } 95 96Here is a sample command line session that shows how to build and run this 97code via ``lli`` inside LLDB: 98 99.. code-block:: bash 100 101 > export BINPATH=/workspaces/llvm-project/build/bin 102 > $BINPATH/clang -g -S -emit-llvm --target=x86_64-unknown-unknown-elf showdebug.c 103 > lldb $BINPATH/lli 104 (lldb) target create "/workspaces/llvm-project/build/bin/lli" 105 Current executable set to '/workspaces/llvm-project/build/bin/lli' (x86_64). 106 (lldb) settings set plugin.jit-loader.gdb.enable on 107 (lldb) b compute_factorial 108 Breakpoint 1: no locations (pending). 109 WARNING: Unable to resolve breakpoint to any actual locations. 110 (lldb) run --jit-kind=mcjit showdebug.ll 5 111 1 location added to breakpoint 1 112 Process 21340 stopped 113 * thread #1, name = 'lli', stop reason = breakpoint 1.1 114 frame #0: 0x00007ffff7fd0007 JIT(0x45c2cb0)`compute_factorial(n=5) at showdebug.c:3:11 115 1 int compute_factorial(int n) 116 2 { 117 -> 3 if (n <= 1) 118 4 return 1; 119 5 int f = n; 120 6 while (--n > 1) 121 7 f *= n; 122 (lldb) p n 123 (int) $0 = 5 124 (lldb) b showdebug.c:9 125 Breakpoint 2: where = JIT(0x45c2cb0)`compute_factorial + 60 at showdebug.c:9:1, address = 0x00007ffff7fd003c 126 (lldb) c 127 Process 21340 resuming 128 Process 21340 stopped 129 * thread #1, name = 'lli', stop reason = breakpoint 2.1 130 frame #0: 0x00007ffff7fd003c JIT(0x45c2cb0)`compute_factorial(n=1) at showdebug.c:9:1 131 6 while (--n > 1) 132 7 f *= n; 133 8 return f; 134 -> 9 } 135 10 136 11 int main(int argc, char** argv) 137 12 { 138 (lldb) p f 139 (int) $1 = 120 140 (lldb) bt 141 * thread #1, name = 'lli', stop reason = breakpoint 2.1 142 * frame #0: 0x00007ffff7fd003c JIT(0x45c2cb0)`compute_factorial(n=1) at showdebug.c:9:1 143 frame #1: 0x00007ffff7fd0095 JIT(0x45c2cb0)`main(argc=2, argv=0x00000000046122f0) at showdebug.c:16:18 144 frame #2: 0x0000000002a8306e lli`llvm::MCJIT::runFunction(this=0x000000000458ed10, F=0x0000000004589ff8, ArgValues=ArrayRef<llvm::GenericValue> @ 0x00007fffffffc798) at MCJIT.cpp:554:31 145 frame #3: 0x00000000029bdb45 lli`llvm::ExecutionEngine::runFunctionAsMain(this=0x000000000458ed10, Fn=0x0000000004589ff8, argv=size=0, envp=0x00007fffffffe140) at ExecutionEngine.cpp:467:10 146 frame #4: 0x0000000001f2fc2f lli`main(argc=4, argv=0x00007fffffffe118, envp=0x00007fffffffe140) at lli.cpp:643:18 147 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 frame #6: 0x0000000001f2dc7a lli`_start + 42 149 (lldb) finish 150 Process 21340 stopped 151 * thread #1, name = 'lli', stop reason = step out 152 Return value: (int) $2 = 120 153 154 frame #0: 0x00007ffff7fd0095 JIT(0x45c2cb0)`main(argc=2, argv=0x00000000046122f0) at showdebug.c:16:9 155 13 if (argc < 2) 156 14 return -1; 157 15 char firstletter = argv[1][0]; 158 -> 16 int result = compute_factorial(firstletter - '0'); 159 17 160 18 // Returned result is clipped at 255... 161 19 return result; 162 (lldb) p result 163 (int) $3 = 73670648 164 (lldb) n 165 Process 21340 stopped 166 * thread #1, name = 'lli', stop reason = step over 167 frame #0: 0x00007ffff7fd0098 JIT(0x45c2cb0)`main(argc=2, argv=0x00000000046122f0) at showdebug.c:19:12 168 16 int result = compute_factorial(firstletter - '0'); 169 17 170 18 // Returned result is clipped at 255... 171 -> 19 return result; 172 20 } 173 (lldb) p result 174 (int) $4 = 120 175 (lldb) expr result=42 176 (int) $5 = 42 177 (lldb) p result 178 (int) $6 = 42 179 (lldb) c 180 Process 21340 resuming 181 Process 21340 exited with status = 42 (0x0000002a) 182 (lldb) exit 183