2010-02-13 Jb Evain <jbevain@novell.com>
[mono-project.git] / data / gdb / mono-gdb.py
blobca0d19e294f29dd5893e0c345114a5ef4c15fe01
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 import os
15 class StringPrinter:
16 "Print a C# string"
18 def __init__(self, val):
19 self.val = val
21 def to_string(self):
22 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
23 return "null"
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)
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)
52 class ArrayPrinter:
53 "Print a C# array"
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
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))
65 class ObjectPrinter:
66 "Print a C# object"
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 ())
74 class _iterator:
75 def __init__(self,obj):
76 self.obj = obj
77 self.iter = self.obj.type.fields ().__iter__ ()
78 pass
80 def __iter__(self):
81 return self
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))))
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__ ()
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"))
139 class MonoMethodPrinter:
140 "Print a MonoMethod structure"
142 def __init__(self, val):
143 self.val = val
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 ())
155 class MonoClassPrinter:
156 "Print a MonoClass structure"
158 def __init__(self, val):
159 self.val = val
161 def to_string(self):
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 return "\"%s\"" % (class_name)
167 # This returns more info but requires calling into the inferior
168 #return "\"%s\"" % (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*)%s)->byval_arg)" % (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
170 def lookup_pretty_printer(val):
171 t = str (val.type)
172 if t == "object":
173 return ObjectPrinter (val)
174 if t[0:5] == "class" and t[-1] == "&":
175 return ObjectPrinter (val)
176 if t == "string":
177 return StringPrinter (val)
178 if t == "MonoMethod *":
179 return MonoMethodPrinter (val)
180 if t == "MonoClass *":
181 return MonoClassPrinter (val)
182 return None
184 def register_csharp_printers(obj):
185 "Register C# pretty-printers with objfile Obj."
187 if obj == None:
188 obj = gdb
190 obj.pretty_printers.append (lookup_pretty_printer)
192 # This command will flush the debugging info collected by the runtime
193 class XdbCommand (gdb.Command):
194 def __init__ (self):
195 super (XdbCommand, self).__init__ ("xdb", gdb.COMMAND_NONE,
196 gdb.COMPLETE_COMMAND)
198 def invoke(self, arg, from_tty):
199 gdb.execute ("call mono_xdebug_flush ()")
201 register_csharp_printers (gdb.current_objfile())
203 XdbCommand ()
205 gdb.execute ("set environment MONO_XDEBUG gdb")
207 print "Mono support loaded."