xref: /llvm-project/llvm/utils/gdb-scripts/prettyprinters.py (revision 1c9a81b2bd91e8cd9baf742fa66650eefbaf552c)
1from __future__ import print_function
2import struct
3import sys
4
5import gdb.printing
6import gdb.types
7
8
9class Iterator:
10    def __iter__(self):
11        return self
12
13    if sys.version_info.major == 2:
14
15        def next(self):
16            return self.__next__()
17
18    def children(self):
19        return self
20
21
22class SmallStringPrinter:
23    """Print an llvm::SmallString object."""
24
25    def __init__(self, val):
26        self.val = val
27
28    def to_string(self):
29        data = self.val["BeginX"].cast(gdb.lookup_type("char").pointer())
30        length = self.val["Size"]
31        return data.lazy_string(length=length)
32
33    def display_hint(self):
34        return "string"
35
36
37class StringRefPrinter:
38    """Print an llvm::StringRef object."""
39
40    def __init__(self, val):
41        self.val = val
42
43    def to_string(self):
44        data = self.val["Data"]
45        length = self.val["Length"]
46        return data.lazy_string(length=length)
47
48    def display_hint(self):
49        return "string"
50
51
52class SmallVectorPrinter(Iterator):
53    """Print an llvm::SmallVector object."""
54
55    def __init__(self, val):
56        self.val = val
57        t = val.type.template_argument(0).pointer()
58        self.begin = val["BeginX"].cast(t)
59        self.size = val["Size"]
60        self.i = 0
61
62    def __next__(self):
63        if self.i == self.size:
64            raise StopIteration
65        ret = "[{}]".format(self.i), (self.begin + self.i).dereference()
66        self.i += 1
67        return ret
68
69    def to_string(self):
70        return "llvm::SmallVector of Size {}, Capacity {}".format(
71            self.size, self.val["Capacity"]
72        )
73
74    def display_hint(self):
75        return "array"
76
77
78class ArrayRefPrinter:
79    """Print an llvm::ArrayRef object."""
80
81    class _iterator:
82        def __init__(self, begin, end):
83            self.cur = begin
84            self.end = end
85            self.count = 0
86
87        def __iter__(self):
88            return self
89
90        def __next__(self):
91            if self.cur == self.end:
92                raise StopIteration
93            count = self.count
94            self.count = self.count + 1
95            cur = self.cur
96            self.cur = self.cur + 1
97            return "[%d]" % count, cur.dereference()
98
99        if sys.version_info.major == 2:
100            next = __next__
101
102    def __init__(self, val):
103        self.val = val
104
105    def children(self):
106        data = self.val["Data"]
107        return self._iterator(data, data + self.val["Length"])
108
109    def to_string(self):
110        return "llvm::ArrayRef of length %d" % (self.val["Length"])
111
112    def display_hint(self):
113        return "array"
114
115
116class ExpectedPrinter(Iterator):
117    """Print an llvm::Expected object."""
118
119    def __init__(self, val):
120        self.val = val
121
122    def __next__(self):
123        val = self.val
124        if val is None:
125            raise StopIteration
126        self.val = None
127        if val["HasError"]:
128            return (
129                "error",
130                val["ErrorStorage"]
131                .address.cast(gdb.lookup_type("llvm::ErrorInfoBase").pointer())
132                .dereference(),
133            )
134        return (
135            "value",
136            val["TStorage"]
137            .address.cast(val.type.template_argument(0).pointer())
138            .dereference(),
139        )
140
141    def to_string(self):
142        return "llvm::Expected{}".format(" is error" if self.val["HasError"] else "")
143
144
145class OptionalPrinter(Iterator):
146    """Print an llvm::Optional object."""
147
148    def __init__(self, val):
149        self.val = val
150
151    def __next__(self):
152        val = self.val
153        if val is None:
154            raise StopIteration
155        self.val = None
156        if not val["Storage"]["hasVal"]:
157            raise StopIteration
158        return ("value", val["Storage"]["val"])
159
160    def to_string(self):
161        return "llvm::Optional{}".format(
162            "" if self.val["Storage"]["hasVal"] else " is not initialized"
163        )
164
165
166class DenseMapPrinter:
167    "Print a DenseMap"
168
169    class _iterator:
170        def __init__(self, key_info_t, begin, end):
171            self.key_info_t = key_info_t
172            self.cur = begin
173            self.end = end
174            self.advancePastEmptyBuckets()
175            self.first = True
176
177        def __iter__(self):
178            return self
179
180        def advancePastEmptyBuckets(self):
181            # disabled until the comments below can be addressed
182            # keeping as notes/posterity/hints for future contributors
183            return
184            n = self.key_info_t.name
185            is_equal = gdb.parse_and_eval(n + "::isEqual")
186            empty = gdb.parse_and_eval(n + "::getEmptyKey()")
187            tombstone = gdb.parse_and_eval(n + "::getTombstoneKey()")
188            # the following is invalid, GDB fails with:
189            #   Python Exception <class 'gdb.error'> Attempt to take address of value
190            #   not located in memory.
191            # because isEqual took parameter (for the unsigned long key I was testing)
192            # by const ref, and GDB
193            # It's also not entirely general - we should be accessing the "getFirst()"
194            # member function, not the 'first' member variable, but I've yet to figure
195            # out how to find/call member functions (especially (const) overloaded
196            # ones) on a gdb.Value.
197            while self.cur != self.end and (
198                is_equal(self.cur.dereference()["first"], empty)
199                or is_equal(self.cur.dereference()["first"], tombstone)
200            ):
201                self.cur = self.cur + 1
202
203        def __next__(self):
204            if self.cur == self.end:
205                raise StopIteration
206            cur = self.cur
207            v = cur.dereference()["first" if self.first else "second"]
208            if not self.first:
209                self.cur = self.cur + 1
210                self.advancePastEmptyBuckets()
211                self.first = True
212            else:
213                self.first = False
214            return "x", v
215
216        if sys.version_info.major == 2:
217            next = __next__
218
219    def __init__(self, val):
220        self.val = val
221
222    def children(self):
223        t = self.val.type.template_argument(3).pointer()
224        begin = self.val["Buckets"].cast(t)
225        end = (begin + self.val["NumBuckets"]).cast(t)
226        return self._iterator(self.val.type.template_argument(2), begin, end)
227
228    def to_string(self):
229        return "llvm::DenseMap with %d elements" % (self.val["NumEntries"])
230
231    def display_hint(self):
232        return "map"
233
234
235class StringMapPrinter:
236    "Print a StringMap"
237
238    def __init__(self, val):
239        self.val = val
240
241    def children(self):
242        it = self.val["TheTable"]
243        end = it + self.val["NumBuckets"]
244        value_ty = self.val.type.template_argument(0)
245        entry_base_ty = gdb.lookup_type("llvm::StringMapEntryBase")
246        tombstone = gdb.parse_and_eval("llvm::StringMapImpl::TombstoneIntVal")
247
248        while it != end:
249            it_deref = it.dereference()
250            if it_deref == 0 or it_deref == tombstone:
251                it = it + 1
252                continue
253
254            entry_ptr = it_deref.cast(entry_base_ty.pointer())
255            entry = entry_ptr.dereference()
256
257            str_len = entry["keyLength"]
258            value_ptr = (entry_ptr + 1).cast(value_ty.pointer())
259            str_data = (entry_ptr + 1).cast(gdb.lookup_type("uintptr_t")) + max(
260                value_ty.sizeof, entry_base_ty.alignof
261            )
262            str_data = str_data.cast(gdb.lookup_type("char").const().pointer())
263            string_ref = gdb.Value(
264                struct.pack("PN", int(str_data), int(str_len)),
265                gdb.lookup_type("llvm::StringRef"),
266            )
267            yield "key", string_ref
268
269            value = value_ptr.dereference()
270            yield "value", value
271
272            it = it + 1
273
274    def to_string(self):
275        return "llvm::StringMap with %d elements" % (self.val["NumItems"])
276
277    def display_hint(self):
278        return "map"
279
280
281class TwinePrinter:
282    "Print a Twine"
283
284    def __init__(self, val):
285        self._val = val
286
287    def display_hint(self):
288        return "string"
289
290    def string_from_pretty_printer_lookup(self, val):
291        """Lookup the default pretty-printer for val and use it.
292
293        If no pretty-printer is defined for the type of val, print an error and
294        return a placeholder string."""
295
296        pp = gdb.default_visualizer(val)
297        if pp:
298            s = pp.to_string()
299
300            # The pretty-printer may return a LazyString instead of an actual Python
301            # string.  Convert it to a Python string.  However, GDB doesn't seem to
302            # register the LazyString type, so we can't check
303            # "type(s) == gdb.LazyString".
304            if "LazyString" in type(s).__name__:
305                s = s.value().string()
306
307        else:
308            print(
309                (
310                    "No pretty printer for {} found. The resulting Twine "
311                    + "representation will be incomplete."
312                ).format(val.type.name)
313            )
314            s = "(missing {})".format(val.type.name)
315
316        return s
317
318    def is_twine_kind(self, kind, expected):
319        if not kind.endswith(expected):
320            return False
321        # apparently some GDB versions add the NodeKind:: namespace
322        # (happens for me on GDB 7.11)
323        return kind in (
324            "llvm::Twine::" + expected,
325            "llvm::Twine::NodeKind::" + expected,
326        )
327
328    def string_from_child(self, child, kind):
329        """Return the string representation of the Twine::Child child."""
330
331        if self.is_twine_kind(kind, "EmptyKind") or self.is_twine_kind(
332            kind, "NullKind"
333        ):
334            return ""
335
336        if self.is_twine_kind(kind, "TwineKind"):
337            return self.string_from_twine_object(child["twine"].dereference())
338
339        if self.is_twine_kind(kind, "CStringKind"):
340            return child["cString"].string()
341
342        if self.is_twine_kind(kind, "StdStringKind"):
343            val = child["stdString"].dereference()
344            return self.string_from_pretty_printer_lookup(val)
345
346        if self.is_twine_kind(kind, "PtrAndLengthKind"):
347            val = child["ptrAndLength"]
348            data = val["ptr"]
349            length = val["length"]
350            return data.string(length=length)
351
352        if self.is_twine_kind(kind, "CharKind"):
353            return chr(child["character"])
354
355        if self.is_twine_kind(kind, "DecUIKind"):
356            return str(child["decUI"])
357
358        if self.is_twine_kind(kind, "DecIKind"):
359            return str(child["decI"])
360
361        if self.is_twine_kind(kind, "DecULKind"):
362            return str(child["decUL"].dereference())
363
364        if self.is_twine_kind(kind, "DecLKind"):
365            return str(child["decL"].dereference())
366
367        if self.is_twine_kind(kind, "DecULLKind"):
368            return str(child["decULL"].dereference())
369
370        if self.is_twine_kind(kind, "DecLLKind"):
371            return str(child["decLL"].dereference())
372
373        if self.is_twine_kind(kind, "UHexKind"):
374            val = child["uHex"].dereference()
375            return hex(int(val))
376
377        print(
378            (
379                "Unhandled NodeKind {} in Twine pretty-printer. The result will be "
380                "incomplete."
381            ).format(kind)
382        )
383
384        return "(unhandled {})".format(kind)
385
386    def string_from_twine_object(self, twine):
387        """Return the string representation of the Twine object twine."""
388
389        lhs = twine["LHS"]
390        rhs = twine["RHS"]
391
392        lhs_kind = str(twine["LHSKind"])
393        rhs_kind = str(twine["RHSKind"])
394
395        lhs_str = self.string_from_child(lhs, lhs_kind)
396        rhs_str = self.string_from_child(rhs, rhs_kind)
397
398        return lhs_str + rhs_str
399
400    def to_string(self):
401        return self.string_from_twine_object(self._val)
402
403    def display_hint(self):
404        return "string"
405
406
407def get_pointer_int_pair(val):
408    """Get tuple from llvm::PointerIntPair."""
409    info_name = val.type.template_argument(4).strip_typedefs().name
410    # Note: this throws a gdb.error if the info type is not used (by means of a
411    # call to getPointer() or similar) in the current translation unit.
412    enum_type = gdb.lookup_type(info_name + "::MaskAndShiftConstants")
413    enum_dict = gdb.types.make_enum_dict(enum_type)
414    ptr_mask = enum_dict[info_name + "::PointerBitMask"]
415    int_shift = enum_dict[info_name + "::IntShift"]
416    int_mask = enum_dict[info_name + "::IntMask"]
417    pair_union = val["Value"]
418    value_type = pair_union.type.template_argument(0)
419    value_type_ptr = value_type.pointer()
420    pair_union = pair_union.address.cast(value_type_ptr).dereference()
421    pair_union = pair_union.cast(gdb.lookup_type("intptr_t"))
422    pointer = pair_union & ptr_mask
423    pointer = pointer.cast(value_type)
424    value = (pair_union >> int_shift) & int_mask
425    return (pointer, value)
426
427
428class PointerIntPairPrinter:
429    """Print a PointerIntPair."""
430
431    def __init__(self, pointer, value):
432        self.pointer = pointer
433        self.value = value
434
435    def children(self):
436        yield ("pointer", self.pointer)
437        yield ("value", self.value)
438
439    def to_string(self):
440        return "(%s, %s)" % (self.pointer.type, self.value.type)
441
442
443def make_pointer_int_pair_printer(val):
444    """Factory for an llvm::PointerIntPair printer."""
445    try:
446        pointer, value = get_pointer_int_pair(val)
447    except gdb.error:
448        return None  # If PointerIntPair cannot be analyzed, print as raw value.
449    pointer_type = val.type.template_argument(0)
450    value_type = val.type.template_argument(2)
451    return PointerIntPairPrinter(pointer.cast(pointer_type), value.cast(value_type))
452
453
454class PointerUnionPrinter:
455    """Print a PointerUnion."""
456
457    def __init__(self, pointer):
458        self.pointer = pointer
459
460    def children(self):
461        yield ("pointer", self.pointer)
462
463    def to_string(self):
464        return "Containing %s" % self.pointer.type
465
466
467def make_pointer_union_printer(val):
468    """Factory for an llvm::PointerUnion printer."""
469    try:
470        pointer, value = get_pointer_int_pair(val["Val"])
471    except gdb.error:
472        return None  # If PointerIntPair cannot be analyzed, print as raw value.
473    pointer_type = val.type.template_argument(int(value))
474    return PointerUnionPrinter(pointer.cast(pointer_type))
475
476
477class IlistNodePrinter:
478    """Print an llvm::ilist_node object."""
479
480    def __init__(self, val):
481        impl_type = val.type.fields()[0].type
482        base_type = impl_type.fields()[0].type
483        derived_type = val.type.template_argument(0)
484
485        def get_prev_and_sentinel(base):
486            # One of Prev and PrevAndSentinel exists. Depending on #defines used to
487            # compile LLVM, the base_type's template argument is either true of false.
488            if base_type.template_argument(0):
489                return get_pointer_int_pair(base["PrevAndSentinel"])
490            return base["Prev"], None
491
492        # Casts a base_type pointer to the appropriate derived type.
493        def cast_pointer(pointer):
494            sentinel = get_prev_and_sentinel(pointer.dereference())[1]
495            pointer = pointer.cast(impl_type.pointer())
496            if sentinel:
497                return pointer
498            return pointer.cast(derived_type.pointer())
499
500        # Repeated cast becaue val.type's base_type is ambiguous when using tags.
501        base = val.cast(impl_type).cast(base_type)
502        (prev, sentinel) = get_prev_and_sentinel(base)
503        prev = prev.cast(base_type.pointer())
504        self.prev = cast_pointer(prev)
505        self.next = cast_pointer(val["Next"])
506        self.sentinel = sentinel
507
508    def children(self):
509        if self.sentinel:
510            yield "sentinel", "yes"
511        yield "prev", self.prev
512        yield "next", self.next
513
514
515class IlistPrinter:
516    """Print an llvm::simple_ilist or llvm::iplist object."""
517
518    def __init__(self, val):
519        self.node_type = val.type.template_argument(0)
520        sentinel = val["Sentinel"]
521        # First field is common base type of sentinel and ilist_node.
522        base_type = sentinel.type.fields()[0].type
523        self.sentinel = sentinel.address.cast(base_type.pointer())
524
525    def _pointers(self):
526        pointer = self.sentinel
527        while True:
528            pointer = pointer["Next"].cast(pointer.type)
529            if pointer == self.sentinel:
530                return
531            yield pointer.cast(self.node_type.pointer())
532
533    def children(self):
534        for k, v in enumerate(self._pointers()):
535            yield ("[%d]" % k, v.dereference())
536
537
538pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport")
539pp.add_printer("llvm::SmallString", "^llvm::SmallString<.*>$", SmallStringPrinter)
540pp.add_printer("llvm::StringRef", "^llvm::StringRef$", StringRefPrinter)
541pp.add_printer(
542    "llvm::SmallVectorImpl", "^llvm::SmallVector(Impl)?<.*>$", SmallVectorPrinter
543)
544pp.add_printer("llvm::ArrayRef", "^llvm::(Mutable)?ArrayRef<.*>$", ArrayRefPrinter)
545pp.add_printer("llvm::Expected", "^llvm::Expected<.*>$", ExpectedPrinter)
546pp.add_printer("llvm::Optional", "^llvm::Optional<.*>$", OptionalPrinter)
547pp.add_printer("llvm::DenseMap", "^llvm::DenseMap<.*>$", DenseMapPrinter)
548pp.add_printer("llvm::StringMap", "^llvm::StringMap<.*>$", StringMapPrinter)
549pp.add_printer("llvm::Twine", "^llvm::Twine$", TwinePrinter)
550pp.add_printer(
551    "llvm::PointerIntPair", "^llvm::PointerIntPair<.*>$", make_pointer_int_pair_printer
552)
553pp.add_printer(
554    "llvm::PointerUnion", "^llvm::PointerUnion<.*>$", make_pointer_union_printer
555)
556pp.add_printer("llvm::ilist_node", "^llvm::ilist_node<.*>$", IlistNodePrinter)
557pp.add_printer("llvm::iplist", "^llvm::iplist<.*>$", IlistPrinter)
558pp.add_printer("llvm::simple_ilist", "^llvm::simple_ilist<.*>$", IlistPrinter)
559gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
560