1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Debugging JITed Code With GDB</title>
<link rel="stylesheet" href="llvm.css" type="text/css">
</head>
<body>
<h1>Debugging JIT-ed Code With GDB</h1>
<ol>
<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 and Eli Bendersky</div>
<!--=========================================================================-->
<h2><a name="background">Background</a></h2>
<!--=========================================================================-->
<div>
<p>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.
</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 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 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.
</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>
<a href="http://jigsaw.w3.org/css-validator/check/referer"><img
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>,
<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>
</body>
</html>
|