A few pretty print fixes for the GDB plugin. (#4001)
[mono.git] / data / gdb / mono-gdb.py
index 1ce7e6e2d7be6517ac35e68d035ac8de64da4777..43c49cfc6a0aad2e99147091f0fb76a1697cc37c 100644 (file)
@@ -10,6 +10,7 @@
 # - run mono under gdb, or attach to a mono process started with --debug=gdb using gdb.
 #
 
+from __future__ import print_function
 import os
 
 class StringPrinter:
@@ -30,7 +31,7 @@ class StringPrinter:
         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
+                c = unichr (val)
             else:
                 c = chr (val)
             res.append (c)
@@ -47,7 +48,7 @@ def stringify_class_name(ns, name):
     if ns == "":
         return name
     else:
-        return "%s.%s" % (ns, name)
+        return "{}.{}".format (ns, name)
 
 class ArrayPrinter:
     "Print a C# array"
@@ -60,7 +61,7 @@ class ArrayPrinter:
     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))
+        return "{} [{}]".format (stringify_class_name (self.class_ns, self.class_name [0:len(self.class_name) - 2]), int(length))
         
 class ObjectPrinter:
     "Print a C# object"
@@ -90,7 +91,7 @@ class ObjectPrinter:
                     return (field.name, self.obj [field.name])
             except:
                 # Superclass
-                return (field.name, self.obj.cast (gdb.lookup_type ("%s" % (field.name))))
+                return (field.name, self.obj.cast (gdb.lookup_type ("{}".format (field.name))))
 
     def children(self):
         # FIXME: It would be easier if gdb.Value would support iteration itself
@@ -104,13 +105,13 @@ class ObjectPrinter:
             if class_name [-2:len(class_name)] == "[]":
                 return {}.__iter__ ()
             try:
-                gdb_type = gdb.lookup_type ("struct %s_%s" % (class_ns.replace (".", "_"), class_name))
+                gdb_type = gdb.lookup_type ("struct {}_{}".format (class_ns.replace (".", "_"), class_name))
                 return self._iterator(obj.cast (gdb_type))
             except:
                 return {}.__iter__ ()
         except:
-            print sys.exc_info ()[0]
-            print sys.exc_info ()[1]
+            print (sys.exc_info ()[0])
+            print (sys.exc_info ()[1])
             return {}.__iter__ ()
 
     def to_string(self):
@@ -126,16 +127,16 @@ class ObjectPrinter:
                 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))
+                    gdb_type = gdb.lookup_type ("struct {}.{}".format (class_ns, class_name))
                 except:
                     # Maybe there is no debug info for that type
-                    return "%s.%s" % (class_ns, class_name)
+                    return "{}.{}".format (class_ns, class_name)
                 #return obj.cast (gdb_type)
-                return "%s.%s" % (class_ns, class_name)
+                return "{}.{}".format (class_ns, class_name)
             return class_name
         except:
-            print sys.exc_info ()[0]
-            print sys.exc_info ()[1]
+            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"))
         
@@ -151,9 +152,9 @@ class MonoMethodPrinter:
         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 ())
+        return "\"{}:{} ()\"".format (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 ())
+        #return "\"{}\"".format (gdb.parse_and_eval ("mono_method_full_name ({}, 1)".format (str (int (self.val.cast (gdb.lookup_type ("guint64")))))).string ())
 
 class MonoClassPrinter:
     "Print a MonoClass structure"
@@ -167,18 +168,18 @@ class MonoClassPrinter:
         klass = self.val.dereference ()
         class_name = stringify_class_name (klass ["name_space"].string (), klass ["name"].string ())
         if add_quotes:
-            return "\"%s\"" % (class_name)
+            return "\"{}\"".format (class_name)
         else:
             return 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")))))))
+        #return "\"{}\"".format (gdb.parse_and_eval ("mono_type_full_name (&((MonoClass*){})->byval_arg)".format (str (int ((self.val).cast (gdb.lookup_type ("guint64")))))))
 
     def to_string(self):
         try:
             return self.to_string_inner (True)
         except:
-            #print sys.exc_info ()[0]
-            #print sys.exc_info ()[1]
+            #print (sys.exc_info ()[0])
+            #print (sys.exc_info ()[1])
             return str(self.val.cast (gdb.lookup_type ("gpointer")))
 
 class MonoGenericInstPrinter:
