2 # Author: Zoltan Varga (vargaz@gmail.com)
7 # This is a mono support mode for a python-enabled gdb:
8 # http://sourceware.org/gdb/wiki/PythonGdb
10 # - copy/symlink this file, plus mono-gdbinit to the directory where the mono
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.
23 def __init__(self, val):
27 if int(self.val.cast (gdb.Type ("guint64"))) == 0:
30 obj = self.val.cast (gdb.Type ("MonoString").pointer ()).dereference ()
36 val = (chars.cast(gdb.Type ("gint64")) + (i * 2)).cast(gdb.Type ("gunichar2").pointer ()).dereference ()
46 def stringify_class_name(ns, name):
52 return "%s.%s" % (ns, name)
57 def __init__(self, val, class_ns, class_name):
59 self.class_ns = class_ns
60 self.class_name = class_name
63 obj = self.val.cast (gdb.Type ("MonoArray").pointer ()).dereference ()
64 length = obj ['max_length']
65 return "%s [%d]" % (stringify_class_name (self.class_ns, self.class_name [0:len(self.class_name) - 2]), int(length))
70 def __init__(self, val):
71 if str(val.type ())[-1] == "&":
72 self.val = val.address ().cast (gdb.Type ("MonoObject").pointer ())
74 self.val = val.cast (gdb.Type ("MonoObject").pointer ())
77 def __init__(self,obj):
79 self.iter = self.obj.type ().fields ().__iter__ ()
86 field = self.iter.next ()
88 if str(self.obj [field.name].type ()) == "object":
90 return (field.name, self.obj [field.name].cast (gdb.Type ("void").pointer ()))
92 return (field.name, self.obj [field.name])
95 return (field.name, self.obj.cast (gdb.Type ("%s" % (field.name))))
98 # FIXME: It would be easier if gdb.Value would support iteration itself
99 # It would also be better if we could return None
100 if int(self.val.cast (gdb.Type ("guint64"))) == 0:
101 return {}.__iter__ ()
103 obj = self.val.dereference ()
104 class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
105 class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
106 if class_name [-2:len(class_name)] == "[]":
107 return {}.__iter__ ()
108 gdb_type = gdb.Type ("struct %s_%s" % (class_ns.replace (".", "_"), class_name))
109 return self._iterator(obj.cast (gdb_type))
111 print sys.exc_info ()[0]
112 print sys.exc_info ()[1]
113 return {}.__iter__ ()
116 if int(self.val.cast (gdb.Type ("guint64"))) == 0:
119 obj = self.val.dereference ()
120 class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
121 class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
122 if class_ns == "System" and class_name == "String":
123 return StringPrinter (self.val).to_string ()
124 if class_name [-2:len(class_name)] == "[]":
125 return ArrayPrinter (self.val,class_ns,class_name).to_string ()
128 gdb_type = gdb.Type ("struct %s.%s" % (class_ns, class_name))
130 # Maybe there is no debug info for that type
131 return "%s.%s" % (class_ns, class_name)
132 #return obj.cast (gdb_type)
133 return "%s.%s" % (class_ns, class_name)
136 print sys.exc_info ()[0]
137 print sys.exc_info ()[1]
138 # FIXME: This can happen because we don't have liveness information
139 return self.val.cast (gdb.Type ("guint64"))
141 def lookup_pretty_printer(val):
142 t = str (val.type ())
144 return ObjectPrinter (val)
145 if t[0:5] == "class" and t[-1] == "&":
146 return ObjectPrinter (val)
148 return StringPrinter (val)
151 def register_csharp_printers(obj):
152 "Register C# pretty-printers with objfile Obj."
157 obj.pretty_printers.append (lookup_pretty_printer)
159 register_csharp_printers (gdb.current_objfile())
161 class MonoSupport(object):
167 if os.access ("xdb.s", os.F_OK):
169 gdb.execute ("set environment MONO_XDEBUG 1")
172 # Called when the program is stopped
173 # Need to recompile+reload the xdb.s file if needed
174 # FIXME: Need to detect half-written files created when the child is
175 # interrupted while executing the xdb.s writing code
176 # FIXME: Handle appdomain unload
177 if os.access ("xdb.s", os.F_OK):
178 new_size = os.stat ("xdb.s").st_size
179 if new_size > self.s_size:
181 gdb.execute ("shell as -o xdb.o xdb.s && ld -shared -o %s xdb.o" % sofile)
182 # FIXME: This prints messages which couldn't be turned off
183 gdb.execute ("add-symbol-file %s 0" % sofile)
184 self.s_size = new_size
186 class RunHook (gdb.Command):
188 super (RunHook, self).__init__ ("hook-run", gdb.COMMAND_NONE,
189 gdb.COMPLETE_COMMAND, pre_hook_of="run")
191 def invoke(self, arg, from_tty):
192 mono_support.run_hook ()
194 print "Mono support loaded."
196 mono_support = MonoSupport ()
198 # This depends on the changes in gdb-python.diff to work
202 # This currently cannot be done from python code
204 exec_file = gdb.current_objfile ().filename
205 # FIXME: Is there a way to detect symbolic links ?
206 if os.stat (exec_file).st_size != os.lstat (exec_file).st_size:
207 exec_file = os.readlink (exec_file)
208 exec_dir = os.path.dirname (exec_file)
209 gdb.execute ("source %s/%s-gdbinit" % (exec_dir, os.path.basename (exec_file)))