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__ ()
107 gdb_type = gdb.lookup_type ("struct %s_%s" % (class_ns.replace (".", "_"), class_name))
108 return self._iterator(obj.cast (gdb_type))
110 return {}.__iter__ ()
112 print sys.exc_info ()[0]
113 print sys.exc_info ()[1]
114 return {}.__iter__ ()
117 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
120 obj = self.val.dereference ()
121 class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
122 class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
123 if class_ns == "System" and class_name == "String":
124 return StringPrinter (self.val).to_string ()
125 if class_name [-2:len(class_name)] == "[]":
126 return ArrayPrinter (self.val,class_ns,class_name).to_string ()
129 gdb_type = gdb.lookup_type ("struct %s.%s" % (class_ns, class_name))
131 # Maybe there is no debug info for that type
132 return "%s.%s" % (class_ns, class_name)
133 #return obj.cast (gdb_type)
134 return "%s.%s" % (class_ns, class_name)
137 print sys.exc_info ()[0]
138 print sys.exc_info ()[1]
139 # FIXME: This can happen because we don't have liveness information
140 return self.val.cast (gdb.lookup_type ("guint64"))
142 class MonoMethodPrinter:
143 "Print a MonoMethod structure"
145 def __init__(self, val):
149 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
151 val = self.val.dereference ()
152 klass = val ["klass"].dereference ()
153 class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
154 return "\"%s:%s ()\"" % (class_name, val ["name"].string ())
155 # This returns more info but requires calling into the inferior
156 #return "\"%s\"" % (gdb.parse_and_eval ("mono_method_full_name (%s, 1)" % (str (int (self.val.cast (gdb.lookup_type ("guint64")))))).string ())
158 class MonoClassPrinter:
159 "Print a MonoClass structure"
161 def __init__(self, val):
164 def to_string_inner(self, add_quotes):
165 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
167 klass = self.val.dereference ()
168 class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
169 if klass ["generic_class"].cast (gdb.lookup_type ("guint64")) != 0:
170 class_name = "%s<%s>" % (class_name, str (klass ["generic_class"]["context"]["class_inst"]))
172 return "\"%s\"" % (class_name)
175 # This returns more info but requires calling into the inferior
176 #return "\"%s\"" % (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*)%s)->byval_arg)" % (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
180 return self.to_string_inner (True)
182 #print sys.exc_info ()[0]
183 #print sys.exc_info ()[1]
184 return str(self.val.cast (gdb.lookup_type ("gpointer")))
186 class MonoGenericInstPrinter:
187 "Print a MonoGenericInst structure"
189 def __init__(self, val):
193 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
195 inst = self.val.dereference ()
196 inst_len = inst ["type_argc"]
197 inst_args = inst ["type_argv"]
199 for i in range(0, inst_len):
201 type_printer = MonoTypePrinter (inst_args [i])
203 inst_str = inst_str + ", "
204 inst_str = inst_str + type_printer.to_string ()
207 class MonoGenericClassPrinter:
208 "Print a MonoGenericClass structure"
210 def __init__(self, val):
213 def to_string_inner(self):
214 gclass = self.val.dereference ()
215 container_str = str(gclass ["container_class"])
216 class_inst = gclass ["context"]["class_inst"]
218 if int(class_inst.cast (gdb.lookup_type ("guint64"))) != 0:
219 class_inst_str = str(class_inst)
220 method_inst = gclass ["context"]["method_inst"]
222 if int(method_inst.cast (gdb.lookup_type ("guint64"))) != 0:
223 method_inst_str = str(method_inst)
224 return "%s, [%s], [%s]>" % (container_str, class_inst_str, method_inst_str)
228 return self.to_string_inner ()
230 #print sys.exc_info ()[0]
231 #print sys.exc_info ()[1]
232 return str(self.val.cast (gdb.lookup_type ("gpointer")))
234 class MonoTypePrinter:
235 "Print a MonoType structure"
237 def __init__(self, val):
240 def to_string_inner(self, csharp):
242 t = self.val.dereference ()
244 kind = str (t ["type"]).replace ("MONO_TYPE_", "").lower ()
248 p = MonoClassPrinter(t ["data"]["klass"])
249 info = p.to_string ()
250 elif kind == "genericinst":
251 info = str(t ["data"]["generic_class"])
254 return "{%s, %s}" % (kind, info)
256 return "{%s}" % (kind)
258 #print sys.exc_info ()[0]
259 #print sys.exc_info ()[1]
260 return str(self.val.cast (gdb.lookup_type ("gpointer")))
263 return self.to_string_inner (False)
265 class MonoMethodRgctxPrinter:
266 "Print a MonoMethodRgctx structure"
268 def __init__(self, val):
272 rgctx = self.val.dereference ()
273 klass = rgctx ["class_vtable"].dereference () ["klass"]
274 klass_printer = MonoClassPrinter (klass)
275 inst = rgctx ["method_inst"].dereference ()
276 inst_len = inst ["type_argc"]
277 inst_args = inst ["type_argv"]
279 for i in range(0, inst_len):
281 type_printer = MonoTypePrinter (inst_args [i])
283 inst_str = inst_str + ", "
284 inst_str = inst_str + type_printer.to_string ()
285 return "MRGCTX[%s, [%s]]" % (klass_printer.to_string(), inst_str)
287 class MonoVTablePrinter:
288 "Print a MonoVTable structure"
290 def __init__(self, val):
294 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
296 vtable = self.val.dereference ()
297 klass = vtable ["klass"]
298 klass_printer = MonoClassPrinter (klass)
300 return "vtable(%s)" % (klass_printer.to_string ())
302 def lookup_pretty_printer(val):
305 return ObjectPrinter (val)
306 if t[0:5] == "class" and t[-1] == "&":
307 return ObjectPrinter (val)
309 return StringPrinter (val)
310 if t == "MonoString *":
311 return StringPrinter (val)
312 if t == "MonoMethod *":
313 return MonoMethodPrinter (val)
314 if t == "MonoClass *":
315 return MonoClassPrinter (val)
316 if t == "MonoType *":
317 return MonoTypePrinter (val)
318 if t == "MonoGenericInst *":
319 return MonoGenericInstPrinter (val)
320 if t == "MonoGenericClass *":
321 return MonoGenericClassPrinter (val)
322 if t == "MonoMethodRuntimeGenericContext *":
323 return MonoMethodRgctxPrinter (val)
324 if t == "MonoVTable *":
325 return MonoVTablePrinter (val)
328 def register_csharp_printers(obj):
329 "Register C# pretty-printers with objfile Obj."
334 obj.pretty_printers.append (lookup_pretty_printer)
336 # This command will flush the debugging info collected by the runtime
337 class XdbCommand (gdb.Command):
339 super (XdbCommand, self).__init__ ("xdb", gdb.COMMAND_NONE,
340 gdb.COMPLETE_COMMAND)
342 def invoke(self, arg, from_tty):
343 gdb.execute ("call mono_xdebug_flush ()")
345 register_csharp_printers (gdb.current_objfile())
349 gdb.execute ("set environment MONO_XDEBUG gdb")
351 print "Mono support loaded."