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