2002-09-25 Martin Baulig <martin@gnome.org>
[mono.git] / doc / jit-debug
1 * How to debug your C# application with the JIT engine 
2
3         To debug a C# application you need to run the JIT in your debugger.
4
5         Before you can do anything useful in a debugger, you need a symbol
6         file which tells your debugger about functions, types, line numbers
7         and such. Unfortunately, this symbol file needs to be recreated each
8         time the JIT compiles a new method since it doesn't know anything
9         about this method (especially not its memory address) before actually
10         compiling it.
11
12         You have two ways of creating a symbol file:
13
14 ** Letting the JIT dynamically create the symbol file
15
16         This'll give you a symbol file which is suitable for debugging IL byte
17         code - you won't see your C# source code.
18
19         However, this method has the advantage that it works with every assembly,
20         no matter whether it has been compiled with Mono's C# compiler (MCS) or
21         with any other compiler. It's currently the only way to debug
22         <tt>corlib.dll</tt> or any other library which cannot be compiled with
23         our compiler yet.
24
25         All that you need is a dump of the IL bytecode for each assembly (including
26         all assemblies this assembly is referencing). This is done by using the
27         <tt>monodis</tt> utility:
28
29         <pre>
30         monodis /home/export/martin/MONO-LINUX/lib/corlib.dll > corlib.il<br>
31         monodis /home/export/martin/MONO-LINUX/lib/System.dll > System.il<br>
32         monodis /home/export/martin/MONO-LINUX/bin/mcs.exe > mcs.il
33         </pre>
34
35         This is normally done automatically, but you can also disable
36         it and create them by hand.  See the <tt>mono</tt> manual page
37         for details.
38
39         Make sure that all the .il files have the same name as their corresponding
40         assembly and that they're all created in the current directory.
41
42         The JIT supports two different debugging file formats:
43
44         <ul>
45         * STABS: This is a very simple debugging format, but it may be the only one
46         which is supported on your system. It is limited to source files of no more
47         than 65.535 lines and it's type support is also very limited. You should only
48         use this if your debugger doesn't support DWARF 2.
49
50         To generate STABS output, use the <tt>--debug=stabs</tt> command line argument.
51
52
53         * DWARF 2: The DWARF 2 debugging format is a very powerful debugging format
54         which can handle source files of arbitrary size and has a highly sophisticated
55         type support. It's the recommended format unless you need to use STABS because
56         your debugger doesn't support DWARF 2.
57
58         To generate DWARF 2 output, use the <tt>--debug=dwarf</tt> command line argument.
59         </ul>
60
61         You need to regenerate the symbol file each time the JIT compiled a new
62         method and each time you restart the JIT. You cannot reuse your symbol file
63         if you start the JIT a second file, not even if you're running the same
64         application with the same input data a second time.
65
66         Regenerating the symbol file is done by calling the JIT's
67         <tt>mono_debug_make_symbols ()</tt> function from within your debugger and
68         then reloading the symbol files. This function creates a <tt>filename-dwarf.s</tt>
69         (or <tt>filename-stabs.s</tt>) assembler input file in the current directory and
70         an object file in <tt>/tmp/filename.o</tt> - you need to tell your debugger to
71         add this object file as symbol file.
72
73         If you're using the GNU debugger, this is done like this:
74
75         <pre>
76         call mono_debug_make_symbols ()
77         add-symbol-file /tmp/corlib.o
78         add-symbol-file /tmp/mcs.o
79         add-symbol-file /tmp/Mono.CSharp.Debugger.o
80         </pre>
81
82         You can also write a GDB macro like this:
83
84         <pre>
85         define reload
86           call mono_debug_make_symbols ()
87           add-symbol-file /tmp/corlib.o
88           add-symbol-file /tmp/mcs.o
89           add-symbol-file /tmp/Mono.CSharp.Debugger.o
90         end
91         </pre>
92
93         Then you can just say <tt>reload</tt> to have GDB recreate the symbol file.
94
95         There's also an <a href="jit-debug-sample.html">example debugging session</a> using
96         the GNU debugger.
97
98 ** Using a symbol file which have been created by the Mono C# compiler
99
100         If you compiled your application with Mono's C# compiler (MCS), you can tell it to
101         create a symbol file which is then processed and rewritten by the JIT engine.
102
103         To do this, you must give MCS the <tt>-g</tt> option:
104
105         <pre>
106         $ mcs -g Foo.cs
107         </pre>
108
109         This creates a <tt>Foo-debug.s</tt> assembler input file.
110
111         To use this in the JIT, you must first copy it to the target machine (the machine
112         where you want to run the JIT to debug your application) and run it through the
113         assembler to produce an object file <tt>Foo-debug.o</tt>. This object file must be
114         in the current directory.
115
116         Then start the JIT in your debugger and give it the <tt>--debug=dwarf-plus</tt> command
117         line argument.
118
119         Each time you call <tt>mono_debug_make_symbols ()</tt> from withing your debugger,
120         the JIT will read this <tt>Foo-debug.o</tt>, fix some machine dependent things like
121         memory addresses etc. in it and write it back to disk.
122
123         If you're using the GNU debugger, you'll want to use a macro like this:
124
125         <pre>
126         define relocate
127           call mono_debug_make_symbols ()
128           add-symbol-file /tmp/corlib.o
129           add-symbol-file mcs-debug.o
130           add-symbol-file Mono.CSharp.Debugger-debug.o
131         end
132         </pre>
133
134         If there is no <tt>assembly-debug.o</tt> file, but an <tt>assembly.il</tt> one, the
135         JIT will fall back to normal DWARF 2 (in the example above, <tt>corlib.dll</tt> was
136         compiled with Microsoft's compiler and the JIT is thus using DWARF to debug it).
137
138         This debugging method only works if you compiled your assembly with MCS, but it'll
139         allow you to actually debug your C# source code :-)
140
141         Here's an <a href="jit-debug-sample2.html">example debugging session</a> using
142         the GNU debugger.
143
144 ** Breakpoints and single stepping
145
146         The JIT has a <tt>--break</tt> command line argument to insert a breakpoint at the
147         beginning of this method. It takes a <tt>Namespace.Class:Method</tt> argument which
148         is the method. This argument can be given multiple times.
149
150         However, once your application is stopped in GDB you may want to insert a breakpoint
151         the next time the JIT compiles a method. There's a global variable
152         <tt>mono_debug_insert_breakpoint</tt> which you can modify in your debugger.
153
154         If this variable is set to a non-zero value, the JIT's <tt>arch_compile_method</tt>
155         will insert a breakpoint the next time it is called, ie. at the top of the next
156         method it compiles. If this value has a positive value, it acts as a counter and is
157         decremented after inserting the breakpoint - setting it to a negative value will let
158         the JIT insert the breakpoint each time it compiles a new method.
159
160         There's also global variable <tt>mono_debug_last_breakpoint_address</tt> which always
161         contains the address of the last inserted breakpoint. You may manually override this
162         address with a <tt>nop</tt> instruction to delete the breakpoint.
163
164         For instance, I have a GDB macro called <tt>enter</tt> which I use to enter a method
165         rather than stepping over it:
166
167         <pre>
168         define enter
169         set mono_debug_insert_breakpoint = 1
170         continue
171         set *mono_debug_last_breakpoint_address = 0x90
172         relocate
173         frame
174         </pre>
175
176         Btw. speaking of single stepping - you should use your debuggers <tt>next</tt> command,
177         not its <tt>step</tt> command for single stepping unless you compiled the JIT without
178         debugging support. The reason for this is that the JIT creates machine code which contains
179         calls to JIT methods such as <tt>mono_object_new_wrapper</tt> at places where you don't
180         expect them - so unless the JIT is compiled at least without line numbers, your debugger
181         will enter such methods if you use <tt>step</tt> rather than <tt>next</tt>.
182
183
184