Add GDB pretty printers for llvm::ilist, llvm::simple_ilist, and llvm::ilist_node.
authorChristian Sigg <csigg@google.com>
Tue, 28 Jan 2020 21:02:17 +0000 (22:02 +0100)
committerChristian Sigg <csigg@google.com>
Thu, 30 Jan 2020 08:35:49 +0000 (09:35 +0100)
Reviewers: dblaikie

Reviewed By: dblaikie

Subscribers: merge_guards_bot, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D72589

debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.cpp
debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.gdb
llvm/utils/gdb-scripts/prettyprinters.py

index bb0e02d..ed556ec 100644 (file)
@@ -6,6 +6,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/ADT/ilist.h"
 #include "llvm/Support/Error.h"
 
 int Array[] = {1, 2, 3};
@@ -25,4 +26,25 @@ llvm::Twine Twine = llvm::Twine(SmallString) + StringRef;
 llvm::PointerIntPair<int *, 1> PointerIntPair(IntPtr, 1);
 llvm::PointerUnion<float *, int *> PointerUnion(IntPtr);
 
+using IlistTag = llvm::ilist_tag<struct A>;
+using SimpleIlistTag = llvm::ilist_tag<struct B>;
+struct IlistNode : llvm::ilist_node<IlistNode, IlistTag>,
+                   llvm::ilist_node<IlistNode, SimpleIlistTag> {
+  int Value;
+};
+auto Ilist = [] {
+  llvm::ilist<IlistNode, IlistTag> Result;
+  for (int I : {13, 14, 15}) {
+    Result.push_back(new IlistNode);
+    Result.back().Value = I;
+  }
+  return Result;
+}();
+auto SimpleIlist = []() {
+  llvm::simple_ilist<IlistNode, SimpleIlistTag> Result;
+  for (auto &Node : Ilist)
+    Result.push_front(Node);
+  return Result;
+}();
+
 int main() { return 0; }
index d6e8164..12baa6e 100644 (file)
@@ -45,4 +45,85 @@ p PointerIntPair
 # CHECK: llvm::PointerUnion containing int * = {pointer = 0xabc}
 p PointerUnion
 
