From dba842eea04236c9d769a9902a03579c1fda2c7e Mon Sep 17 00:00:00 2001
From: Stephan Hageboeck <stephan.hageboeck@cern.ch>
Date: Thu, 25 Apr 2019 15:49:10 +0200
Subject: [PATCH] Add alpha version of gdb pretty printers.

This adds gdb pretty printers for a few objects such as TString and TNamed, as well
as a couple of RooFit objects. gdb can automatically load them if gdb's `add-auto-load-safe-path`
is set to ROOT's lib directory. `print /r <obj>` allows to still print raw.
---
 build/CMakeLists.txt                      |  11 ++
 build/gdbPrinters/libCore.so-gdb.py       |  72 ++++++++++++
 build/gdbPrinters/libRooFitCore.so-gdb.py | 136 ++++++++++++++++++++++
 3 files changed, 219 insertions(+)
 create mode 100644 build/gdbPrinters/libCore.so-gdb.py
 create mode 100644 build/gdbPrinters/libRooFitCore.so-gdb.py

diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt
index 2d5e3ef6c27..b84481041b3 100644
--- a/build/CMakeLists.txt
+++ b/build/CMakeLists.txt
@@ -18,3 +18,14 @@ ROOT_EXECUTABLE(rmkdepend
   rmkdepend/parse.c
   rmkdepend/pr.c
 )
