2009-10-12 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Mon, 12 Oct 2009 12:02:14 +0000 (12:02 -0000)
committerZoltan Varga <vargaz@gmail.com>
Mon, 12 Oct 2009 12:02:14 +0000 (12:02 -0000)
* data/gdb-pre7.0: New directory, containing the mono support files for
gdb versions before 7.0.

svn path=/trunk/mono/; revision=143956

ChangeLog
data/gdb-pre7.0/ChangeLog [new file with mode: 0644]
data/gdb-pre7.0/gdb-python.diff [new file with mode: 0644]
data/gdb-pre7.0/mono-gdb.py [new file with mode: 0644]
data/gdb-pre7.0/mono-gdbinit [new file with mode: 0644]
data/gdb-pre7.0/test-xdb.py [new file with mode: 0644]

index bb8e72798b33eaea95dfead1c5b717344453f27e..35577f3a3cb326a191ce4a40fde7fc662f354882 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-10-12  Zoltan Varga  <vargaz@gmail.com>
+
+       * data/gdb-pre7.0: New directory, containing the mono support files for
+       gdb versions before 7.0.
+
 2009-10-10  Zoltan Varga  <vargaz@gmail.com>
 
        * */CMakeLists.txt: Update this to latest autoconf files.
@@ -37,7 +42,7 @@
 
 2009-08-04  Miguel de Icaza  <miguel@novell.com>
 
-       * Start the split between PLATFORM_WIN32 and TARGET_WIN32.  
+       * Start the split between PLATFORM_WIN32 and TARGET_WIN32.
 
        PLATFORM_WIN32 should be used to configure the runtime while
        building it.   TARGET_WIN32 is used for target execution.
