2 # Author: Zoltan Varga (vargaz@gmail.com)
7 # This is a mono support mode for gdb 7.0 and later
9 # - copy/symlink this file to the directory where the mono executable lives.
10 # - run mono under gdb, or attach to a mono process started with --debug=gdb using gdb.
18 def __init__(self
, val
):
22 if int(self
.val
.cast (gdb
.lookup_type ("guint64"))) == 0:
25 obj
= self
.val
.cast (gdb
.lookup_type ("MonoString").pointer ()).dereference ()
31 val
= (chars
.cast(gdb
.lookup_type ("gint64")) + (i
* 2)).cast(gdb
.lookup_type ("gunichar2").pointer ()).dereference ()
41 def stringify_class_name(ns
, name
):
50 return "%s.%s" % (ns
, name
)
55 def __init__(self
, val
, class_ns
, class_name
):
57 self
.class_ns
= class_ns
58 self
.class_name
= class_name
61 obj
= self
.val
.cast (gdb
.lookup_type ("MonoArray").pointer ()).dereference ()
62 length
= obj
['max_length']
63 return "%s [%d]" % (stringify_class_name (self
.class_ns
, self
.class_name
[0:len(self
.class_name
) - 2]), int(length
))
68 def __init__(self
, val
):
69 if str(val
.type)[-1] == "&":
70 self
.val
= val
.address
.cast (gdb
.lookup_type ("MonoObject").pointer ())
72 self
.val
= val
.cast (gdb
.lookup_type ("MonoObject").pointer ())
75 def __init__(self
,obj
):
77 self
.iter = self
.obj
.type.fields ().__iter
__ ()
84 field
= self
.iter.next ()
86 if str(self
.obj
[field
.name
].type) == "object":
88 return (field
.name
, self
.obj
[field
.name
].cast (gdb
.lookup_type ("void").pointer ()))
90 return (field
.name
, self
.obj
[field
.name
])
93 return (field
.name
, self
.obj
.cast (gdb
.lookup_type ("%s" % (field
.name
))))
96 # FIXME: It would be easier if gdb.Value would support iteration itself
97 # It would also be better if we could return None
98 if int(self
.val
.cast (gdb
.lookup_type ("guint64"))) == 0:
101 obj
= self
.val
.dereference ()
102 class_ns
= obj
['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
103 class_name
= obj
['vtable'].dereference ()['klass'].dereference ()['name'].string ()
104 if class_name
[-2:len(class_name
)] == "[]":
105 return {}.__iter
__ ()
106 gdb_type
= gdb
.lookup_type ("struct %s_%s" % (class_ns
.replace (".", "_"), class_name
))
107 return self
._iterator
(obj
.cast (gdb_type
))
109 print sys
.exc_info ()[0]
110 print sys
.exc_info ()[1]
111 return {}.__iter
__ ()
114 if int(self
.val
.cast (gdb
.lookup_type ("guint64"))) == 0:
117 obj
= self
.val
.dereference ()
118 class_ns
= obj
['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
119 class_name
= obj
['vtable'].dereference ()['klass'].dereference ()['name'].string ()
120 if class_ns
== "System" and class_name
== "String":
121 return StringPrinter (self
.val
).to_string ()
122 if class_name
[-2:len(class_name
)] == "[]":
123 return ArrayPrinter (self
.val
,class_ns
,class_name
).to_string ()
126 gdb_type
= gdb
.lookup_type ("struct %s.%s" % (class_ns
, class_name
))
128 # Maybe there is no debug info for that type
129 return "%s.%s" % (class_ns
, class_name
)
130 #return obj.cast (gdb_type)
131 return "%s.%s" % (class_ns
, class_name
)
134 print sys
.exc_info ()[0]
135 print sys
.exc_info ()[1]
136 # FIXME: This can happen because we don't have liveness information
137 return self
.val
.cast (gdb
.lookup_type ("guint64"))
139 class MonoMethodPrinter
:
140 "Print a MonoMethod structure"
142 def __init__(self
, val
):
146 if int(self
.val
.cast (gdb
.lookup_type ("guint64"))) == 0:
148 val
= self
.val
.dereference ()
149 klass
= val
["klass"].dereference ()
150 class_name
= stringify_class_name (klass
["name_space"].string (), klass
["name"].string ())
151 return "\"%s:%s ()\"" % (class_name
, val
["name"].string ())
152 # This returns more info but requires calling into the inferior
153 #return "\"%s\"" % (gdb.parse_and_eval ("mono_method_full_name (%s, 1)" % (str (int (self.val.cast (gdb.lookup_type ("guint64")))))).string ())
155 class MonoClassPrinter
:
156 "Print a MonoClass structure"
158 def __init__(self
, val
):
162 if int(self
.val
.cast (gdb
.lookup_type ("guint64"))) == 0:
164 klass
= self
.val
.dereference ()
165 class_name
= stringify_class_name (klass
["name_space"].string (), klass
["name"].string ())
166 return "\"%s\"" % (class_name
)
167 # This returns more info but requires calling into the inferior
168 #return "\"%s\"" % (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*)%s)->byval_arg)" % (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
170 def lookup_pretty_printer(val
):
173 return ObjectPrinter (val
)
174 if t
[0:5] == "class" and t
[-1] == "&":
175 return ObjectPrinter (val
)
177 return StringPrinter (val
)
178 if t
== "MonoMethod *":
179 return MonoMethodPrinter (val
)
180 if t
== "MonoClass *":
181 return MonoClassPrinter (val
)
184 def register_csharp_printers(obj
):
185 "Register C# pretty-printers with objfile Obj."
190 obj
.pretty_printers
.append (lookup_pretty_printer
)
192 # This command will flush the debugging info collected by the runtime
193 class XdbCommand (gdb
.Command
):
195 super (XdbCommand
, self
).__init
__ ("xdb", gdb
.COMMAND_NONE
,
196 gdb
.COMPLETE_COMMAND
)
198 def invoke(self
, arg
, from_tty
):
199 gdb
.execute ("call mono_xdebug_flush ()")
201 register_csharp_printers (gdb
.current_objfile())
205 gdb
.execute ("set environment MONO_XDEBUG gdb")
207 print "Mono support loaded."