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 ()
34 c
= "\u%X".format (val
)
42 def stringify_class_name(ns
, name
):
51 return "%s.%s".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 "%s [%d]".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 ("%s".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 %s_%s".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 %s.%s".format (class_ns
, class_name
))
132 # Maybe there is no debug info for that type
133 return "%s.%s".format (class_ns
, class_name
)
134 #return obj.cast (gdb_type)
135 return "%s.%s".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 "\"%s:%s ()\"".format (class_name
, val
["name"].string ())
156 # This returns more info but requires calling into the inferior
157 #return "\"%s\"".format (gdb.parse_and_eval ("mono_method_full_name (%s, 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 ())
170 if klass
["generic_class"].cast (gdb
.lookup_type ("guint64")) != 0:
171 class_name
= "%s<%s>".format (class_name
, str (klass
["generic_class"]["context"]["class_inst"]))
173 return "\"%s\"".format (class_name
)
176 # This returns more info but requires calling into the inferior
177 #return "\"%s\"".format (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*)%s)->byval_arg)".format (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
181 return self
.to_string_inner (True)
183 #print (sys.exc_info ()[0])
184 #print (sys.exc_info ()[1])
185 return str(self
.val
.cast (gdb
.lookup_type ("gpointer")))
187 class MonoGenericInstPrinter
:
188 "Print a MonoGenericInst structure"
190 def __init__(self
, val
):
194 if int(self
.val
.cast (gdb
.lookup_type ("guint64"))) == 0:
196 inst
= self
.val
.dereference ()
197 inst_len
= inst
["type_argc"]
198 inst_args
= inst
["type_argv"]
200 for i
in range(0, inst_len
):
202 type_printer
= MonoTypePrinter (inst_args
[i
])
204 inst_str
= inst_str
+ ", "
205 inst_str
= inst_str
+ type_printer
.to_string ()
208 class MonoGenericClassPrinter
:
209 "Print a MonoGenericClass structure"
211 def __init__(self
, val
):
214 def to_string_inner(self
):
215 gclass
= self
.val
.dereference ()
216 container_str
= str(gclass
["container_class"])
217 class_inst
= gclass
["context"]["class_inst"]
219 if int(class_inst
.cast (gdb
.lookup_type ("guint64"))) != 0:
220 class_inst_str
= str(class_inst
)
221 method_inst
= gclass
["context"]["method_inst"]
223 if int(method_inst
.cast (gdb
.lookup_type ("guint64"))) != 0:
224 method_inst_str
= str(method_inst
)
225 return "%s, [%s], [%s]>".format (container_str
, class_inst_str
, method_inst_str
)
229 return self
.to_string_inner ()
231 #print (sys.exc_info ()[0])
232 #print (sys.exc_info ()[1])
233 return str(self
.val
.cast (gdb
.lookup_type ("gpointer")))
235 class MonoTypePrinter
:
236 "Print a MonoType structure"
238 def __init__(self
, val
):
241 def to_string_inner(self
, csharp
):
243 t
= self
.val
.dereference ()
245 kind
= str (t
["type"]).replace ("MONO_TYPE_", "").lower ()
249 p
= MonoClassPrinter(t
["data"]["klass"])
250 info
= p
.to_string ()
251 elif kind
== "genericinst":
252 info
= str(t
["data"]["generic_class"])
255 return "{%s, %s}".format (kind
, info
)
257 return "{%s}".format (kind
)
259 #print (sys.exc_info ()[0])
260 #print (sys.exc_info ()[1])
261 return str(self
.val
.cast (gdb
.lookup_type ("gpointer")))
264 return self
.to_string_inner (False)
266 class MonoMethodRgctxPrinter
:
267 "Print a MonoMethodRgctx structure"
269 def __init__(self
, val
):
273 rgctx
= self
.val
.dereference ()
274 klass
= rgctx
["class_vtable"].dereference () ["klass"]
275 klass_printer
= MonoClassPrinter (klass
)
276 inst
= rgctx
["method_inst"].dereference ()
277 inst_len
= inst
["type_argc"]
278 inst_args
= inst
["type_argv"]
280 for i
in range(0, inst_len
):
282 type_printer
= MonoTypePrinter (inst_args
[i
])
284 inst_str
= inst_str
+ ", "
285 inst_str
= inst_str
+ type_printer
.to_string ()
286 return "MRGCTX[%s, [%s]]".format (klass_printer
.to_string(), inst_str
)
288 class MonoVTablePrinter
:
289 "Print a MonoVTable structure"
291 def __init__(self
, val
):
295 if int(self
.val
.cast (gdb
.lookup_type ("guint64"))) == 0:
297 vtable
= self
.val
.dereference ()
298 klass
= vtable
["klass"]
299 klass_printer
= MonoClassPrinter (klass
)
301 return "vtable(%s)".format (klass_printer
.to_string ())
303 def lookup_pretty_printer(val
):
306 return ObjectPrinter (val
)
307 if t
[0:5] == "class" and t
[-1] == "&":
308 return ObjectPrinter (val
)
310 return StringPrinter (val
)
311 if t
== "MonoString *":
312 return StringPrinter (val
)
313 if t
== "MonoMethod *":
314 return MonoMethodPrinter (val
)
315 if t
== "MonoClass *":
316 return MonoClassPrinter (val
)
317 if t
== "MonoType *":
318 return MonoTypePrinter (val
)
319 if t
== "MonoGenericInst *":
320 return MonoGenericInstPrinter (val
)
321 if t
== "MonoGenericClass *":
322 return MonoGenericClassPrinter (val
)
323 if t
== "MonoMethodRuntimeGenericContext *":
324 return MonoMethodRgctxPrinter (val
)
325 if t
== "MonoVTable *":
326 return MonoVTablePrinter (val
)
329 def register_csharp_printers(obj
):
330 "Register C# pretty-printers with objfile Obj."
335 obj
.pretty_printers
.append (lookup_pretty_printer
)
337 # This command will flush the debugging info collected by the runtime
338 class XdbCommand (gdb
.Command
):
340 super (XdbCommand
, self
).__init
__ ("xdb", gdb
.COMMAND_NONE
,
341 gdb
.COMPLETE_COMMAND
)
343 def invoke(self
, arg
, from_tty
):
344 gdb
.execute ("call mono_xdebug_flush ()")
346 register_csharp_printers (gdb
.current_objfile())
350 gdb
.execute ("set environment MONO_XDEBUG gdb")
352 print ("Mono support loaded.")