Fixed.
[mono.git] / data / gdb / mono-gdb.py
1 #
2 # Author: Zoltan Varga (vargaz@gmail.com)
3 # License: MIT/X11
4 #
5
6 #
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.
11 #
12
13 import os
14
15 class StringPrinter:
16     "Print a C# string"
17
18     def __init__(self, val):
19         self.val = val
20
21     def to_string(self):
22         if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
23             return "null"
24
25         obj = self.val.cast (gdb.lookup_type ("MonoString").pointer ()).dereference ()
26         len = obj ['length']
27         chars = obj ['chars']
28         i = 0
29         res = ['"']
30         while i < len:
31             val = (chars.cast(gdb.lookup_type ("gint64")) + (i * 2)).cast(gdb.lookup_type ("gunichar2").pointer ()).dereference ()
32             if val >= 256:
33                 c = "\u%X" % val
34             else:
35                 c = chr (val)
36             res.append (c)
37             i = i + 1
38         res.append ('"')
39         return ''.join (res)
40
41 def stringify_class_name(ns, name):
42     if ns == "System":
43         if name == "Byte":
44             return "byte"
45         if name == "String":
46             return "string"
47     if ns == "":
48         return name
49     else:
50         return "%s.%s" % (ns, name)
51
52 class ArrayPrinter:
53     "Print a C# array"
54
55     def __init__(self, val, class_ns, class_name):
56         self.val = val
57         self.class_ns = class_ns
58         self.class_name = class_name
59
60     def to_string(self):
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))
64         
65 class ObjectPrinter:
66     "Print a C# object"
67
68     def __init__(self, val):
69         if str(val.type)[-1] == "&":
70             self.val = val.address.cast (gdb.lookup_type ("MonoObject").pointer ())
71         else:
72             self.val = val.cast (gdb.lookup_type ("MonoObject").pointer ())
73
74     class _iterator:
75         def __init__(self,obj):
76             self.obj = obj
77             self.iter = self.obj.type.fields ().__iter__ ()
78             pass
79
80         def __iter__(self):
81             return self
82
83         def next(self):
84             field = self.iter.next ()
85             try:
86                 if str(self.obj [field.name].type) == "object":
87                     # Avoid recursion
88                     return (field.name, self.obj [field.name].cast (gdb.lookup_type ("void").pointer ()))
89                 else:
90                     return (field.name, self.obj [field.name])
91             except:
92                 # Superclass
93                 return (field.name, self.obj.cast (gdb.lookup_type ("%s" % (field.name))))
94
95     def children(self):
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:
99             return {}.__iter__ ()
100         try:
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))
108         except:
109             print sys.exc_info ()[0]
110             print sys.exc_info ()[1]
111             return {}.__iter__ ()
112
113     def to_string(self):
114         if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
115             return "null"
116         try:
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 ()
124             if class_ns != "":
125                 try:
126                     gdb_type = gdb.lookup_type ("struct %s.%s" % (class_ns, class_name))
127                 except:
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)
132             return class_name
133         except:
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"))
138         
139 class MonoMethodPrinter:
140     "Print a MonoMethod structure"
141
142     def __init__(self, val):
143         self.val = val
144
145     def to_string(self):
146         if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
147             return "0x0"
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 ())
154
155 class MonoClassPrinter:
156     "Print a MonoClass structure"
157
158     def __init__(self, val):
159         self.val = val
160
161     def to_string_inner(self, add_quotes):
162         if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
163             return "0x0"
164         klass = self.val.dereference ()
165         class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
166         if add_quotes:
167             return "\"%s\"" % (class_name)
168         else:
169             return class_name
170         # This returns more info but requires calling into the inferior
171         #return "\"%s\"" % (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*)%s)->byval_arg)" % (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
172
173     def to_string(self):
174         try:
175             return self.to_string_inner (True)
176         except:
177             #print sys.exc_info ()[0]
178             #print sys.exc_info ()[1]
179             return str(self.val.cast (gdb.lookup_type ("gpointer")))
180
181 class MonoGenericInstPrinter:
182     "Print a MonoGenericInst structure"
183
184     def __init__(self, val):
185         self.val = val
186
187     def to_string(self):
188         inst = self.val.dereference ()
189         inst_len = inst ["type_argc"]
190         inst_args = inst ["type_argv"]
191         inst_str = ""
192         for i in range(0, inst_len):
193             print inst_args
194             type_printer = MonoTypePrinter (inst_args [i])
195             if i > 0:
196                 inst_str = inst_str + ", "
197             inst_str = inst_str + type_printer.to_string ()
198         return inst_str
199
200 class MonoGenericClassPrinter:
201     "Print a MonoGenericClass structure"
202
203     def __init__(self, val):
204         self.val = val
205
206     def to_string_inner(self):
207         gclass = self.val.dereference ()
208         container_str = str(gclass ["container_class"])
209         class_inst = gclass ["context"]["class_inst"]
210         class_inst_str = ""
211         if int(class_inst.cast (gdb.lookup_type ("guint64"))) != 0:
212             class_inst_str  = str(class_inst)
213         method_inst = gclass ["context"]["method_inst"]
214         method_inst_str = ""
215         if int(method_inst.cast (gdb.lookup_type ("guint64"))) != 0:
216             method_inst_str  = str(method_inst)
217         return "%s, [%s], [%s]>" % (container_str, class_inst_str, method_inst_str)
218
219     def to_string(self):
220         try:
221             return self.to_string_inner ()
222         except:
223             #print sys.exc_info ()[0]
224             #print sys.exc_info ()[1]
225             return str(self.val.cast (gdb.lookup_type ("gpointer")))
226
227 class MonoTypePrinter:
228     "Print a MonoType structure"
229
230     def __init__(self, val):
231         self.val = val
232
233     def to_string_inner(self, csharp):
234         try:
235             t = self.val.dereference ()
236
237             kind = str (t ["type"]).replace ("MONO_TYPE_", "").lower ()
238             info = ""
239
240             if kind == "class":
241                 p = MonoClassPrinter(t ["data"]["klass"])
242                 info = p.to_string ()
243             elif kind == "genericinst":
244                 info = str(t ["data"]["generic_class"])
245
246             if info != "":
247                 return "{%s, %s}" % (kind, info)
248             else:
249                 return "{%s}" % (kind)
250         except:
251             #print sys.exc_info ()[0]
252             #print sys.exc_info ()[1]
253             return str(self.val.cast (gdb.lookup_type ("gpointer")))
254
255     def to_string(self):
256         return self.to_string_inner (False)
257
258 class MonoMethodRgctxPrinter:
259     "Print a MonoMethodRgctx structure"
260
261     def __init__(self, val):
262         self.val = val
263
264     def to_string(self):
265         rgctx = self.val.dereference ()
266         klass = rgctx ["class_vtable"].dereference () ["klass"]
267         klass_printer = MonoClassPrinter (klass)
268         inst = rgctx ["method_inst"].dereference ()
269         inst_len = inst ["type_argc"]
270         inst_args = inst ["type_argv"]
271         inst_str = ""
272         for i in range(0, inst_len):
273             print inst_args
274             type_printer = MonoTypePrinter (inst_args [i])
275             if i > 0:
276                 inst_str = inst_str + ", "
277             inst_str = inst_str + type_printer.to_string ()
278         return "MRGCTX[%s, [%s]]" % (klass_printer.to_string(), inst_str)
279
280 def lookup_pretty_printer(val):
281     t = str (val.type)
282     if t == "object":
283         return ObjectPrinter (val)
284     if t[0:5] == "class" and t[-1] == "&":
285         return ObjectPrinter (val)    
286     if t == "string":
287         return StringPrinter (val)
288     if t == "MonoMethod *":
289         return MonoMethodPrinter (val)
290     if t == "MonoClass *":
291         return MonoClassPrinter (val)
292     if t == "MonoType *":
293         return MonoTypePrinter (val)
294     if t == "MonoGenericInst *":
295         return MonoGenericInstPrinter (val)
296     if t == "MonoGenericClass *":
297         return MonoGenericClassPrinter (val)
298     if t == "MonoMethodRuntimeGenericContext *":
299         return MonoMethodRgctxPrinter (val)
300     return None
301
302 def register_csharp_printers(obj):
303     "Register C# pretty-printers with objfile Obj."
304
305     if obj == None:
306         obj = gdb
307
308     obj.pretty_printers.append (lookup_pretty_printer)
309
310 # This command will flush the debugging info collected by the runtime
311 class XdbCommand (gdb.Command):
312     def __init__ (self):
313         super (XdbCommand, self).__init__ ("xdb", gdb.COMMAND_NONE,
314                                            gdb.COMPLETE_COMMAND)
315
316     def invoke(self, arg, from_tty):
317         gdb.execute ("call mono_xdebug_flush ()")
318
319 register_csharp_printers (gdb.current_objfile())
320
321 XdbCommand ()
322
323 gdb.execute ("set environment MONO_XDEBUG gdb")
324
325 print "Mono support loaded."
326
327