diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.cpp b/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.cpp --- a/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.cpp +++ b/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.cpp @@ -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::PointerIntPair PointerIntPair(IntPtr, 1); llvm::PointerUnion PointerUnion(IntPtr); +using IlistTag = llvm::ilist_tag; +using SimpleIlistTag = llvm::ilist_tag; +struct IlistNode : llvm::ilist_node, + llvm::ilist_node { + int Value; +}; +auto Ilist = [] { + llvm::ilist Result; + for (int I : {13, 14, 15}) { + Result.push_back(new IlistNode); + Result.back().Value = I; + } + return Result; +}(); +auto SimpleIlist = []() { + llvm::simple_ilist Result; + for (auto &Node : Ilist) + Result.push_front(Node); + return Result; +}(); + int main() { return 0; } diff --git a/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.gdb b/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.gdb --- a/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.gdb +++ b/debuginfo-tests/llvm-prettyprinters/gdb/prettyprinters.gdb @@ -45,4 +45,85 @@ # 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: >> = { +# CHECK: prev = [[Ilist_Sentinel:0x.*]] , +# CHECK: next = [[Node_14:0x.*]] +# CHECK: }, +# CHECK: >> = { +# CHECK: prev = [[Node_14]], +# CHECK: next = [[SimpleIlist_Sentinel:0x.*]] +# CHECK: }, +# CHECK: members of IlistNode: +# CHECK: Value = 13 +# CHECK: }, +# CHECK: [1] = { +# CHECK: >> = { +# CHECK: prev = [[Node_13:0x.*]], +# CHECK: next = [[Node_15:0x.*]] +# CHECK: }, +# CHECK: >> = { +# CHECK: prev = [[Node_15]], +# CHECK: next = [[Node_13]] +# CHECK: }, +# CHECK: members of IlistNode: +# CHECK: Value = 14 +# CHECK: }, +# CHECK: [2] = { +# CHECK: >> = { +# CHECK: prev = [[Node_14]], +# CHECK: next = [[Ilist_Sentinel]] +# CHECK: }, +# CHECK: >> = { +# CHECK: prev = [[SimpleIlist_Sentinel]] , +# CHECK: next = [[Node_14]] +# CHECK: }, +# CHECK: members of IlistNode: +# CHECK: Value = 15 +# CHECK: } +# CHECK: } +p Ilist + +# CHECK: { +# CHECK: [0] = { +# CHECK: >> = { +# CHECK: prev = [[Node_14]], +# CHECK: next = [[Ilist_Sentinel]] +# CHECK: }, +# CHECK: >> = { +# CHECK: prev = [[SimpleIlist_Sentinel]] , +# CHECK: next = [[Node_14]] +# CHECK: }, +# CHECK: members of IlistNode: +# CHECK: Value = 15 +# CHECK: }, +# CHECK: [1] = { +# CHECK: >> = { +# CHECK: prev = [[Node_13]], +# CHECK: next = [[Node_15]] +# CHECK: }, +# CHECK: >> = { +# CHECK: prev = [[Node_15]], +# CHECK: next = [[Node_13]] +# CHECK: }, +# CHECK: members of IlistNode: +# CHECK: Value = 14 +# CHECK: }, +# CHECK: [2] = { +# CHECK: >> = { +# CHECK: prev = [[Ilist_Sentinel]] , +# CHECK: next = [[Node_14]] +# CHECK: }, +# CHECK: >> = { +# CHECK: prev = [[Node_14]], +# CHECK: next = [[SimpleIlist_Sentinel]] +# CHECK: }, +# CHECK: members of IlistNode: +# CHECK: Value = 13 +# CHECK: } +# CHECK: } +p SimpleIlist diff --git a/llvm/utils/gdb-scripts/prettyprinters.py b/llvm/utils/gdb-scripts/prettyprinters.py --- a/llvm/utils/gdb-scripts/prettyprinters.py +++ b/llvm/utils/gdb-scripts/prettyprinters.py @@ -365,6 +365,66 @@ 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::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)