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 @@ -4,6 +4,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}; @@ -20,6 +21,25 @@ llvm::StringRef StringRef = "bar"; llvm::Twine Twine = llvm::Twine(SmallString) + StringRef; -int main() { - return 0; -} +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 @@ -39,3 +39,12 @@ # CHECK: "\"foo\"\"bar\"" p Twine +# CHECK: Value = 13 +# CHECK: Value = 14 +# CHECK: Value = 15 +p Ilist + +# CHECK: Value = 15 +# CHECK: Value = 14 +# CHECK: Value = 13 +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 @@ -315,6 +315,110 @@ def to_string(self): return self.string_from_twine_object(self._val) +class PointerIntPairPrinter: + """Print an llvm::PointerIntPair object.""" + + def __init__(self, val): + pointer_type = val.type.template_argument(0) + try: + name = val.type.template_argument(3).name + '::NumLowBitsAvailable' + bits_available = gdb.parse_and_eval(name) + except gdb.error: + # Above fails if NumLowBitsAvailable is an enum or is optimized away. + bits_available = pointer_type.target().alignof.bit_length() - 1 + value_mask = (1 << bits_available) - 1 + value_shift = bits_available - val.type.template_argument(1) + value = val['Value'] + self.pointer = (value & ~value_mask).cast(pointer_type) + self.value = (value & value_mask) >> value_shift + + def children(self): + return [('pointer', self.pointer), ('value', self.value)] + + def to_string(self): + return 'llvm::PointerIntPair' + + def display_hint (self): + return 'array' + +class PointerUnionPrinter: + """Print an llvm::PointerUnion object.""" + + def __init__(self, val): + pair_printer = PointerIntPairPrinter(val['Val']) + pointer_type = val.type.template_argument(int(pair_printer.value)) + self.pointer = pair_printer.pointer.cast(pointer_type) + + def children(self): + return [('pointer', self.pointer)] + + def to_string(self): + return 'llvm::PointerUnion containing %s' % self.pointer.type + + def display_hint (self): + return 'array' + +class IlistNodePrinter: + """Print an llvm::ilist_node object.""" + + def __init__(self, val): + pointer_type = val.type.pointer() + try: + pair_printer = PointerIntPairPrinter(val['PrevAndSentinel']) + self.prev = pair_printer.pointer.cast(pointer_type) + self.sentinel = bool(pair_printer.value) + except gdb.error: + # Fall back to base node that doesn't contain sentinel flag. + self.prev = val['Prev'].cast(pointer_type) + self.sentinel = None + self.next = val['Next'].cast(pointer_type) + + def _get_pointer(self, pointer): + printer = IlistNodePrinter(pointer) + if printer.sentinel: + return pointer + node_type = pointer.type.target().template_argument(0) + return pointer.cast(node_type.pointer()) + + def children(self): + if self.sentinel: + yield ('sentinel', 'true') + yield ('prev', self._get_pointer(self.prev)) + yield ('next', self._get_pointer(self.next)) + + def to_string(self): + return 'llvm::ilist_node' + + def display_hint(self): + return 'array' + +class IlistPrinter: + """Print an llvm::simple_ilist or llvm::iplist object.""" + + def __init__(self, val): + self.node_type = val.type.template_argument(0) + # First field is common base type of sentinel and ilist_node. + base_type = val['Sentinel'].type.fields()[0].type + self.sentinel = val['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()) + + def to_string(self): + return 'llvm::ilist' + + def display_hint(self): + return 'array' + pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport") pp.add_printer('llvm::SmallString', '^llvm::SmallString<.*>$', SmallStringPrinter) pp.add_printer('llvm::StringRef', '^llvm::StringRef$', StringRefPrinter) @@ -324,4 +428,9 @@ pp.add_printer('llvm::Optional', '^llvm::Optional<.*>$', OptionalPrinter) pp.add_printer('llvm::DenseMap', '^llvm::DenseMap<.*>$', DenseMapPrinter) pp.add_printer('llvm::Twine', '^llvm::Twine$', TwinePrinter) -gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) +pp.add_printer('llvm::PointerIntPair', '^llvm::PointerIntPair<.*>$', PointerIntPairPrinter) +pp.add_printer('llvm::PointerUnion', '^llvm::PointerUnion<.*>$', PointerUnionPrinter) +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, True)