Right now, GDB has no way to be told about JITed code. I'm working on adding such an interface, and the LLVM JIT would be the first client. The interface is evolving, and I'll admit that right now it's downright terrible. Here's how it works right now: - The JIT generates the machine code and DWARF call frame info (.eh_frame/.debug_frame) for a function into memory. - The JIT copies that info into a temporary ELF file with a symbol for the function. - The JIT stuffs the filename and text address (function start) into a global struct at a special symbol that GDB knows about. - The JIT calls a function marked noinline that GDB knows about and has put an internal breakpoint in. - GDB takes control when the breakpoint fires, reads the filename and addr from the struct, and does the equivalent of an 'add-symbol-file' command from the prompt with those two arguments. - The JIT continues, and the next time we stop the program, we are able to produce a proper backtrace. There is a lot of room for improvement, but I have to start somewhere, and this works. Here is a GDB session debugging a simple JITed program that makes three nested calls and segfaults without debug info, and then with debug info: [rnk at knuckles llvm-gdb]$ ../gdb-install/bin/gdb ../llvm-gdb/Debug/bin/lli GNU gdb (GDB) 6.8.50.20090609-cvs Copyright (C) 2009 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-unknown-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... (gdb) run t.bc Starting program: /home/rnk/llvm-gdb/Debug/bin/lli t.bc [Thread debugging using libthread_db enabled] Program received signal SIGSEGV, Segmentation fault. 0x00007ffff5d310b8 in ?? () (gdb) bt #0 0x00007ffff5d310b8 in ?? () #1 0x0000000000000003 in ?? () #2 0x0000000000000004 in ?? () #3 0x00037ffff5d30fd0 in ?? () #4 0x00007ffff5d3108c in ?? () #5 0x00027fff00000003 in ?? () #6 0x00007ffff5d3105a in ?? () #7 0x01000002f5d30ff0 in ?? () #8 0x00007ffff5d3102c in ?? () #9 0x0100000000000001 in ?? () #10 0x0000000001430220 in ?? () #11 0x00007fff00000001 in ?? () #12 0x0000000000b8692c in llvm::JIT::runFunction (this=0x13fdb20, F=0x13fa520, ArgValues=...) at JIT.cpp:394 #13 0x0000000000ba9a69 in llvm::ExecutionEngine::runFunctionAsMain (this=0x13fdb20, Fn=0x13fa520, argv=..., envp=0x7fffffffe410) at ExecutionEngine.cpp:376 #14 0x00000000007eb665 in main (argc=2, argv=0x7fffffffe3f8, envp=0x7fffffffe410) at lli.cpp:205 (gdb) kill Kill the program being debugged? (y or n) y (gdb) run --jit-emit-debug t.bc Starting program: /home/rnk/llvm-gdb/Debug/bin/lli --jit-emit-debug t.bc [Thread debugging using libthread_db enabled] symbol_file: /tmp/llvm_zp32Cb/llvm_function_0x7ffff5d31010_main.o symbol_file: /tmp/llvm_zp32Cb/llvm_function_0x7ffff5d31090_foo.o symbol_file: /tmp/llvm_zp32Cb/llvm_function_0x7ffff5d31110_bar.o symbol_file: /tmp/llvm_zp32Cb/llvm_function_0x7ffff5d31190_baz.o Program received signal SIGSEGV, Segmentation fault. 0x00007ffff5d311a8 in baz () (gdb) bt #0 0x00007ffff5d311a8 in baz () #1 0x00007ffff5d3112c in bar () #2 0x00007ffff5d310aa in foo () #3 0x00007ffff5d3102c in main () #4 0x0000000000b8692c in llvm::JIT::runFunction (this=0x13fdb20, F=0x13fa520, ArgValues=...) at JIT.cpp:394 #5 0x0000000000ba9a69 in llvm::ExecutionEngine::runFunctionAsMain (this=0x13fdb20, Fn=0x13fa520, argv=..., envp=0x7fffffffe3f8) at ExecutionEngine.cpp:376 #6 0x00000000007eb665 in main (argc=3, argv=0x7fffffffe3d8, envp=0x7fffffffe3f8) at lli.cpp:205 (gdb) For reference, here is the corresponding patch against GDB: http://web.mit.edu/rnk/www/jit-patch.diff And finally, the patch to LLVM is attached and uploaded to Rietveld: http://codereview.appspot.com/91042/show I know this code is sketchy and preliminary, but it's useful for us, and I have plans to improve it: http://wiki.llvm.org/HowTo:_Tell_GDB_about_JITted_code Please review! Thanks, Reid -------------- next part -------------- A non-text attachment was scrubbed... Name: gdb-elf-patch.diff Type: text/x-diff Size: 16778 bytes Desc: not available URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20090708/5ebda977/attachment.diff>
Eric Christopher
2009-Jul-08 19:16 UTC
[LLVMdev] Preliminary patch for GDB support for JIT
On Jul 8, 2009, at 11:41 AM, Reid Kleckner wrote:> Right now, GDB has no way to be told about JITed code. I'm working on > adding such an interface, and the LLVM JIT would be the first client. > The interface is evolving, and I'll admit that right now it's > downright terrible. Here's how it works right now: > > - The JIT generates the machine code and DWARF call frame info > (.eh_frame/.debug_frame) for a function into memory. > - The JIT copies that info into a temporary ELF file with a symbol for > the function. > - The JIT stuffs the filename and text address (function start) into a > global struct at a special symbol that GDB knows about. > - The JIT calls a function marked noinline that GDB knows about and > has put an internal breakpoint in. > - GDB takes control when the breakpoint fires, reads the filename and > addr from the struct, and does the equivalent of an 'add-symbol-file' > command from the prompt with those two arguments. > - The JIT continues, and the next time we stop the program, we are > able to produce a proper backtrace. >I've been thinking about this lately myself and this is along the lines I was going as well.> For reference, here is the corresponding patch against GDB: > http://web.mit.edu/rnk/www/jit-patch.diff >This appears to be missing some hunks...> And finally, the patch to LLVM is attached and uploaded to Rietveld: > http://codereview.appspot.com/91042/show >In general I'd like to see the ELF support separated from the main interface. It makes any other platform support require a complete refactor :)> I know this code is sketchy and preliminary, but it's useful for us, > and I have plans to improve it: > http://wiki.llvm.org/HowTo:_Tell_GDB_about_JITted_codeI'm not entirely sure about the lazy debug symbols part, but as far as I can tell neither are you :) The rest of it seems reasonable to me. Note that I can't approve the patch anyhow :) -eric
On Wed, Jul 8, 2009 at 11:41 AM, Reid Kleckner<rnk at mit.edu> wrote:> Right now, GDB has no way to be told about JITed code. I'm working on > adding such an interface, and the LLVM JIT would be the first client.Have you considered how this might be made to work for embedded targets where remote debugging is required? deep
On Wed, Jul 8, 2009 at 12:16 PM, Eric Christopher<echristo at apple.com> wrote:>> For reference, here is the corresponding patch against GDB: >> http://web.mit.edu/rnk/www/jit-patch.diff >> > > This appears to be missing some hunks...Ah, crap, there's a gdb/jit.[ch] but I don't know how to get cvs diff to include them. 'cvs add' wants write access on the main server. Supposedly 'cvs diff -upN' will do it, but it's not working for me... Expect to hear back.>> And finally, the patch to LLVM is attached and uploaded to Rietveld: >> http://codereview.appspot.com/91042/show >> > > In general I'd like to see the ELF support separated from the main > interface. It makes any other platform support require a complete > refactor :)That's a goal I have for the summer. One dumb way to approach it would be to push the ELF creation to the GDB side of the interface, and create the ELF there. That would clean up the interface and make it much nicer. But once you've done that, then it's probably just as much work to figure out the in memory objfile data structures and modify those directly. This was just the path that yielded results most quickly.>> I know this code is sketchy and preliminary, but it's useful for us, >> and I have plans to improve it: >> http://wiki.llvm.org/HowTo:_Tell_GDB_about_JITted_code > > I'm not entirely sure about the lazy debug symbols part, but > as far as I can tell neither are you :)Yeah, that's seeming less and less likely to happen.> The rest of it seems reasonable to me.Great! On Wed, Jul 8, 2009 at 12:27 PM, Sandeep Patel<deeppatel1987 at gmail.com> wrote:> On Wed, Jul 8, 2009 at 11:41 AM, Reid Kleckner<rnk at mit.edu> wrote: >> Right now, GDB has no way to be told about JITed code. I'm working on >> adding such an interface, and the LLVM JIT would be the first client. > > Have you considered how this might be made to work for embedded > targets where remote debugging is required?GDB supports remote debugging, and once GDB can read the info out of the target's memory instead of off the filesystem, then it would probably Just Work. Reid