diff options
author | Martin Baulig <martin@novell.com> | 2002-03-29 12:56:40 +0300 |
---|---|---|
committer | Martin Baulig <martin@novell.com> | 2002-03-29 12:56:40 +0300 |
commit | e09cc97a750466f4497eba6aa89c49d26a11a922 (patch) | |
tree | 3d2777fbdf2fb16676d25e13017339b0a7063ac6 /web/jit-debug | |
parent | b1a7c0e3f741e868d902c6d07cf27f7cee1da82f (diff) |
2002-03-29 Martin Baulig <martin@gnome.org>
* doc/jit-debug, docs/jit-debug-sample, docs/jit-debug-sample2:
New files, added documentation for the debugging code.
* doc/web/commands: Added the debugging pages.
* docs/jit-debug: Removed, this is now on the web site.
svn path=/trunk/mono/; revision=3493
Diffstat (limited to 'web/jit-debug')
-rw-r--r-- | web/jit-debug | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/web/jit-debug b/web/jit-debug new file mode 100644 index 00000000000..867738101ae --- /dev/null +++ b/web/jit-debug @@ -0,0 +1,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>. + + + |