diff --git a/data/gdb-pre7.0/ChangeLog b/data/gdb-pre7.0/ChangeLog
new file mode 100644 (file)
index 0000000..5ae92a0
--- /dev/null
@@ -0,0 +1,66 @@
+2009-10-09  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py (MonoSupport.run_hook): Set MONO_XDEBUG to 'gdb' to activate
+       the GDB support mode in the runtime.
+
+2009-04-14  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py (MonoClassPrinter.to_string): Add a MonoClass* pretty
+       printer.
+
+2009-04-12  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py (MonoMethodPrinter.to_string): Add a MonoMethod* pretty
+       printer.
+
+2009-04-10  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py: Update to the latest archer api.
+
+2009-04-07  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py (ObjectPrinter.__init__): Update to latest archer api.
+
+2009-04-06  Zoltan Varga  <vargaz@gmail.com>
+
+       * test-xdb.py: New file, tester script for xdb.
+
+       * mono-gdb.py (stringify_class_name): Handle classes without a namespace
+       correctly.
+       
+       * mono-gdb.py: Update after the changes to dwarfwriter.c.
+
+2009-04-05  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py: Handle superclasses in the pretty printer.
+
+2009-03-27  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py (StringPrinter.to_string): Fix support for non-ascii characters.
+
+2009-03-20  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py: Update for the latest python API on the archer branch.
+
+2009-02-03  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py: Remove the --64 argument to as, it is not needed.
+       
+       * mono-gdb.py (stringify_class_name): Helper function to print base types
+       using their short name. Also add a prototype implementation of registering
+       the hooks from python code instead of needing the mono-gdbinit file.
+
+       * gdb-python.diff: Changes against the gdb archer branch at 
+       http://sourceware.org/gdb/wiki/PythonGdb to fix some problems/add functionality.
+       
+2009-02-03  Geoff Norton  <gnorton@novell.com>
+
+       * mono-gdbinit: Hook into backtrace as hook-stop seems to crash gdb
+       * mono-gdb.py: Find the gdbinit name from the executable name instead of
+       hardcoding mono
+
+2009-01-29  Zoltan Varga  <vargaz@gmail.com>
+
+       * mono-gdb.py mono-gdbinit: Support files to help debugging mono/mono apps
+       using a python enabled gdb.
+
diff --git a/data/gdb-pre7.0/gdb-python.diff b/data/gdb-pre7.0/gdb-python.diff
new file mode 100644 (file)
index 0000000..464a8be
--- /dev/null
@@ -0,0 +1,163 @@
+diff --git a/gdb/ChangeLog b/gdb/ChangeLog
+index 640998b..fb73e9d 100644
+--- a/gdb/ChangeLog
++++ b/gdb/ChangeLog
+@@ -1,3 +1,10 @@
++2009-02-03  Zoltan Varga  <vargaz@gmail.com>
++
++      * cil-script.c python/python-cmd.c: Allow registration of pre/post hooks from 
++      python.
++      
++      * symfile.c (add_symbol_file_command): Comment out verbose messages.
++
+ 2009-02-03  Thiago Jung Bauermann  <bauerman@br.ibm.com>
+       * gdb/c-lang.c (c_get_string): Remove superfluous parenthesis from
+diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
+index 835d29c..3941aa5 100644
+--- a/gdb/cli/cli-script.c
++++ b/gdb/cli/cli-script.c
+@@ -299,6 +299,13 @@ execute_user_command (struct cmd_list_element *c, char *args)
+   static int user_call_depth = 0;
+   extern int max_user_call_depth;
++  /* Might be a user defined command implemented in Python */
++  if (!c->user_commands && c->func)
++      {
++        (*c->func) (c, args, FALSE);
++        return;
++      }
++      
+   old_chain = setup_user_args (args);
+   cmdlines = c->user_commands;
+diff --git a/gdb/python/python-cmd.c b/gdb/python/python-cmd.c
+index 61d5e5d..a3fbc08 100644
+--- a/gdb/python/python-cmd.c
++++ b/gdb/python/python-cmd.c
+@@ -339,7 +339,8 @@ gdbpy_parse_command_name (char *text, struct cmd_list_element ***base_list,
+ /* Object initializer; sets up gdb-side structures for command.
+-   Use: __init__(NAME, CMDCLASS, [COMPLETERCLASS, [PREFIX]]).
++   Use: __init__(NAME, CMDCLASS, [completerclass=COMPLETERCLASS, prefix=PREFIX,
++                 pre_hook_of=PREHOOK_OF, post_hook_of=POSTHOOK_OF]).
+    NAME is the name of the command.  It may consist of multiple words,
+    in which case the final word is the name of the new command, and
+@@ -354,6 +355,11 @@ gdbpy_parse_command_name (char *text, struct cmd_list_element ***base_list,
+    If PREFIX is True, then this command is a prefix command.
++   PREHOOK_OF is the name of a gdb command this command becomes a 
++   pre-execution hook of, same as if this command was defined using 
++   "define hook-<cmdname>"
++   POSTHOOK_OF is the same for post-execution hooks.
++
+    The documentation for the command is taken from the doc string for
+    the python class.
+    
+@@ -362,15 +368,18 @@ static int
+ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+ {
+   cmdpy_object *obj = (cmdpy_object *) self;
+-  char *name;
++  char *name, *pre_hook_of = NULL, *post_hook_of = NULL;
+   int cmdtype;
+   int completetype = -1;
+   char *docstring = NULL;
+   volatile struct gdb_exception except;
+   struct cmd_list_element **cmd_list;
++  struct cmd_list_element *pre_hookc = NULL, *post_hookc = NULL;
+   char *cmd_name, *pfx_name;
+   PyObject *is_prefix = NULL;
+   int cmp;
++  static char *kwlist[] = {"name", "cmdclass", "completerclass", "prefix", 
++                                                 "pre_hook_of", "post_hook_of", NULL};
+   if (obj->command)
+     {
+@@ -381,8 +390,9 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+       return -1;
+     }
+-  if (! PyArg_ParseTuple (args, "si|iO", &name, &cmdtype,
+-                        &completetype, &is_prefix))
++  if (! PyArg_ParseTupleAndKeywords (args, kwds, "si|iOss", kwlist, &name, &cmdtype,
++                                                                       &completetype, &is_prefix, &pre_hook_of,
++                                                                       &post_hook_of))
+     return -1;
+   if (cmdtype != no_class && cmdtype != class_run
+@@ -402,6 +412,30 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+       return -1;
+     }
++  if (pre_hook_of)
++      {
++        char *text = pre_hook_of;
++
++        pre_hookc = lookup_cmd_1 (&text, cmdlist, NULL, 1);
++        if (! pre_hookc)
++              {
++                PyErr_Format (PyExc_RuntimeError, _("command name given by pre_hook argument not found"));
++                return -1;
++              }
++      }
++
++  if (post_hook_of)
++      {
++        char *text = post_hook_of;
++
++        post_hookc = lookup_cmd_1 (&text, cmdlist, NULL, 1);
++        if (! post_hookc)
++              {
++                PyErr_Format (PyExc_RuntimeError, _("command name given by post_hook argument not found"));
++                return -1;
++              }
++      }
++
+   cmd_name = gdbpy_parse_command_name (name, &cmd_list, &cmdlist);
+   if (! cmd_name)
+     return -1;
+@@ -470,6 +504,18 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kwds)
+       cmd->func = cmdpy_function;
+       cmd->destroyer = cmdpy_destroyer;
++        if (pre_hookc)
++              {
++                pre_hookc->hook_pre = cmd;
++                cmd->hookee_pre = pre_hookc;
++              }
++
++        if (post_hookc)
++              {
++                post_hookc->hook_post = cmd;
++                cmd->hookee_post = post_hookc;
++              }
++
+       obj->command = cmd;
+       set_cmd_context (cmd, self);
+       set_cmd_completer (cmd, ((completetype == -1) ? cmdpy_completer
+diff --git a/gdb/symfile.c b/gdb/symfile.c
+index 14cb7b8..6d0bb40 100644
+--- a/gdb/symfile.c
++++ b/gdb/symfile.c
+@@ -2196,7 +2196,7 @@ add_symbol_file_command (char *args, int from_tty)
+      statements because hex_string returns a local static
+      string. */
+-  printf_unfiltered (_("add symbol table from file \"%s\" at\n"), filename);
++  /* printf_unfiltered (_("add symbol table from file \"%s\" at\n"), filename); */
+   section_addrs = alloc_section_addr_info (section_index);
+   make_cleanup (xfree, section_addrs);
+   for (i = 0; i < section_index; i++)
+@@ -2211,7 +2211,7 @@ add_symbol_file_command (char *args, int from_tty)
+          entered on the command line. */
+       section_addrs->other[sec_num].name = sec;
+       section_addrs->other[sec_num].addr = addr;
+-      printf_unfiltered ("\t%s_addr = %s\n", sec, paddress (addr));
++      /* printf_unfiltered ("\t%s_addr = %s\n", sec, paddress (addr)); */
+       sec_num++;
+       /* The object's sections are initialized when a
diff --git a/data/gdb-pre7.0/mono-gdb.py b/data/gdb-pre7.0/mono-gdb.py
new file mode 100644 (file)
index 0000000..c360d65
--- /dev/null
@@ -0,0 +1,247 @@
+#
+# Author: Zoltan Varga (vargaz@gmail.com)
+# License: MIT/X11
+#
+
+#
+# This is a mono support mode for a python-enabled gdb:
+# http://sourceware.org/gdb/wiki/PythonGdb
+# Usage:
+# - copy/symlink this file, plus mono-gdbinit to the directory where the mono 
+#   executable lives.
+# - run mono under gdb, or attach to a mono process using gdb
+# - Type 'xdb' in gdb to load/reload the debugging info emitted by the runtime.
+# - The debug info is emitted to a file called xdb.s in the current working directory.
+#   When attaching to a mono process, make sure you are in the same directory.
+#
+
+import os
+
+class StringPrinter:
+    "Print a C# string"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
+            return "null"
+
+        obj = self.val.cast (gdb.lookup_type ("MonoString").pointer ()).dereference ()
+        len = obj ['length']
+        chars = obj ['chars']
+        i = 0
+        res = ['"']
+        while i < len:
+            val = (chars.cast(gdb.lookup_type ("gint64")) + (i * 2)).cast(gdb.lookup_type ("gunichar2").pointer ()).dereference ()
+            if val >= 256:
+                c = "\u%X" % val
+            else:
+                c = chr (val)
+            res.append (c)
+            i = i + 1
+        res.append ('"')
+        return ''.join (res)
+
+def stringify_class_name(ns, name):
+    if ns == "System":
+        if name == "Byte":
+            return "byte"
+        if name == "String":
+            return "string"
+    if ns == "":
+        return name
+    else:
+        return "%s.%s" % (ns, name)
+
+class ArrayPrinter:
+    "Print a C# array"
+
+    def __init__(self, val, class_ns, class_name):
+        self.val = val
+        self.class_ns = class_ns
+        self.class_name = class_name
+
+    def to_string(self):
+        obj = self.val.cast (gdb.lookup_type ("MonoArray").pointer ()).dereference ()
+        length = obj ['max_length']
+        return "%s [%d]" % (stringify_class_name (self.class_ns, self.class_name [0:len(self.class_name) - 2]), int(length))
+        
+class ObjectPrinter:
+    "Print a C# object"
+
+    def __init__(self, val):
+        if str(val.type)[-1] == "&":
+            self.val = val.address.cast (gdb.lookup_type ("MonoObject").pointer ())
+        else:
+            self.val = val.cast (gdb.lookup_type ("MonoObject").pointer ())
+
+    class _iterator:
+        def __init__(self,obj):
+            self.obj = obj
+            self.iter = self.obj.type.fields ().__iter__ ()
+            pass
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            field = self.iter.next ()
+            try:
+                if str(self.obj [field.name].type) == "object":
+                    # Avoid recursion
+                    return (field.name, self.obj [field.name].cast (gdb.lookup_type ("void").pointer ()))
+                else:
+                    return (field.name, self.obj [field.name])
+            except:
+                # Superclass
+                return (field.name, self.obj.cast (gdb.lookup_type ("%s" % (field.name))))
+
+    def children(self):
+        # FIXME: It would be easier if gdb.Value would support iteration itself
+        # It would also be better if we could return None
+        if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
+            return {}.__iter__ ()
+        try:
+            obj = self.val.dereference ()
+            class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
+            class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
+            if class_name [-2:len(class_name)] == "[]":
+                return {}.__iter__ ()
+            gdb_type = gdb.lookup_type ("struct %s_%s" % (class_ns.replace (".", "_"), class_name))
+            return self._iterator(obj.cast (gdb_type))
+        except:
+            print sys.exc_info ()[0]
+            print sys.exc_info ()[1]
+            return {}.__iter__ ()
+
+    def to_string(self):
+        if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
+            return "null"
+        try:
+            obj = self.val.dereference ()
+            class_ns = obj ['vtable'].dereference ()['klass'].dereference ()['name_space'].string ()
+            class_name = obj ['vtable'].dereference ()['klass'].dereference ()['name'].string ()
+            if class_ns == "System" and class_name == "String":
+                return StringPrinter (self.val).to_string ()
+            if class_name [-2:len(class_name)] == "[]":
+                return ArrayPrinter (self.val,class_ns,class_name).to_string ()
+            if class_ns != "":
+                try:
+                    gdb_type = gdb.lookup_type ("struct %s.%s" % (class_ns, class_name))
+                except:
+                    # Maybe there is no debug info for that type
+                    return "%s.%s" % (class_ns, class_name)
+                #return obj.cast (gdb_type)
+                return "%s.%s" % (class_ns, class_name)
+            return class_name
+        except:
+            print sys.exc_info ()[0]
+            print sys.exc_info ()[1]
+            # FIXME: This can happen because we don't have liveness information
+            return self.val.cast (gdb.lookup_type ("guint64"))
+        
+class MonoMethodPrinter:
+    "Print a MonoMethod structure"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
+            return "0x0"
+        val = self.val.dereference ()
+        klass = val ["klass"].dereference ()
+        class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
+        return "\"%s:%s ()\"" % (class_name, val ["name"].string ())
+        # This returns more info but requires calling into the inferior
+        #return "\"%s\"" % (gdb.parse_and_eval ("mono_method_full_name (%s, 1)" % (str (int (self.val.cast (gdb.lookup_type ("guint64")))))).string ())
+
+class MonoClassPrinter:
+    "Print a MonoClass structure"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
+            return "0x0"
+        klass = self.val.dereference ()
+        class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
+        return "\"%s\"" % (class_name)
+        # This returns more info but requires calling into the inferior
+        #return "\"%s\"" % (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*)%s)->byval_arg)" % (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
+
+def lookup_pretty_printer(val):
+    t = str (val.type)
+    if t == "object":
+        return ObjectPrinter (val)
+    if t[0:5] == "class" and t[-1] == "&":
+        return ObjectPrinter (val)    
+    if t == "string":
+        return StringPrinter (val)
+    if t == "MonoMethod *":
+        return MonoMethodPrinter (val)
+    if t == "MonoClass *":
+        return MonoClassPrinter (val)
+    return None
+
+def register_csharp_printers(obj):
+    "Register C# pretty-printers with objfile Obj."
+
+    if obj == None:
+        obj = gdb
+
+    obj.pretty_printers.append (lookup_pretty_printer)
+
+register_csharp_printers (gdb.current_objfile())
+
+class MonoSupport(object):
+
+    def __init__(self):
+        self.s_size = 0
+
+    def run_hook(self):
+        if os.access ("xdb.s", os.F_OK):
+            os.remove ("xdb.s")
+        gdb.execute ("set environment MONO_XDEBUG gdb")
+        
+    def stop_hook(self):
+        # Called when the program is stopped
+        # Need to recompile+reload the xdb.s file if needed
+        # FIXME: Need to detect half-written files created when the child is
+        # interrupted while executing the xdb.s writing code
+        # FIXME: Handle appdomain unload
+        if os.access ("xdb.s", os.F_OK):
+            new_size = os.stat ("xdb.s").st_size
+            if new_size > self.s_size:
+                sofile = "xdb.so"
+                gdb.execute ("shell as -o xdb.o xdb.s && ld -shared -o %s xdb.o" % sofile)
+                # FIXME: This prints messages which couldn't be turned off
+                gdb.execute ("add-symbol-file %s 0" % sofile)
+                self.s_size = new_size
+
+class RunHook (gdb.Command):
+    def __init__ (self):
+        super (RunHook, self).__init__ ("hook-run", gdb.COMMAND_NONE,
+                                        gdb.COMPLETE_COMMAND, pre_hook_of="run")
+
+    def invoke(self, arg, from_tty):
+        mono_support.run_hook ()
+
+print "Mono support loaded."
+
+mono_support = MonoSupport ()
+
+# This depends on the changes in gdb-python.diff to work
+#RunHook ()
+
+# Register our hooks
+# This currently cannot be done from python code
+
+exec_file = gdb.current_objfile ().filename
+# FIXME: Is there a way to detect symbolic links ?
+if os.stat (exec_file).st_size != os.lstat (exec_file).st_size:
+    exec_file = os.readlink (exec_file)
+exec_dir = os.path.dirname (exec_file)
+gdb.execute ("source %s/%s-gdbinit" % (exec_dir, os.path.basename (exec_file)))
diff --git a/data/gdb-pre7.0/mono-gdbinit b/data/gdb-pre7.0/mono-gdbinit
new file mode 100644 (file)
index 0000000..aed152c
--- /dev/null
@@ -0,0 +1,20 @@
+# Loaded by mono-gdb.py
+
+# FIXME: According to gdb docs, this is called _before_ anything is printed
+# Got broken by this patch:
+# http://sourceware.org/ml/gdb-patches/2008-09/msg00193.html
+# FIXME: This seems to cause crashes inside gdb
+#define hook-stop
+#         python mono_support.stop_hook ()
+#end
+define hook-backtrace
+          python mono_support.stop_hook ()
+end
+
+define hook-run
+          python mono_support.run_hook ()
+end
+
+define xdb
+          python mono_support.stop_hook ()
+end
diff --git a/data/gdb-pre7.0/test-xdb.py b/data/gdb-pre7.0/test-xdb.py
new file mode 100644 (file)
index 0000000..a78a998
--- /dev/null
@@ -0,0 +1,19 @@
+# Tester script for the xdb functionality
+# Run using gdb -P test-xdb.py <NORMAL GDB COMMAND LINE>
+
+import sys
+
+gdb.execute ("file %s" % sys.argv [0])
+gdb.execute ("r --break *:* %s" % " ".join (sys.argv[1:len(sys.argv)]))
+
+while True:
+       try:
+               if gdb.threads () == None:
+                       break
+               gdb.execute("xdb")
+               gdb.execute("bt")
+               gdb.execute("info args")
+               gdb.execute("info locals")
+               gdb.execute("c")
+       except:
+               gdb.execute ("quit")