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.
13 from __future__ import print_function
19 def __init__(self, val):
23 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
26 obj = self.val.cast (gdb.lookup_type ("MonoString").pointer ()).dereference ()
32 val = (chars.cast(gdb.lookup_type ("gint64")) + (i * 2)).cast(gdb.lookup_type ("gunichar2").pointer ()).dereference ()
42 def stringify_class_name(ns, name):
51 return "{}.{}".format (ns, name)
56 def __init__(self, val, class_ns, class_name):
58 self.class_ns = class_ns
59 self.class_name = class_name
62 obj = self.val.cast (gdb.lookup_type ("MonoArray").pointer ()).dereference ()
63 length = obj ['max_length']
64 return "{} [{}]".format (stringify_class_name (self.class_ns, self.class_name [0:len(self.class_name) - 2]), int(length))
69 def __init__(self, val):
70 if str(val.type)[-1] == "&":
71 self.val = val.address.cast (gdb.lookup_type ("MonoObject").pointer ())
73 self.val = val.cast (gdb.lookup_type ("MonoObject").pointer ())
76 def __init__(self,obj):
78 self.iter = self.obj.type.fields ().__iter__ ()
85 field = self.iter.next ()
87 if str(self.obj [field.name].type) == "object":
89 return (field.name, self.obj [field.name].cast (gdb.lookup_type ("void").pointer ()))
91 return (field.name, self.obj [field.name])
94 return (field.name, self.obj.cast (gdb.lookup_type ("{}".format (field.name))))
97 # FIXME: It would be easier if gdb.Value would support iteration itself
98 # It would also be better if we could return None
99 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
100 return {}.__iter__ ()
102 obj = self.val.dereference ()
103 class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
104 class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
105 if class_name [-2:len(class_name)] == "[]":
106 return {}.__iter__ ()
108 gdb_type = gdb.lookup_type ("struct {}_{}".format (class_ns.replace (".", "_"), class_name))
109 return self._iterator(obj.cast (gdb_type))
111 return {}.__iter__ ()
113 print (sys.exc_info ()[0])
114 print (sys.exc_info ()[1])
115 return {}.__iter__ ()
118 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
121 obj = self.val.dereference ()
122 class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
123 class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
124 if class_ns == "System" and class_name == "String":
125 return StringPrinter (self.val).to_string ()
126 if class_name [-2:len(class_name)] == "[]":
127 return ArrayPrinter (self.val,class_ns,class_name).to_string ()
130 gdb_type = gdb.lookup_type ("struct {}.{}".format (class_ns, class_name))
132 # Maybe there is no debug info for that type
133 return "{}.{}".format (class_ns, class_name)
134 #return obj.cast (gdb_type)
135 return "{}.{}".format (class_ns, class_name)
138 print (sys.exc_info ()[0])
139 print (sys.exc_info ()[1])
140 # FIXME: This can happen because we don't have liveness information
141 return self.val.cast (gdb.lookup_type ("guint64"))
143 class MonoMethodPrinter:
144 "Print a MonoMethod structure"
146 def __init__(self, val):
150 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
152 val = self.val.dereference ()
153 klass = val ["klass"].dereference ()
154 class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
155 return "\"{}:{} ()\"".format (class_name, val ["name"].string ())
156 # This returns more info but requires calling into the inferior
157 #return "\"{}\"".format (gdb.parse_and_eval ("mono_method_full_name ({}, 1)".format (str (int (self.val.cast (gdb.lookup_type ("guint64")))))).string ())
159 class MonoClassPrinter:
160 "Print a MonoClass structure"
162 def __init__(self, val):
165 def to_string_inner(self, add_quotes):
166 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
168 klass = self.val.dereference ()
169 class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
171 return "\"{}\"".format (class_name)
174 # This returns more info but requires calling into the inferior
175 #return "\"{}\"".format (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*){})->byval_arg)".format (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
179 return self.to_string_inner (True)
181 #print (sys.exc_info ()[0])
182 #print (sys.exc_info ()[1])
183 return str(self.val.cast (gdb.lookup_type ("gpointer")))
185 class MonoGenericInstPrinter:
186 "Print a MonoGenericInst structure"
188 def __init__(self, val):
192 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
194 inst = self.val.dereference ()
195 inst_len = inst ["type_argc"]
196 inst_args = inst ["type_argv"]
198 for i in range(0, inst_len):
200 type_printer = MonoTypePrinter (inst_args [i])
202 inst_str = inst_str + ", "
203 inst_str = inst_str + type_printer.to_string ()
206 class MonoGenericClassPrinter:
207 "Print a MonoGenericClass structure"
209 def __init__(self, val):
212 def to_string_inner(self):
213 gclass = self.val.dereference ()
214 container_str = str(gclass ["container_class"])
215 class_inst = gclass ["context"]["class_inst"]
217 if int(class_inst.cast (gdb.lookup_type ("guint64"))) != 0:
218 class_inst_str = str(class_inst)
219 method_inst = gclass ["context"]["method_inst"]
221 if int(method_inst.cast (gdb.lookup_type ("guint64"))) != 0:
222 method_inst_str = str(method_inst)
223 return "{}, [{}], [{}]>".format (container_str, class_inst_str, method_inst_str)
227 return self.to_string_inner ()
229 #print (sys.exc_info ()[0])
230 #print (sys.exc_info ()[1])
231 return str(self.val.cast (gdb.lookup_type ("gpointer")))
233 class MonoTypePrinter:
234 "Print a MonoType structure"
236 def __init__(self, val):
239 def to_string_inner(self, csharp):
241 t = self.val.referenced_value ()
243 kind = str (t ["type"]).replace ("MONO_TYPE_", "").lower ()
247 p = MonoClassPrinter(t ["data"]["klass"])
248 info = p.to_string ()
249 elif kind == "genericinst":
250 info = str(t ["data"]["generic_class"])
253 return "{{{}, {}}}".format (kind, info)
255 return "{{{}}}".format (kind)
257 #print (sys.exc_info ()[0])
258 #print (sys.exc_info ()[1])
259 return str(self.val.cast (gdb.lookup_type ("gpointer")))
262 return self.to_string_inner (False)
264 class MonoMethodRgctxPrinter:
265 "Print a MonoMethodRgctx structure"
267 def __init__(self, val):
271 rgctx = self.val.dereference ()
272 klass = rgctx ["class_vtable"].dereference () ["klass"]
273 klass_printer = MonoClassPrinter (klass)
274 inst = rgctx ["method_inst"].dereference ()
275 inst_len = inst ["type_argc"]
276 inst_args = inst ["type_argv"]
278 for i in range(0, inst_len):
280 type_printer = MonoTypePrinter (inst_args [i])
282 inst_str = inst_str + ", "
283 inst_str = inst_str + type_printer.to_string ()
284 return "MRGCTX[{}, [{}]]".format (klass_printer.to_string(), inst_str)
286 class MonoVTablePrinter:
287 "Print a MonoVTable structure"
289 def __init__(self, val):
293 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
295 vtable = self.val.dereference ()
296 klass = vtable ["klass"]
297 klass_printer = MonoClassPrinter (klass)
299 return "vtable({})".format (klass_printer.to_string ())
301 def lookup_pretty_printer(val):
304 return ObjectPrinter (val)
305 if t[0:5] == "class" and t[-1] == "&":
306 return ObjectPrinter (val)
308 return StringPrinter (val)
309 if t == "MonoString *":
310 return StringPrinter (val)
311 if t == "MonoMethod *":
312 return MonoMethodPrinter (val)
313 if t == "MonoClass *":
314 return MonoClassPrinter (val)
315 if t == "MonoType *":
316 return MonoTypePrinter (val)
317 if t == "MonoGenericInst *":
318 return MonoGenericInstPrinter (val)
319 if t == "MonoGenericClass *":
320 return MonoGenericClassPrinter (val)
321 if t == "MonoMethodRuntimeGenericContext *":
322 return MonoMethodRgctxPrinter (val)
323 if t == "MonoVTable *":
324 return MonoVTablePrinter (val)
327 def register_csharp_printers(obj):
328 "Register C# pretty-printers with objfile Obj."
333 obj.pretty_printers.append (lookup_pretty_printer)
335 # This command will flush the debugging info collected by the runtime
336 class XdbCommand (gdb.Command):
338 super (XdbCommand, self).__init__ ("xdb", gdb.COMMAND_NONE,
339 gdb.COMPLETE_COMMAND)
341 def invoke(self, arg, from_tty):
342 gdb.execute ("call mono_xdebug_flush ()")
344 register_csharp_printers (gdb.current_objfile())
348 gdb.execute ("set environment MONO_XDEBUG gdb")
350 print ("Mono support loaded.")