brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.8 KiB · 9a85697 Raw
538 lines · python
1from __future__ import print_function2import struct3import sys4 5import gdb.printing6import gdb.types7 8 9class Iterator:10    def __iter__(self):11        return self12 13    if sys.version_info.major == 2:14 15        def next(self):16            return self.__next__()17 18    def children(self):19        return self20 21 22class SmallStringPrinter:23    """Print an llvm::SmallString object."""24 25    def __init__(self, val):26        self.val = val27 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 = val42 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 = val57        t = val.type.template_argument(0).pointer()58        self.begin = val["BeginX"].cast(t)59        self.size = val["Size"]60        self.i = 061 62    def __next__(self):63        if self.i == self.size:64            raise StopIteration65        ret = "[{}]".format(self.i), (self.begin + self.i).dereference()66        self.i += 167        return ret68 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 = begin84            self.end = end85            self.count = 086 87        def __iter__(self):88            return self89 90        def __next__(self):91            if self.cur == self.end:92                raise StopIteration93            count = self.count94            self.count = self.count + 195            cur = self.cur96            self.cur = self.cur + 197            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 = val104 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 = val121 122    def __next__(self):123        val = self.val124        if val is None:125            raise StopIteration126        self.val = None127        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 DenseMapPrinter:146    "Print a DenseMap"147 148    class _iterator:149        def __init__(self, key_info_t, begin, end):150            self.key_info_t = key_info_t151            self.cur = begin152            self.end = end153            self.advancePastEmptyBuckets()154            self.first = True155 156        def __iter__(self):157            return self158 159        def advancePastEmptyBuckets(self):160            # disabled until the comments below can be addressed161            # keeping as notes/posterity/hints for future contributors162            return163            n = self.key_info_t.name164            is_equal = gdb.parse_and_eval(n + "::isEqual")165            empty = gdb.parse_and_eval(n + "::getEmptyKey()")166            tombstone = gdb.parse_and_eval(n + "::getTombstoneKey()")167            # the following is invalid, GDB fails with:168            #   Python Exception <class 'gdb.error'> Attempt to take address of value169            #   not located in memory.170            # because isEqual took parameter (for the unsigned long key I was testing)171            # by const ref, and GDB172            # It's also not entirely general - we should be accessing the "getFirst()"173            # member function, not the 'first' member variable, but I've yet to figure174            # out how to find/call member functions (especially (const) overloaded175            # ones) on a gdb.Value.176            while self.cur != self.end and (177                is_equal(self.cur.dereference()["first"], empty)178                or is_equal(self.cur.dereference()["first"], tombstone)179            ):180                self.cur = self.cur + 1181 182        def __next__(self):183            if self.cur == self.end:184                raise StopIteration185            cur = self.cur186            v = cur.dereference()["first" if self.first else "second"]187            if not self.first:188                self.cur = self.cur + 1189                self.advancePastEmptyBuckets()190                self.first = True191            else:192                self.first = False193            return "x", v194 195        if sys.version_info.major == 2:196            next = __next__197 198    def __init__(self, val):199        self.val = val200 201    def children(self):202        t = self.val.type.template_argument(3).pointer()203        begin = self.val["Buckets"].cast(t)204        end = (begin + self.val["NumBuckets"]).cast(t)205        return self._iterator(self.val.type.template_argument(2), begin, end)206 207    def to_string(self):208        return "llvm::DenseMap with %d elements" % (self.val["NumEntries"])209 210    def display_hint(self):211        return "map"212 213 214class StringMapPrinter:215    "Print a StringMap"216 217    def __init__(self, val):218        self.val = val219 220    def children(self):221        it = self.val["TheTable"]222        end = it + self.val["NumBuckets"]223        value_ty = self.val.type.template_argument(0)224        entry_base_ty = gdb.lookup_type("llvm::StringMapEntryBase")225        tombstone = gdb.parse_and_eval("llvm::StringMapImpl::TombstoneIntVal")226 227        while it != end:228            it_deref = it.dereference()229            if it_deref == 0 or it_deref == tombstone:230                it = it + 1231                continue232 233            entry_ptr = it_deref.cast(entry_base_ty.pointer())234            entry = entry_ptr.dereference()235 236            str_len = entry["keyLength"]237            value_ptr = (entry_ptr + 1).cast(value_ty.pointer())238            str_data = (entry_ptr + 1).cast(gdb.lookup_type("uintptr_t")) + max(239                value_ty.sizeof, entry_base_ty.alignof240            )241            str_data = str_data.cast(gdb.lookup_type("char").const().pointer())242            string_ref = gdb.Value(243                struct.pack("PN", int(str_data), int(str_len)),244                gdb.lookup_type("llvm::StringRef"),245            )246            yield "key", string_ref247 248            value = value_ptr.dereference()249            yield "value", value250 251            it = it + 1252 253    def to_string(self):254        return "llvm::StringMap with %d elements" % (self.val["NumItems"])255 256    def display_hint(self):257        return "map"258 259 260class TwinePrinter:261    "Print a Twine"262 263    def __init__(self, val):264        self._val = val265 266    def display_hint(self):267        return "string"268 269    def string_from_pretty_printer_lookup(self, val):270        """Lookup the default pretty-printer for val and use it.271 272        If no pretty-printer is defined for the type of val, print an error and273        return a placeholder string."""274 275        pp = gdb.default_visualizer(val)276        if pp:277            s = pp.to_string()278 279            # The pretty-printer may return a LazyString instead of an actual Python280            # string.  Convert it to a Python string.  However, GDB doesn't seem to281            # register the LazyString type, so we can't check282            # "type(s) == gdb.LazyString".283            if "LazyString" in type(s).__name__:284                s = s.value().string()285 286        else:287            print(288                (289                    "No pretty printer for {} found. The resulting Twine "290                    + "representation will be incomplete."291                ).format(val.type.name)292            )293            s = "(missing {})".format(val.type.name)294 295        return s296 297    def is_twine_kind(self, kind, expected):298        if not kind.endswith(expected):299            return False300        # apparently some GDB versions add the NodeKind:: namespace301        # (happens for me on GDB 7.11)302        return kind in (303            "llvm::Twine::" + expected,304            "llvm::Twine::NodeKind::" + expected,305        )306 307    def string_from_child(self, child, kind):308        """Return the string representation of the Twine::Child child."""309 310        if self.is_twine_kind(kind, "EmptyKind") or self.is_twine_kind(311            kind, "NullKind"312        ):313            return ""314 315        if self.is_twine_kind(kind, "TwineKind"):316            return self.string_from_twine_object(child["twine"].dereference())317 318        if self.is_twine_kind(kind, "CStringKind"):319            return child["cString"].string()320 321        if self.is_twine_kind(kind, "StdStringKind"):322            val = child["stdString"].dereference()323            return self.string_from_pretty_printer_lookup(val)324 325        if self.is_twine_kind(kind, "PtrAndLengthKind"):326            val = child["ptrAndLength"]327            data = val["ptr"]328            length = val["length"]329            return data.string(length=length)330 331        if self.is_twine_kind(kind, "CharKind"):332            return chr(child["character"])333 334        if self.is_twine_kind(kind, "DecUIKind"):335            return str(child["decUI"])336 337        if self.is_twine_kind(kind, "DecIKind"):338            return str(child["decI"])339 340        if self.is_twine_kind(kind, "DecULKind"):341            return str(child["decUL"].dereference())342 343        if self.is_twine_kind(kind, "DecLKind"):344            return str(child["decL"].dereference())345 346        if self.is_twine_kind(kind, "DecULLKind"):347            return str(child["decULL"].dereference())348 349        if self.is_twine_kind(kind, "DecLLKind"):350            return str(child["decLL"].dereference())351 352        if self.is_twine_kind(kind, "UHexKind"):353            val = child["uHex"].dereference()354            return hex(int(val))355 356        print(357            (358                "Unhandled NodeKind {} in Twine pretty-printer. The result will be "359                "incomplete."360            ).format(kind)361        )362 363        return "(unhandled {})".format(kind)364 365    def string_from_twine_object(self, twine):366        """Return the string representation of the Twine object twine."""367 368        lhs = twine["LHS"]369        rhs = twine["RHS"]370 371        lhs_kind = str(twine["LHSKind"])372        rhs_kind = str(twine["RHSKind"])373 374        lhs_str = self.string_from_child(lhs, lhs_kind)375        rhs_str = self.string_from_child(rhs, rhs_kind)376 377        return lhs_str + rhs_str378 379    def to_string(self):380        return self.string_from_twine_object(self._val)381 382    def display_hint(self):383        return "string"384 385 386def get_pointer_int_pair(val):387    """Get tuple from llvm::PointerIntPair."""388    info_name = val.type.template_argument(4).strip_typedefs().name389    # Note: this throws a gdb.error if the info type is not used (by means of a390    # call to getPointer() or similar) in the current translation unit.391    enum_type = gdb.lookup_type(info_name + "::MaskAndShiftConstants")392    enum_dict = gdb.types.make_enum_dict(enum_type)393    ptr_mask = enum_dict[info_name + "::PointerBitMask"]394    int_shift = enum_dict[info_name + "::IntShift"]395    int_mask = enum_dict[info_name + "::IntMask"]396    pair_union = val["Value"]397    value_type = pair_union.type.template_argument(0)398    value_type_ptr = value_type.pointer()399    pair_union = pair_union.address.cast(value_type_ptr).dereference()400    pair_union = pair_union.cast(gdb.lookup_type("intptr_t"))401    pointer = pair_union & ptr_mask402    pointer = pointer.cast(value_type)403    value = (pair_union >> int_shift) & int_mask404    return (pointer, value)405 406 407class PointerIntPairPrinter:408    """Print a PointerIntPair."""409 410    def __init__(self, pointer, value):411        self.pointer = pointer412        self.value = value413 414    def children(self):415        yield ("pointer", self.pointer)416        yield ("value", self.value)417 418    def to_string(self):419        return "(%s, %s)" % (self.pointer.type, self.value.type)420 421 422def make_pointer_int_pair_printer(val):423    """Factory for an llvm::PointerIntPair printer."""424    try:425        pointer, value = get_pointer_int_pair(val)426    except gdb.error:427        return None  # If PointerIntPair cannot be analyzed, print as raw value.428    pointer_type = val.type.template_argument(0)429    value_type = val.type.template_argument(2)430    return PointerIntPairPrinter(pointer.cast(pointer_type), value.cast(value_type))431 432 433class PointerUnionPrinter:434    """Print a PointerUnion."""435 436    def __init__(self, pointer):437        self.pointer = pointer438 439    def children(self):440        yield ("pointer", self.pointer)441 442    def to_string(self):443        return "Containing %s" % self.pointer.type444 445 446def make_pointer_union_printer(val):447    """Factory for an llvm::PointerUnion printer."""448    try:449        pointer, value = get_pointer_int_pair(val["Val"])450    except gdb.error:451        return None  # If PointerIntPair cannot be analyzed, print as raw value.452    pointer_type = val.type.template_argument(int(value))453    return PointerUnionPrinter(pointer.cast(pointer_type))454 455 456class IlistNodePrinter:457    """Print an llvm::ilist_node object."""458 459    def __init__(self, val):460        impl_type = val.type.fields()[0].type461        base_type = impl_type.fields()[0].type462        derived_type = val.type.template_argument(0)463 464        def get_prev_and_sentinel(base):465            # One of Prev and PrevAndSentinel exists. Depending on #defines used to466            # compile LLVM, the base_type's template argument is either true of false.467            if base_type.template_argument(0):468                return get_pointer_int_pair(base["PrevAndSentinel"])469            return base["Prev"], None470 471        # Casts a base_type pointer to the appropriate derived type.472        def cast_pointer(pointer):473            sentinel = get_prev_and_sentinel(pointer.dereference())[1]474            pointer = pointer.cast(impl_type.pointer())475            if sentinel:476                return pointer477            return pointer.cast(derived_type.pointer())478 479        # Repeated cast becaue val.type's base_type is ambiguous when using tags.480        base = val.cast(impl_type).cast(base_type)481        (prev, sentinel) = get_prev_and_sentinel(base)482        prev = prev.cast(base_type.pointer())483        self.prev = cast_pointer(prev)484        self.next = cast_pointer(val["Next"])485        self.sentinel = sentinel486 487    def children(self):488        if self.sentinel:489            yield "sentinel", "yes"490        yield "prev", self.prev491        yield "next", self.next492 493 494class IlistPrinter:495    """Print an llvm::simple_ilist or llvm::iplist object."""496 497    def __init__(self, val):498        self.node_type = val.type.template_argument(0)499        sentinel = val["Sentinel"]500        # First field is common base type of sentinel and ilist_node.501        base_type = sentinel.type.fields()[0].type502        self.sentinel = sentinel.address.cast(base_type.pointer())503 504    def _pointers(self):505        pointer = self.sentinel506        while True:507            pointer = pointer["Next"].cast(pointer.type)508            if pointer == self.sentinel:509                return510            yield pointer.cast(self.node_type.pointer())511 512    def children(self):513        for k, v in enumerate(self._pointers()):514            yield ("[%d]" % k, v.dereference())515 516 517pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport")518pp.add_printer("llvm::SmallString", "^llvm::SmallString<.*>$", SmallStringPrinter)519pp.add_printer("llvm::StringRef", "^llvm::StringRef$", StringRefPrinter)520pp.add_printer(521    "llvm::SmallVectorImpl", "^llvm::SmallVector(Impl)?<.*>$", SmallVectorPrinter522)523pp.add_printer("llvm::ArrayRef", "^llvm::(Mutable)?ArrayRef<.*>$", ArrayRefPrinter)524pp.add_printer("llvm::Expected", "^llvm::Expected<.*>$", ExpectedPrinter)525pp.add_printer("llvm::DenseMap", "^llvm::DenseMap<.*>$", DenseMapPrinter)526pp.add_printer("llvm::StringMap", "^llvm::StringMap<.*>$", StringMapPrinter)527pp.add_printer("llvm::Twine", "^llvm::Twine$", TwinePrinter)528pp.add_printer(529    "llvm::PointerIntPair", "^llvm::PointerIntPair<.*>$", make_pointer_int_pair_printer530)531pp.add_printer(532    "llvm::PointerUnion", "^llvm::PointerUnion<.*>$", make_pointer_union_printer533)534pp.add_printer("llvm::ilist_node", "^llvm::ilist_node<.*>$", IlistNodePrinter)535pp.add_printer("llvm::iplist", "^llvm::iplist<.*>$", IlistPrinter)536pp.add_printer("llvm::simple_ilist", "^llvm::simple_ilist<.*>$", IlistPrinter)537gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)538