in System:
[mono-project.git] / data / gdb-pre7.0 / mono-gdb.py
blobc360d658f6a230b164943d4c285df1ef8a8d06d1
2 # Author: Zoltan Varga (vargaz@gmail.com)
3 # License: MIT/X11
7 # This is a mono support mode for a python-enabled gdb:
8 # http://sourceware.org/gdb/wiki/PythonGdb
9 # Usage:
10 # - copy/symlink this file, plus mono-gdbinit to the directory where the mono
11 # executable lives.
12 # - run mono under gdb, or attach to a mono process using gdb
13 # - Type 'xdb' in gdb to load/reload the debugging info emitted by the runtime.
14 # - The debug info is emitted to a file called xdb.s in the current working directory.
15 # When attaching to a mono process, make sure you are in the same directory.
18 import os
20 class StringPrinter:
21 "Print a C# string"
23 def __init__(self, val):
24 self.val = val
26 def to_string(self):
27 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
28 return "null"
30 obj = self.val.cast (gdb.lookup_type ("MonoString").pointer ()).dereference ()
31 len = obj ['length']
32 chars = obj ['chars']
33 i = 0
34 res = ['"']
35 while i < len:
36 val = (chars.cast(gdb.lookup_type ("gint64")) + (i * 2)).cast(gdb.lookup_type ("gunichar2").pointer ()).dereference ()
37 if val >= 256:
38 c = "\u%X" % val
39 else:
40 c = chr (val)
41 res.append (c)
42 i = i + 1
43 res.append ('"')
44 return ''.join (res)
46 def stringify_class_name(ns, name):
47 if ns == "System":
48 if name == "Byte":
49 return "byte"
50 if name == "String":
51 return "string"
52 if ns == "":
53 return name
54 else:
55 return "%s.%s" % (ns, name)
57 class ArrayPrinter:
58 "Print a C# array"
60 def __init__(self, val, class_ns, class_name):
61 self.val = val
62 self.class_ns = class_ns
63 self.class_name = class_name
65 def to_string(self):
66 obj = self.val.cast (gdb.lookup_type ("MonoArray").pointer ()).dereference ()
67 length = obj ['max_length']
68 return "%s [%d]" % (stringify_class_name (self.class_ns, self.class_name [0:len(self.class_name) - 2]), int(length))
70 class ObjectPrinter:
71 "Print a C# object"
73 def __init__(self, val):
74 if str(val.type)[-1] == "&":
75 self.val = val.address.cast (gdb.lookup_type ("MonoObject").pointer ())
76 else:
77 self.val = val.cast (gdb.lookup_type ("MonoObject").pointer ())
79 class _iterator:
80 def __init__(self,obj):
81 self.obj = obj
82 self.iter = self.obj.type.fields ().__iter__ ()
83 pass
85 def __iter__(self):
86 return self
88 def next(self):
89 field = self.iter.next ()
90 try:
91 if str(self.obj [field.name].type) == "object":
92 # Avoid recursion
93 return (field.name, self.obj [field.name].cast (gdb.lookup_type ("void").pointer ()))
94 else:
95 return (field.name, self.obj [field.name])
96 except:
97 # Superclass
98 return (field.name, self.obj.cast (gdb.lookup_type ("%s" % (field.name))))
100 def children(self):
101 # FIXME: It would be easier if gdb.Value would support iteration itself
102 # It would also be better if we could return None
103 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
104 return {}.__iter__ ()
105 try:
106 obj = self.val.dereference ()
107 class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
108 class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
109 if class_name [-2:len(class_name)] == "[]":
110 return {}.__iter__ ()
111 gdb_type = gdb.lookup_type ("struct %s_%s" % (class_ns.replace (".", "_"), class_name))
112 return self._iterator(obj.cast (gdb_type))
113 except:
114 print sys.exc_info ()[0]
115 print sys.exc_info ()[1]
116 return {}.__iter__ ()
118 def to_string(self):
119 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
120 return "null"
121 try:
122 obj = self.val.dereference ()
123 class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
124 class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
125 if class_ns == "System" and class_name == "String":
126 return StringPrinter (self.val).to_string ()
127 if class_name [-2:len(class_name)] == "[]":
128 return ArrayPrinter (self.val,class_ns,class_name).to_string ()
129 if class_ns != "":
130 try:
131 gdb_type = gdb.lookup_type ("struct %s.%s" % (class_ns, class_name))
132 except:
133 # Maybe there is no debug info for that type
134 return "%s.%s" % (class_ns, class_name)
135 #return obj.cast (gdb_type)
136 return "%s.%s" % (class_ns, class_name)
137 return class_name
138 except:
139 print sys.exc_info ()[0]
140 print sys.exc_info ()[1]
141 # FIXME: This can happen because we don't have liveness information
142 return self.val.cast (gdb.lookup_type ("guint64"))
144 class MonoMethodPrinter:
145 "Print a MonoMethod structure"
147 def __init__(self, val):
148 self.val = val
150 def to_string(self):
151 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
152 return "0x0"
153 val = self.val.dereference ()
154 klass = val ["klass"].dereference ()
155 class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
156 return "\"%s:%s ()\"" % (class_name, val ["name"].string ())
157 # This returns more info but requires calling into the inferior
158 #return "\"%s\"" % (gdb.parse_and_eval ("mono_method_full_name (%s, 1)" % (str (int (self.val.cast (gdb.lookup_type ("guint64")))))).string ())
160 class MonoClassPrinter:
161 "Print a MonoClass structure"
163 def __init__(self, val):
164 self.val = val
166 def to_string(self):
167 if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
168 return "0x0"
169 klass = self.val.dereference ()
170 class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
171 return "\"%s\"" % (class_name)
172 # This returns more info but requires calling into the inferior
173 #return "\"%s\"" % (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*)%s)->byval_arg)" % (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
175 def lookup_pretty_printer(val):
176 t = str (val.type)
177 if t == "object":
178 return ObjectPrinter (val)
179 if t[0:5] == "class" and t[-1] == "&":
180 return ObjectPrinter (val)
181 if t == "string":
182 return StringPrinter (val)
183 if t == "MonoMethod *":
184 return MonoMethodPrinter (val)
185 if t == "MonoClass *":
186 return MonoClassPrinter (val)
187 return None
189 def register_csharp_printers(obj):
190 "Register C# pretty-printers with objfile Obj."
192 if obj == None:
193 obj = gdb
195 obj.pretty_printers.append (lookup_pretty_printer)
197 register_csharp_printers (gdb.current_objfile())
199 class MonoSupport(object):
201 def __init__(self):
202 self.s_size = 0
204 def run_hook(self):
205 if os.access ("xdb.s", os.F_OK):
206 os.remove ("xdb.s")
207 gdb.execute ("set environment MONO_XDEBUG gdb")
209 def stop_hook(self):
210 # Called when the program is stopped
211 # Need to recompile+reload the xdb.s file if needed
212 # FIXME: Need to detect half-written files created when the child is
213 # interrupted while executing the xdb.s writing code
214 # FIXME: Handle appdomain unload
215 if os.access ("xdb.s", os.F_OK):
216 new_size = os.stat ("xdb.s").st_size
217 if new_size > self.s_size:
218 sofile = "xdb.so"
219 gdb.execute ("shell as -o xdb.o xdb.s && ld -shared -o %s xdb.o" % sofile)
220 # FIXME: This prints messages which couldn't be turned off
221 gdb.execute ("add-symbol-file %s 0" % sofile)
222 self.s_size = new_size
224 class RunHook (gdb.Command):
225 def __init__ (self):
226 super (RunHook, self).__init__ ("hook-run", gdb.COMMAND_NONE,
227 gdb.COMPLETE_COMMAND, pre_hook_of="run")
229 def invoke(self, arg, from_tty):
230 mono_support.run_hook ()
232 print "Mono support loaded."
234 mono_support = MonoSupport ()
236 # This depends on the changes in gdb-python.diff to work
237 #RunHook ()
239 # Register our hooks
240 # This currently cannot be done from python code
242 exec_file = gdb.current_objfile ().filename
243 # FIXME: Is there a way to detect symbolic links ?
244 if os.stat (exec_file).st_size != os.lstat (exec_file).st_size:
245 exec_file = os.readlink (exec_file)
246 exec_dir = os.path.dirname (exec_file)
247 gdb.execute ("source %s/%s-gdbinit" % (exec_dir, os.path.basename (exec_file)))