@@ -188,12 +189,14 @@ class MonoGenericInstPrinter:
         self.val = val
 
     def to_string(self):
+        if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
+            return "0x0"
         inst = self.val.dereference ()
         inst_len = inst ["type_argc"]
         inst_args = inst ["type_argv"]
         inst_str = ""
         for i in range(0, inst_len):
-            print inst_args
+            # print (inst_args)
             type_printer = MonoTypePrinter (inst_args [i])
             if i > 0:
                 inst_str = inst_str + ", "
@@ -217,14 +220,14 @@ class MonoGenericClassPrinter:
         method_inst_str = ""
         if int(method_inst.cast (gdb.lookup_type ("guint64"))) != 0:
             method_inst_str  = str(method_inst)
-        return "%s, [%s], [%s]>" % (container_str, class_inst_str, method_inst_str)
+        return "{}, [{}], [{}]>".format (container_str, class_inst_str, method_inst_str)
 
     def to_string(self):
         try:
             return self.to_string_inner ()
         except:
-            #print sys.exc_info ()[0]
-            #print sys.exc_info ()[1]
+            #print (sys.exc_info ()[0])
+            #print (sys.exc_info ()[1])
             return str(self.val.cast (gdb.lookup_type ("gpointer")))
 
 class MonoTypePrinter:
@@ -235,7 +238,7 @@ class MonoTypePrinter:
 
     def to_string_inner(self, csharp):
         try:
-            t = self.val.dereference ()
+            t = self.val.referenced_value ()
 
             kind = str (t ["type"]).replace ("MONO_TYPE_", "").lower ()
             info = ""
@@ -247,12 +250,12 @@ class MonoTypePrinter:
                 info = str(t ["data"]["generic_class"])
 
             if info != "":
-                return "{%s, %s}" % (kind, info)
+                return "{{{}, {}}}".format (kind, info)
             else:
-                return "{%s}" % (kind)
+                return "{{{}}}".format (kind)
         except:
-            #print sys.exc_info ()[0]
-            #print sys.exc_info ()[1]
+            #print (sys.exc_info ()[0])
+            #print (sys.exc_info ()[1])
             return str(self.val.cast (gdb.lookup_type ("gpointer")))
 
     def to_string(self):
@@ -273,12 +276,27 @@ class MonoMethodRgctxPrinter:
         inst_args = inst ["type_argv"]
         inst_str = ""
         for i in range(0, inst_len):
-            print inst_args
+            # print (inst_args)
             type_printer = MonoTypePrinter (inst_args [i])
             if i > 0:
                 inst_str = inst_str + ", "
             inst_str = inst_str + type_printer.to_string ()
-        return "MRGCTX[%s, [%s]]" % (klass_printer.to_string(), inst_str)
+        return "MRGCTX[{}, [{}]]".format (klass_printer.to_string(), inst_str)
+
+class MonoVTablePrinter:
+    "Print a MonoVTable structure"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        if int(self.val.cast (gdb.lookup_type ("guint64"))) == 0:
+            return "0x0"
+        vtable = self.val.dereference ()
+        klass = vtable ["klass"]
+        klass_printer = MonoClassPrinter (klass)
+
+        return "vtable({})".format (klass_printer.to_string ())
 
 def lookup_pretty_printer(val):
     t = str (val.type)
@@ -288,6 +306,8 @@ def lookup_pretty_printer(val):
         return ObjectPrinter (val)    
     if t == "string":
         return StringPrinter (val)
+    if t == "MonoString *":
+        return StringPrinter (val)
     if t == "MonoMethod *":
         return MonoMethodPrinter (val)
     if t == "MonoClass *":
@@ -300,6 +320,8 @@ def lookup_pretty_printer(val):
         return MonoGenericClassPrinter (val)
     if t == "MonoMethodRuntimeGenericContext *":
         return MonoMethodRgctxPrinter (val)
+    if t == "MonoVTable *":
+        return MonoVTablePrinter (val)
     return None
 
 def register_csharp_printers(obj):
@@ -325,6 +347,6 @@ XdbCommand ()
 
 gdb.execute ("set environment MONO_XDEBUG gdb")
 
-print "Mono support loaded."
+print ("Mono support loaded.")