+
+IF(CMAKE_BUILD_TYPE MATCHES "Debug|RelWithDebInfo")
+  file(COPY "gdbPrinters/"
+       DESTINATION ${CMAKE_BINARY_DIR}/lib
+       FILES_MATCHING PATTERN "*-gdb.py")
+
+  file(GLOB PRETTY_PRINTERS "gdbPrinters/*-gdb.py")
+  install(FILES ${PRETTY_PRINTERS}
+          DESTINATION lib
+          CONFIGURATIONS Debug RelWithDebInfo)
+ENDIF()
diff --git a/build/gdbPrinters/libCore.so-gdb.py b/build/gdbPrinters/libCore.so-gdb.py
new file mode 100644
index 00000000000..c9613beb2e0
--- /dev/null
+++ b/build/gdbPrinters/libCore.so-gdb.py
@@ -0,0 +1,72 @@
+# Pretty printers for gdb
+# \author: Stephan Hageboeck, CERN
+# These pretty printers will make ROOT objects more readable when printed in gdb.
+# If the pretty-printed output is not sufficient, one can always use "print /r <object>"
+# for raw printing.
+#
+# When a debug build is used, they will be installed next to the ROOT libraries.
+# gdb will load them automatically if the auto-load-safe-path is set to ROOT's library directory.
+# For this, one has to add `add-auto-load-safe-path <ROOT lib dir>` to .gdbinit
+#
+# If loaded successfully, typing `info pretty-printer` at the gdb prompt should list the
+# printers registered at the end of this file.
+
+import gdb
+
+
+class TObjectPrinter(object):
+   "Print TObjects"
+
+   def __init__(self, val):
+      self.val = val
+      
+   def children(self):
+      yield "fUniqueID", self.val['fUniqueID']
+      yield "fBits", self.val['fBits']
+
+   def to_string(self):
+      return "(TObject)"
+
+
+
+class TNamedPrinter(object):
+   "Print TNamed"
+
+   def __init__(self, val):
+      self.val = val
+
+   def to_string(self):
+      return "(TNamed) " + str(self.val['fName']) + " " + str(self.val['fTitle'])
+
+
+
+class TStringPrinter(object):
+   "Print TStrings"
+
+   def __init__(self, val):
+      self.val = val
+      typeAndAddr = "(*(TString*)"+str(val.address)+")"
+      query = typeAndAddr + ".fRep.fShort.fSize & TString::kShortMask"
+      self.isLong = bool(gdb.parse_and_eval(query))
+      
+   def display_hint(self):
+      return 'string'
+
+   def to_string(self):
+      theStr = self.val['fRep']['fLong']['fData'] if self.isLong else self.val['fRep']['fShort']['fData']
+      return theStr.string()
+
+
+
+
+def build_pretty_printer():
+   pp = gdb.printing.RegexpCollectionPrettyPrinter("libCore")
+   pp.add_printer('TObject', '^TObject$', TObjectPrinter)
+   pp.add_printer('TNamed', '^TNamed$', TNamedPrinter)
+   pp.add_printer('TString', '^TString$', TStringPrinter)  
+   
+   return pp
+
+
+gdb.printing.register_pretty_printer(gdb.current_objfile(),
+    build_pretty_printer())
diff --git a/build/gdbPrinters/libRooFitCore.so-gdb.py b/build/gdbPrinters/libRooFitCore.so-gdb.py
new file mode 100644
index 00000000000..28d1e268fb5
--- /dev/null
+++ b/build/gdbPrinters/libRooFitCore.so-gdb.py
@@ -0,0 +1,136 @@
+# Pretty printers for gdb
+# \author: Stephan Hageboeck, CERN
+# These pretty printers will make ROOT objects more readable when printed in gdb.
+# If the pretty-printed output is not sufficient, one can always use "print /r <object>"
+# for raw printing.
+#
+# When a debug build is used, they will be installed next to the ROOT libraries.
+# gdb will load them automatically if the auto-load-safe-path is set to ROOT's library directory.
+# For this, one has to add `add-auto-load-safe-path <ROOT lib dir>` to .gdbinit
+#
+# If loaded successfully, typing `info pretty-printer` at the gdb prompt should list the
+# printers registered at the end of this file.
+
+import gdb
+
+
+class RooCollectionPrinter(object):
+   "Print a RooAbsCollection"
+
+   def __init__(self, val):
+      self.val = val
+      self.viz = gdb.default_visualizer(self.val['_list'])
+      
+   def to_string(self):
+      ret = "{" + str(self.val.dynamic_type) + " " + str(self.val['_name']) +": "
+      try:
+         for name,val in self.viz.children():
+            itemName = val.referenced_value()['fName']
+            ret += str(itemName) + ","
+      except:
+         ret += "<exception " + str(sys.exc_info()[0]) + ">,"
+            
+      ret += "}"
+      return ret
+      
+   def children(self):
+      for name,val in self.viz.children():
+         try:
+            itemName = val.referenced_value()['fName']
+            key = name + " " + str(val.address) + " (" + str(val.dynamic_type) +") " + str(itemName)
+            yield key, val.referenced_value()
+         except:
+#            print("<exception " + str(sys.exc_info()[0]) + ">,")
+            raise
+
+   def display_hint(self):
+      return 'RooAbsCollection printer'
+
+
+        
+class RooSpanPrinter(object):
+   "Print a RooSpan"
+
+   def __init__(self, val):
+      self.val = val
+      
+   def to_string(self):
+      return "span of length " + str(self.val['_span']['length_'])
+      
+   def children(self):
+      length = self.val['_span']['length_']
+      values = ""
+      for i in range(0, min(length, 10)):
+         values += ' ' + str((self.val['_span']['data_']+i).dereference())
+      yield 'Values', values + '...'
+      yield 'Aux storage', self.val['_auxStorage']
+
+   def display_hint(self):
+      return 'RooSpan printer'
+
+
+        
+class RooAbsArgPrinter(object):
+   "Print a RooAbsArg"
+
+   def __init__(self, val):
+      self.val = val
+      
+   def children(self):
+      for name,item in self.val.fields():
+         yield name, item
+
+   def to_string(self):
+      ret += str(self.val.address) + " " + str(self.val.dynamic_type)
+      itemName = self.val['fName']
+      ret += " = { <fName> = {" + str(itemName) + "} }"
+      return ret
+
+   def display_hint(self):
+      return 'RooAbsArg printer'
+
+
+      
+class RooSTLRefCountListPrinter(object):
+   "Print ref count lists"
+   
+   def __init__(self, val):
+      self.val = val
+      
+   def to_string(self):
+      ret = "{"
+      viz = gdb.default_visualizer(self.val['_storage'])
+      vizRC = gdb.default_visualizer(self.val['_refCount'])
+      for (name,val), (name2,val2) in zip(viz.children(), vizRC.children()):
+         ret += str(val['fName']) + ": " + str(val2) + ", "
+      return ret + "}"
+      
+
+
+class NonePrinter(object):
+   "Prevent printing an object"
+
+   def __init__(self, val):
+      self.val = val
+
+   def to_string(self):
+      return ""
+
+   def display_hint(self):
+      return 'Disables printing'
+
+
+
+
+def build_pretty_printer():
+   pp = gdb.printing.RegexpCollectionPrettyPrinter("libRooFitCore")
+   pp.add_printer('RooSpan', '^RooSpan.*$', RooSpanPrinter)
+   pp.add_printer('Collections', '^Roo(AbsCollection|ArgList|ArgSet)$', RooCollectionPrinter)
+   pp.add_printer('RooSTLRefCountList', '^RooSTLRefCountList.*$', RooSTLRefCountListPrinter)
+   pp.add_printer('RooPrintable', '^RooPrintable$', NonePrinter)
+
+   return pp
+
+
+gdb.printing.register_pretty_printer(gdb.current_objfile(),
+    build_pretty_printer())
-- 
GitLab