Removed examples of stack frame inspection which no longer work for old JIT.

Added an example of MCJIT-based debugging.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@155895 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eli Bendersky 2012-05-01 06:15:40 +00:00
parent e106d2e2ac
commit f8b30f9d16

View File

@ -8,93 +8,16 @@
</head>
<body>
<h1>Debugging JITed Code With GDB</h1>
<h1>Debugging JIT-ed Code With GDB</h1>
<ol>
<li><a href="#example">Example usage</a></li>
<li><a href="#background">Background</a></li>
<li><a href="#gdbversion">GDB Version</a></li>
<li><a href="#mcjitdebug">Debugging MCJIT-ed code</a></li>
<ul>
<li><a href="#mcjitdebug_example">Example</a></li>
</ul>
</ol>
<div class="doc_author">Written by Reid Kleckner</div>
<!--=========================================================================-->
<h2><a name="example">Example usage</a></h2>
<!--=========================================================================-->
<div>
<p>In order to debug code JITed 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 JITed code on Mac OS X.
</p>
<p>Consider debugging the following code compiled with clang and run through
lli:
</p>
<pre class="doc_code">
#include &lt;stdio.h&gt;
void foo() {
printf("%d\n", *(int*)NULL); // Crash here
}
void bar() {
foo();
}
void baz() {
bar();
}
int main(int argc, char **argv) {
baz();
}
</pre>
<p>Here are the commands to run that application under GDB and print the stack
trace at the crash:
</p>
<pre class="doc_code">
# Compile foo.c to bitcode. You can use either clang or llvm-gcc with this
# command line. Both require -fexceptions, or the calls are all marked
# 'nounwind' which disables DWARF exception handling info. Custom frontends
# should avoid adding this attribute to JITed code, since it interferes with
# DWARF CFA generation at the moment.
$ clang foo.c -fexceptions -emit-llvm -c -o foo.bc
# Run foo.bc under lli with -jit-emit-debug. If you built lli in debug mode,
# -jit-emit-debug defaults to true.
$ $GDB_INSTALL/gdb --args lli -jit-emit-debug foo.bc
...
# Run the code.
(gdb) run
Starting program: /tmp/gdb/lli -jit-emit-debug foo.bc
[Thread debugging using libthread_db enabled]
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f55164 in foo ()
# Print the backtrace, this time with symbols instead of ??.
(gdb) bt
#0 0x00007ffff7f55164 in foo ()
#1 0x00007ffff7f550f9 in bar ()
#2 0x00007ffff7f55099 in baz ()
#3 0x00007ffff7f5502a in main ()
#4 0x00000000007c0225 in llvm::JIT::runFunction(llvm::Function*,
std::vector&lt;llvm::GenericValue,
std::allocator&lt;llvm::GenericValue&gt; &gt; const&amp;) ()
#5 0x00000000007d6d98 in
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::vector&lt;std::string,
std::allocator&lt;std::string&gt; &gt; const&amp;, char const* const*) ()
#6 0x00000000004dab76 in main ()
</pre>
<p>As you can see, GDB can correctly unwind the stack and has the appropriate
function names.
</p>
</div>
<div class="doc_author">Written by Reid Kleckner and Eli Bendersky</div>
<!--=========================================================================-->
<h2><a name="background">Background</a></h2>
@ -107,37 +30,144 @@ debug information from the object file of the code, but for JITed code, there is
no such file to look for.
</p>
<p>Depending on the architecture, this can impact the debugging experience in
different ways. For example, on most 32-bit x86 architectures, you can simply
compile with -fno-omit-frame-pointer for GCC and -disable-fp-elim for LLVM.
When GDB creates a backtrace, it can properly unwind the stack, but the stack
frames owned by JITed code have ??'s instead of the appropriate symbol name.
However, on Linux x86_64 in particular, GDB relies on the DWARF call frame
address (CFA) debug information to unwind the stack, so even if you compile
your program to leave the frame pointer untouched, GDB will usually be unable
to unwind the stack past any JITed code stack frames.
</p>
<p>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. At a high level, whenever LLVM generates new machine code, it
also generates an object file in memory containing the debug information. LLVM
then adds the object file to the global list of object files and calls a special
function (__jit_debug_register_code) marked noinline that GDB knows about. When
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
(<tt>__jit_debug_register_code</tt>) 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 LLVM calls the registration
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
LLVM's memory, and resumes the execution. In this way, GDB can get the
the inferior's memory, and resumes the execution. In this way, GDB can get the
necessary debug information.
</p>
<p>At the time of this writing, LLVM only supports architectures that use ELF
object files and it only generates symbols and DWARF CFA information. However,
it would be easy to add more information to the object file, so we don't need to
coordinate with GDB to get better debug information.
</p>
</div>
<!--=========================================================================-->
<h2><a name="gdbversion">GDB Version</a></h2>
<!--=========================================================================-->
<p>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.
</p>
<!--=========================================================================-->
<h2><a name="mcjitdebug">Debugging MCJIT-ed code</a></h2>
<!--=========================================================================-->
<div>
<p>The emerging MCJIT component of LLVM allows full debugging of JIT-ed code with
GDB. This is due to MCJIT's ability to use the MC emitter to provide full
DWARF debugging information to GDB.</p>
<p>Note that lli has to be passed the <tt>-use-mcjit</tt> flag to JIT the code
with MCJIT instead of the old JIT.</p>
<h3><a name="mcjitdebug_example">Example</a></h3>
<div>
<p>Consider the following C code (with line numbers added to make the example
easier to follow):</p>
<pre class="doc_code">
1 int compute_factorial(int n)
2 {
3 if (n <= 1)
4 return 1;
5
6 int f = n;
7 while (--n > 1)
8 f *= n;
9 return f;
10 }
11
12
13 int main(int argc, char** argv)
14 {
15 if (argc < 2)
16 return -1;
17 char firstletter = argv[1][0];
18 int result = compute_factorial(firstletter - '0');
19
20 // Returned result is clipped at 255...
21 return result;
22 }
</pre>
<p>Here is a sample command line session that shows how to build and run this
code via lli inside GDB:
</p>
<pre class="doc_code">
$ $BINPATH/clang -cc1 -O0 -g -emit-llvm showdebug.c
$ gdb --quiet --args $BINPATH/lli -use-mcjit showdebug.ll 5
Reading symbols from $BINPATH/lli...done.
(gdb) b showdebug.c:6
No source file named showdebug.c.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (showdebug.c:6) pending.
(gdb) r
Starting program: $BINPATH/lli -use-mcjit showdebug.ll 5
[Thread debugging using libthread_db enabled]
Breakpoint 1, compute_factorial (n=5) at showdebug.c:6
6 int f = n;
(gdb) p n
$1 = 5
(gdb) p f
$2 = 0
(gdb) n
7 while (--n > 1)
(gdb) p f
$3 = 5
(gdb) b showdebug.c:9
Breakpoint 2 at 0x7ffff7ed404c: file showdebug.c, line 9.
(gdb) c
Continuing.
Breakpoint 2, compute_factorial (n=1) at showdebug.c:9
9 return f;
(gdb) p f
$4 = 120
(gdb) bt
#0 compute_factorial (n=1) at showdebug.c:9
#1 0x00007ffff7ed40a9 in main (argc=2, argv=0x16677e0) at showdebug.c:18
#2 0x3500000001652748 in ?? ()
#3 0x00000000016677e0 in ?? ()
#4 0x0000000000000002 in ?? ()
#5 0x0000000000d953b3 in llvm::MCJIT::runFunction (this=0x16151f0, F=0x1603020, ArgValues=...) at /home/ebenders_test/llvm_svn_rw/lib/ExecutionEngine/MCJIT/MCJIT.cpp:161
#6 0x0000000000dc8872 in llvm::ExecutionEngine::runFunctionAsMain (this=0x16151f0, Fn=0x1603020, argv=..., envp=0x7fffffffe040)
at /home/ebenders_test/llvm_svn_rw/lib/ExecutionEngine/ExecutionEngine.cpp:397
#7 0x000000000059c583 in main (argc=4, argv=0x7fffffffe018, envp=0x7fffffffe040) at /home/ebenders_test/llvm_svn_rw/tools/lli/lli.cpp:324
(gdb) finish
Run till exit from #0 compute_factorial (n=1) at showdebug.c:9
0x00007ffff7ed40a9 in main (argc=2, argv=0x16677e0) at showdebug.c:18
18 int result = compute_factorial(firstletter - '0');
Value returned is $5 = 120
(gdb) p result
$6 = 23406408
(gdb) n
21 return result;
(gdb) p result
$7 = 120
(gdb) c
Continuing.
Program exited with code 0170.
(gdb)
</pre>
</div>
</div>
<!-- *********************************************************************** -->
<hr>
<address>
@ -145,7 +175,8 @@ coordinate with GDB to get better debug information.
src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS"></a>
<a href="http://validator.w3.org/check/referer"><img
src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01"></a>
<a href="mailto:reid.kleckner@gmail.com">Reid Kleckner</a><br>
<a href="mailto:reid.kleckner@gmail.com">Reid Kleckner</a>,
<a href="mailto:eliben@gmail.com">Eli Bendersky</a><br>
<a href="http://llvm.org/">The LLVM Compiler Infrastructure</a><br>
Last modified: $Date$
</address>