[eglib] Fix compilation on PLATFORM_ANDROID.
[mono-project.git] / data / gdb / mono-gdb.py
blobce34d357f643f46953e45518289e7dc796853b9d
2 # Author: Zoltan Varga (vargaz@gmail.com)
3 # License: MIT/X11
7 # This is a mono support mode for gdb 7.0 and later
8 # Usage:
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
14 import os
16 class StringPrinter:
17 "Print a C# string"
19 def __init__(self, val):
20 self.val = val
22 def to_string(self):
23 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
24 return "null"
26 obj = self.val.cast (gdb.lookup_type ("MonoString").pointer ()).dereference ()
27 len = obj ['length']
28 chars = obj ['chars']
29 i = 0
30 res = ['"']
31 while i < len:
32 val = (chars.cast(gdb.lookup_type ("gint64")) + (i * 2)).cast(gdb.lookup_type ("gunichar2").pointer ()).dereference ()
33 if val >= 256:
34 c = "\u%X".format (val)
35 else:
36 c = chr (val)
37 res.append (c)
38 i = i + 1
39 res.append ('"')
40 return ''.join (res)
42 def stringify_class_name(ns, name):
43 if ns == "System":
44 if name == "Byte":
45 return "byte"
46 if name == "String":
47 return "string"
48 if ns == "":
49 return name
50 else:
51 return "%s.%s".format (ns, name)
53 class ArrayPrinter:
54 "Print a C# array"
56 def __init__(self, val, class_ns, class_name):
57 self.val = val
58 self.class_ns = class_ns
59 self.class_name = class_name
61 def to_string(self):
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))
66 class ObjectPrinter:
67 "Print a C# object"
69 def __init__(self, val):
70 if str(val.type)[-1] == "&":
71 self.val = val.address.cast (gdb.lookup_type ("MonoObject").pointer ())
72 else:
73 self.val = val.cast (gdb.lookup_type ("MonoObject").pointer ())
75 class _iterator:
76 def __init__(self,obj):
77 self.obj = obj
78 self.iter = self.obj.type.fields ().__iter__ ()
79 pass
81 def __iter__(self):
82 return self
84 def next(self):
85 field = self.iter.next ()
86 try:
87 if str(self.obj [field.name].type) == "object":
88 # Avoid recursion
89 return (field.name, self.obj [field.name].cast (gdb.lookup_type ("void").pointer ()))
90 else:
91 return (field.name, self.obj [field.name])
92 except:
93 # Superclass
94 return (field.name, self.obj.cast (gdb.lookup_type ("%s".format (field.name))))
96 def children(self):
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__ ()
101 try:
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__ ()
107 try:
108 gdb_type = gdb.lookup_type ("struct %s_%s".format (class_ns.replace (".", "_"), class_name))
109 return self._iterator(obj.cast (gdb_type))
110 except:
111 return {}.__iter__ ()
112 except:
113 print (sys.exc_info ()[0])
114 print (sys.exc_info ()[1])
115 return {}.__iter__ ()
117 def to_string(self):
118 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
119 return "null"
120 try:
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 ()
128 if class_ns != "":
129 try:
130 gdb_type = gdb.lookup_type ("struct %s.%s".format (class_ns, class_name))
131 except:
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)
136 return class_name
137 except:
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):
147 self.val = val
149 def to_string(self):
150 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
151 return "0x0"
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):
163 self.val = val
165 def to_string_inner(self, add_quotes):
166 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
167 return "0x0"
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"]))
172 if add_quotes:
173 return "\"%s\"".format (class_name)
174 else:
175 return 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")))))))
179 def to_string(self):
180 try:
181 return self.to_string_inner (True)
182 except:
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):
191 self.val = val
193 def to_string(self):
194 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
195 return "0x0"
196 inst = self.val.dereference ()
197 inst_len = inst ["type_argc"]
198 inst_args = inst ["type_argv"]
199 inst_str = ""
200 for i in range(0, inst_len):
201 print (inst_args)
202 type_printer = MonoTypePrinter (inst_args [i])
203 if i > 0:
204 inst_str = inst_str + ", "
205 inst_str = inst_str + type_printer.to_string ()
206 return inst_str
208 class MonoGenericClassPrinter:
209 "Print a MonoGenericClass structure"
211 def __init__(self, val):
212 self.val = 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"]
218 class_inst_str = ""
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"]
222 method_inst_str = ""
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)
227 def to_string(self):
228 try:
229 return self.to_string_inner ()
230 except:
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):
239 self.val = val
241 def to_string_inner(self, csharp):
242 try:
243 t = self.val.dereference ()
245 kind = str (t ["type"]).replace ("MONO_TYPE_", "").lower ()
246 info = ""
248 if kind == "class":
249 p = MonoClassPrinter(t ["data"]["klass"])
250 info = p.to_string ()
251 elif kind == "genericinst":
252 info = str(t ["data"]["generic_class"])
254 if info != "":
255 return "{%s, %s}".format (kind, info)
256 else:
257 return "{%s}".format (kind)
258 except:
259 #print (sys.exc_info ()[0])
260 #print (sys.exc_info ()[1])
261 return str(self.val.cast (gdb.lookup_type ("gpointer")))
263 def to_string(self):
264 return self.to_string_inner (False)
266 class MonoMethodRgctxPrinter:
267 "Print a MonoMethodRgctx structure"
269 def __init__(self, val):
270 self.val = val
272 def to_string(self):
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"]
279 inst_str = ""
280 for i in range(0, inst_len):
281 print (inst_args)
282 type_printer = MonoTypePrinter (inst_args [i])
283 if i > 0:
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):
292 self.val = val
294 def to_string(self):
295 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
296 return "0x0"
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):
304 t = str (val.type)
305 if t == "object":
306 return ObjectPrinter (val)
307 if t[0:5] == "class" and t[-1] == "&":
308 return ObjectPrinter (val)
309 if t == "string":
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)
327 return None
329 def register_csharp_printers(obj):
330 "Register C# pretty-printers with objfile Obj."
332 if obj == None:
333 obj = gdb
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):
339 def __init__ (self):
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())
348 XdbCommand ()
350 gdb.execute ("set environment MONO_XDEBUG gdb")
352 print ("Mono support loaded.")