[Mono-list] Source lines in backtraces ....

Martin Baulig martin@gnome.org
21 May 2002 22:07:23 +0200


Hi guys,

after a long day of hacking, there's a cool new toy for you :-)

The JIT engine `mono' now displays source lines and IL offset in
stack traces if you enabled the debugging support.

There are two ways to do this:

1.) Use the "dwarf" / "stabs" debugging format.

    This works for every assembly - no matter whether it has been
    compiled with mcs or csc.

    Just start mono like this:

        mono --debug dwarf <yourapp.exe>

    or

        mono --debug stabs <yourapp.exe>

    Here's a real-life example:

=====
mono --debug dwarf mcs.exe --timestamp -o mcs-mono2.exe -g assign.cs attribute.cs driver.cs cs-parser.cs cs-tokenizer.cs tree.cs location.cs cfold.cs class.cs codegen.cs const.cs constant.cs decl.cs delegate.cs enum.cs ecore.cs expression.cs genericparser.cs interface.cs literal.cs modifiers.cs namespace.cs parameter.cs report.cs rootcontext.cs statement.cs support.cs typemanager.cs
Recreating mcs.il from mcs.exe.
Recreating corlib.il from /home/martin/MONO-LINUX/lib/corlib.dll.
[04:162] Loading references
[00:040]    References loaded
Recreating Mono.CSharp.Debugger.il from /home/martin/MONO-LINUX/lib/Mono.CSharp.Debugger.dll.
[00:515] Initializing Core Types
[00:003]    Core Types done
[00:000] Resolving tree
[00:064] Populate tree
[01:268] Emitting code
[14:063]    done
[00:000] Closing types
[00:266] Saved output

(process:31654): ** WARNING **: unhandled exception System.NullReferenceException: "A null value was found where an object
instance was required"
in (unmanaged) System.Reflection.MonoCMethod:InternalInvoke ()
in [0x00003] (at corlib.il:143483) System.Reflection.MonoCMethod:Invoke (System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
in [0x00035] (at Mono.CSharp.Debugger.il:5458) .DieSubProgram:get_abbrev_id (DieCompileUnit,Mono.CSharp.Debugger.ISourceMethod)
in [0x00004] (at Mono.CSharp.Debugger.il:5492) .DieSubProgram:.ctor (DieCompileUnit,Mono.CSharp.Debugger.ISourceMethod)
in [0x00007] (at Mono.CSharp.Debugger.il:9305) Mono.CSharp.Debugger.MonoSymbolWriter:WriteMethod (DieCompileUnit,Mono.CSharp.Debugger.ISourceMethod)
in [0x00031] (at Mono.CSharp.Debugger.il:9398) Mono.CSharp.Debugger.MonoSymbolWriter:WriteSource (Mono.CSharp.Debugger.DwarfFileWriter,Mono.CSharp.Debugger.ISourceFile)
in [0x00032] (at Mono.CSharp.Debugger.il:9557) Mono.CSharp.Debugger.MonoSymbolWriter:CreateDwarfFile (string)
in [0x00031] (at Mono.CSharp.Debugger.il:8792) Mono.CSharp.Debugger.MonoSymbolWriter:Close ()
in [0x00011] (at mcs.il:44681) Mono.CSharp.CodeGen:SaveSymbols ()
in [0x00a84] (at mcs.il:10487) Mono.CSharp.Driver:MainDriver (string[])
in [0x00011] (at mcs.il:9278) Mono.CSharp.Driver:Main (string[])
======

    The *.il files are automatically created for you.

2.) If you compiled your assembly with mcs, you can use the "dwarf2-plus" format to get
    the lines in your C# source code.

    You need to compile your app with the -g option like this:

       mcs -g exception.cs

    Then start the JIT like this:

       mono --debug dwarf-plus <yourapp.exe>

    Here's a real-life example:

=====
[martin@einstein work]$ mcs -g exception.cs
MonoDwarfFileWriter [00:029] Emitting compile units
MonoDwarfFileWriter [00:083] Done
MonoDwarfFileWriter [00:036] Done emitting 34 line numbers
MonoDwarfFileWriter [00:012] Done writing abbrev declarations
MonoDwarfFileWriter [00:020] Done writing 82 reloc entries
RESULT: 0
[martin@einstein work]$ mono --debug dwarf-plus exception.exe
Recreating exception.il from exception.exe.
Recreating corlib.il from /home/martin/MONO-LINUX/lib/corlib.dll.
Void DoTest()
EXCEPTION!
System.ArgumentNullException
Argument cannot be nullSystem.ArgumentNullExceptionin [0x0000d] (at corlib.il:6438) System.Array:Sort (System.Array)
in [0x00006] (at exception.cs:12) MyException.Test:DoTest ()
in (unmanaged) System.Reflection.MonoMethod:InternalInvoke ()
in [0x00004] (at corlib.il:143099) System.Reflection.MonoMethod:Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
in [0x00032] (at exception.cs:33) MyException.MyException:Main (string[])

in [0x0000d] (at corlib.il:6438) System.Array:Sort (System.Array)
in [0x00006] (at exception.cs:12) MyException.Test:DoTest ()
in (unmanaged) System.Reflection.MonoMethod:InternalInvoke ()
in [0x00004] (at corlib.il:143099) System.Reflection.MonoMethod:Invoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
in [0x00032] (at exception.cs:33) MyException.MyException:Main (string[])


(process:32129): ** WARNING **: unhandled exception System.ArgumentNullException: "Argument cannot be null"
in [0x0000d] (at corlib.il:6438) System.Array:Sort (System.Array)
in [0x00006] (at exception.cs:12) MyException.Test:DoTest ()
in [0x00068] (at exception.cs:40) MyException.MyException:Main (string[])

RESULT: -1
====

    The C# source code is here:

====
using System;
using System.Reflection;

namespace MyException
{
	public class Test
	{
		public void DoTest ()
		{
			try {
				Array.Sort (null);
			} catch (ArgumentOutOfRangeException) {
				Console.WriteLine ("CAUGHT!");
			}
		}
	}

	public class MyException
	{
		public static void Main (string[] args)
		{
			Type type = typeof (Test);
			Type[] argtypes = {};

			MethodInfo method = type.GetMethod ("DoTest", argtypes);

			Console.WriteLine (method);

			Test test = new Test ();

			try {
				Object retval = method.Invoke (test, null);
			} catch (Exception e) {
				Console.WriteLine ("EXCEPTION!");
				Console.WriteLine (e);
				Console.WriteLine (e.StackTrace);
			}

			test.DoTest ();
		}
	}
}
====

Btw. in the stack traces, addresses in [ ] are IL offsets and addresses in < > are
machine addresses.

-- 
Martin Baulig
martin@gnome.org