* 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 corlib.dll 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 monodis utility:
	monodis /home/export/martin/MONO-LINUX/lib/corlib.dll > corlib.il
monodis /home/export/martin/MONO-LINUX/lib/System.dll > System.il
monodis /home/export/martin/MONO-LINUX/bin/mcs.exe > mcs.il
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: 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 mono_debug_make_symbols () function from within your debugger and then reloading the symbol files. This function creates a filename-dwarf.s (or filename-stabs.s) assembler input file in the current directory and an object file in /tmp/filename.o - 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:
	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
	
You can also write a GDB macro like this:
	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
	
Then you can just say reload to have GDB recreate the symbol file. There's also an example debugging session 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 -g option:
	$ mcs -g Foo.cs
	
This creates a Foo-debug.s 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 Foo-debug.o. This object file must be in the current directory. Then start the JIT in your debugger and give it the --dwarf-plus command line argument. Each time you call mono_debug_make_symbols () from withing your debugger, the JIT will read this Foo-debug.o, 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:
	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
	
If there is no assembly-debug.o file, but an assembly.il one, the JIT will fall back to normal DWARF 2 (in the example above, corlib.dll 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 example debugging session using the GNU debugger. ** Breakpoints and single stepping The JIT has a --debug command line argument to insert a breakpoint at the beginning of this method. It takes a Namespace.Class:Method 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 mono_debug_insert_breakpoint which you can modify in your debugger. If this variable is set to a non-zero value, the JIT's arch_compile_method 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 mono_debug_last_breakpoint_address which always contains the address of the last inserted breakpoint. You may manually override this address with a nop instruction to delete the breakpoint. For instance, I have a GDB macro called enter which I use to enter a method rather than stepping over it:
	define enter
	set mono_debug_insert_breakpoint = 1
	continue
	set *mono_debug_last_breakpoint_address = 0x90
	relocate
	frame
	
Btw. speaking of single stepping - you should use your debuggers next command, not its step 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 mono_object_new_wrapper 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 step rather than next.