Welcome to mirror list, hosted at ThFree Co, Russian Federation.

jit-debug « web - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 867738101ae1eaaba833152d3265863761a75bef (plain)
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
* How to debug your C# application with the JIT engine 

	To debug a C# application you need to run the JIT in your debugger.

	Before you can do anything useful in a debugger, you need a symbol
	file which tells your debugger about functions, types, line numbers
	and such. Unfortunately, this symbol file needs to be recreated each
	time the JIT compiles a new method since it doesn't know anything
	about this method (especially not its memory address) before actually
	compiling it.

	You have two ways of creating a symbol file:

** Letting the JIT dynamically create the symbol file

	This'll give you a symbol file which is suitable for debugging IL byte
	code - you won't see your C# source code.

	However, this method has the advantage that it works with every assembly,
	no matter whether it has been compiled with Mono's C# compiler (MCS) or
	with any other compiler. It's currently the only way to debug
	<tt>corlib.dll</tt> or any other library which cannot be compiled with
	our compiler yet.

	All that you need is a dump of the IL bytecode for each assembly (including
	all assemblies this assembly is referencing). This is done by using the
	<tt>monodis</tt> utility:

	<pre>
	monodis /home/export/martin/MONO-LINUX/lib/corlib.dll > corlib.il<br>
	monodis /home/export/martin/MONO-LINUX/lib/System.dll > System.il<br>
	monodis /home/export/martin/MONO-LINUX/bin/mcs.exe > mcs.il
	</pre>

	Make sure that all the .il files have the same name as their corresponding
	assembly and that they're all created in the current directory.

	The JIT supports two different debugging file formats:

	<ul>
	* STABS: This is a very simple debugging format, but it may be the only one
	which is supported on your system. It is limited to source files of no more
	than 65.535 lines and it's type support is also very limited. You should only
	use this if your debugger doesn't support DWARF 2.

	To generate STABS output, use the <tt>--stabs</tt> command line argument.


	* DWARF 2: The DWARF 2 debugging format is a very powerful debugging format
	which can handle source files of arbitrary size and has a highly sophisticated
	type support. It's the recommended format unless you need to use STABS because
	your debugger doesn't support DWARF 2.

	To generate DWARF 2 output, use the <tt>--dwarf</tt> command line argument.
	</ul>


	You need to regenerate the symbol file each time the JIT compiled a new
	method and each time you restart the JIT. You cannot reuse your symbol file
	if you start the JIT a second file, not even if you're running the same
	application with the same input data a second time.

	Regenerating the symbol file is done by calling the JIT's
	<tt>mono_debug_make_symbols ()</tt> function from within your debugger and
	then reloading the symbol files. This function creates a <tt>filename-dwarf.s</tt>
	(or <tt>filename-stabs.s</tt>) assembler input file in the current directory and
	an object file in <tt>/tmp/filename.o</tt> - you need to tell your debugger to
	add this object file as symbol file.

	If you're using the GNU debugger, this is done like this:

	<pre>
	call mono_debug_make_symbols ()
	add-symbol-file /tmp/corlib.o
	add-symbol-file /tmp/mcs.o
	add-symbol-file /tmp/Mono.CSharp.Debugger.o
	</pre>

	You can also write a GDB macro like this:

	<pre>
	define reload
	  call mono_debug_make_symbols ()
	  add-symbol-file /tmp/corlib.o
	  add-symbol-file /tmp/mcs.o
	  add-symbol-file /tmp/Mono.CSharp.Debugger.o
	end
	</pre>

	Then you can just say <tt>reload</tt> to have GDB recreate the symbol file.

	There's also an <a href="jit-debug-sample.html">example debugging session</a> using
	the GNU debugger.

** Using a symbol file which have been created by the Mono C# compiler

	If you compiled your application with Mono's C# compiler (MCS), you can tell it to
	create a symbol file which is then processed and rewritten by the JIT engine.

	To do this, you must give MCS the <tt>-g</tt> option:

	<pre>
	$ mcs -g Foo.cs
	</pre>

	This creates a <tt>Foo-debug.s</tt> assembler input file.

	To use this in the JIT, you must first copy it to the target machine (the machine
	where you want to run the JIT to debug your application) and run it through the
	assembler to produce an object file <tt>Foo-debug.o</tt>. This object file must be
	in the current directory.

	Then start the JIT in your debugger and give it the <tt>--dwarf-plus</tt> command
	line argument.

	Each time you call <tt>mono_debug_make_symbols ()</tt> from withing your debugger,
	the JIT will read this <tt>Foo-debug.o</tt>, fix some machine dependent things like
	memory addresses etc. in it and write it back to disk.

	If you're using the GNU debugger, you'll want to use a macro like this:

	<pre>
	define relocate
	  call mono_debug_make_symbols ()
	  add-symbol-file /tmp/corlib.o
	  add-symbol-file mcs-debug.o
	  add-symbol-file Mono.CSharp.Debugger-debug.o
	end
	</pre>

	If there is no <tt>assembly-debug.o</tt> file, but an <tt>assembly.il</tt> one, the
	JIT will fall back to normal DWARF 2 (in the example above, <tt>corlib.dll</tt> was
	compiled with Microsoft's compiler and the JIT is thus using DWARF to debug it).

	This debugging method only works if you compiled your assembly with MCS, but it'll
	allow you to actually debug your C# source code :-)

	Here's an <a href="jit-debug-sample2.html">example debugging session</a> using
	the GNU debugger.

** Breakpoints and single stepping

	The JIT has a <tt>--debug</tt> command line argument to insert a breakpoint at the
	beginning of this method. It takes a <tt>Namespace.Class:Method</tt> argument which
	is the method. This argument can be given multiple times.

	However, once your application is stopped in GDB you may want to insert a breakpoint
	the next time the JIT compiles a method. There's a global variable
	<tt>mono_debug_insert_breakpoint</tt> which you can modify in your debugger.

	If this variable is set to a non-zero value, the JIT's <tt>arch_compile_method</tt>
	will insert a breakpoint the next time it is called, ie. at the top of the next
	method it compiles. If this value has a positive value, it acts as a counter and is
	decremented after inserting the breakpoint - setting it to a negative value will let
	the JIT insert the breakpoint each time it compiles a new method.

	There's also global variable <tt>mono_debug_last_breakpoint_address</tt> which always
	contains the address of the last inserted breakpoint. You may manually override this
	address with a <tt>nop</tt> instruction to delete the breakpoint.

	For instance, I have a GDB macro called <tt>enter</tt> which I use to enter a method
	rather than stepping over it:

	<pre>
	define enter
	set mono_debug_insert_breakpoint = 1
	continue
	set *mono_debug_last_breakpoint_address = 0x90
	relocate
	frame
	</pre>

	Btw. speaking of single stepping - you should use your debuggers <tt>next</tt> command,
	not its <tt>step</tt> command for single stepping unless you compiled the JIT without
	debugging support. The reason for this is that the JIT creates machine code which contains
	calls to JIT methods such as <tt>mono_object_new_wrapper</tt> at places where you don't
	expect them - so unless the JIT is compiled at least without line numbers, your debugger
	will enter such methods if you use <tt>step</tt> rather than <tt>next</tt>.