-
+# Switch to print pretty adds newlines to the following statements.
+set print pretty
+
+# CHECK: {
+# CHECK:   [0] = {
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<A> >> = {
+# CHECK:       prev = [[Ilist_Sentinel:0x.*]] <Ilist>,
+# CHECK:       next = [[Node_14:0x.*]]
+# CHECK:     },
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<B> >> = {
+# CHECK:       prev = [[Node_14]],
+# CHECK:       next = [[SimpleIlist_Sentinel:0x.*]] <SimpleIlist>
+# CHECK:     },
+# CHECK:     members of IlistNode:
+# CHECK:     Value = 13
+# CHECK:   },
+# CHECK:   [1] = {
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<A> >> = {
+# CHECK:       prev = [[Node_13:0x.*]],
+# CHECK:       next = [[Node_15:0x.*]]
+# CHECK:     },
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<B> >> = {
+# CHECK:       prev = [[Node_15]],
+# CHECK:       next = [[Node_13]]
+# CHECK:     },
+# CHECK:     members of IlistNode:
+# CHECK:     Value = 14
+# CHECK:   },
+# CHECK:   [2] = {
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<A> >> = {
+# CHECK:       prev = [[Node_14]],
+# CHECK:       next = [[Ilist_Sentinel]] <Ilist>
+# CHECK:     },
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<B> >> = {
+# CHECK:       prev = [[SimpleIlist_Sentinel]] <SimpleIlist>,
+# CHECK:       next = [[Node_14]]
+# CHECK:     },
+# CHECK:     members of IlistNode:
+# CHECK:     Value = 15
+# CHECK:   }
+# CHECK: }
+p Ilist
+
+# CHECK: {
+# CHECK:   [0] = {
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<A> >> = {
+# CHECK:       prev = [[Node_14]],
+# CHECK:       next = [[Ilist_Sentinel]] <Ilist>
+# CHECK:     },
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<B> >> = {
+# CHECK:       prev = [[SimpleIlist_Sentinel]] <SimpleIlist>,
+# CHECK:       next = [[Node_14]]
+# CHECK:     },
+# CHECK:     members of IlistNode:
+# CHECK:     Value = 15
+# CHECK:   },
+# CHECK:   [1] = {
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<A> >> = {
+# CHECK:       prev = [[Node_13]],
+# CHECK:       next = [[Node_15]]
+# CHECK:     },
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<B> >> = {
+# CHECK:       prev = [[Node_15]],
+# CHECK:       next = [[Node_13]]
+# CHECK:     },
+# CHECK:     members of IlistNode:
+# CHECK:     Value = 14
+# CHECK:   },
+# CHECK:   [2] = {
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<A> >> = {
+# CHECK:       prev = [[Ilist_Sentinel]] <Ilist>,
+# CHECK:       next = [[Node_14]]
+# CHECK:     },
+# CHECK:     <llvm::ilist_node<IlistNode, llvm::ilist_tag<B> >> = {
+# CHECK:       prev = [[Node_14]],
+# CHECK:       next = [[SimpleIlist_Sentinel]] <SimpleIlist>
+# CHECK:     },
+# CHECK:     members of IlistNode:
+# CHECK:     Value = 13
+# CHECK:   }
+# CHECK: }
+p SimpleIlist
index a994f08..963be17 100644 (file)
@@ -365,6 +365,66 @@ def make_pointer_union_printer(val):
   string = 'llvm::PointerUnion containing %s' % pointer_type
   return make_printer(string, [('pointer', pointer.cast(pointer_type))])
 
+class IlistNodePrinter:
+  """Print an llvm::ilist_node object."""
+
+  def __init__(self, val):
+    impl_type = val.type.fields()[0].type
+    base_type = impl_type.fields()[0].type
+    derived_type = val.type.template_argument(0)
+
+    def get_prev_and_sentinel(base):
+      # One of Prev and PrevAndSentinel exists. Depending on #defines used to
+      # compile LLVM, the base_type's template argument is either true of false.
+      if base_type.template_argument(0):
+        return get_pointer_int_pair(base['PrevAndSentinel'])
+      return base['Prev'], None
+
+    # Casts a base_type pointer to the appropriate derived type.
+    def cast_pointer(pointer):
+      sentinel = get_prev_and_sentinel(pointer.dereference())[1]
+      pointer = pointer.cast(impl_type.pointer())
+      if sentinel:
+          return pointer
+      return pointer.cast(derived_type.pointer())
+
+    # Repeated cast becaue val.type's base_type is ambiguous when using tags.
+    base = val.cast(impl_type).cast(base_type)
+    (prev, sentinel) = get_prev_and_sentinel(base)
+    prev = prev.cast(base_type.pointer())
+    self.prev = cast_pointer(prev)
+    self.next = cast_pointer(val['Next'])
+    self.sentinel = sentinel
+
+  def children(self):
+    if self.sentinel:
+      yield 'sentinel', 'yes'
+    yield 'prev', self.prev
+    yield 'next', self.next
+
+class IlistPrinter:
+  """Print an llvm::simple_ilist or llvm::iplist object."""
+
+  def __init__(self, val):
+    self.node_type = val.type.template_argument(0)
+    sentinel = val['Sentinel']
+    # First field is common base type of sentinel and ilist_node.
+    base_type = sentinel.type.fields()[0].type
+    self.sentinel = sentinel.address.cast(base_type.pointer())
+
+  def _pointers(self):
+    pointer = self.sentinel
+    while True:
+      pointer = pointer['Next'].cast(pointer.type)
+      if pointer == self.sentinel:
+        return
+      yield pointer.cast(self.node_type.pointer())
+
+  def children(self):
+    for k, v in enumerate(self._pointers()):
+      yield ('[%d]' % k, v.dereference())
+
+
 pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport")
 pp.add_printer('llvm::SmallString', '^llvm::SmallString<.*>$', SmallStringPrinter)
 pp.add_printer('llvm::StringRef', '^llvm::StringRef$', StringRefPrinter)
@@ -376,4 +436,7 @@ pp.add_printer('llvm::DenseMap', '^llvm::DenseMap<.*>$', DenseMapPrinter)
 pp.add_printer('llvm::Twine', '^llvm::Twine$', TwinePrinter)
 pp.add_printer('llvm::PointerIntPair', '^llvm::PointerIntPair<.*>$', make_pointer_int_pair_printer)
 pp.add_printer('llvm::PointerUnion', '^llvm::PointerUnion<.*>$', make_pointer_union_printer)
+pp.add_printer('llvm::ilist_node', '^llvm::ilist_node<.*>$', IlistNodePrinter)
+pp.add_printer('llvm::iplist', '^llvm::iplist<.*>$', IlistPrinter)
+pp.add_printer('llvm::simple_ilist', '^llvm::simple_ilist<.*>$', IlistPrinter)
 gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)