1import gdb.printing 2class SmallStringPrinter: 3 """Print an llvm::SmallString object.""" 4 5 def __init__(self, val): 6 self.val = val 7 8 def to_string(self): 9 begin = self.val['BeginX'] 10 end = self.val['EndX'] 11 return begin.cast(gdb.lookup_type("char").pointer()).string(length = end - begin) 12 13 def display_hint (self): 14 return 'string' 15 16class StringRefPrinter: 17 """Print an llvm::StringRef object.""" 18 19 def __init__(self, val): 20 self.val = val 21 22 def to_string(self): 23 return self.val['Data'].string(length = self.val['Length']) 24 25 def display_hint (self): 26 return 'string' 27 28class SmallVectorPrinter: 29 """Print an llvm::SmallVector object.""" 30 31 class _iterator: 32 def __init__(self, begin, end): 33 self.cur = begin 34 self.end = end 35 self.count = 0 36 37 def __iter__(self): 38 return self 39 40 def next(self): 41 if self.cur == self.end: 42 raise StopIteration 43 count = self.count 44 self.count = self.count + 1 45 cur = self.cur 46 self.cur = self.cur + 1 47 return '[%d]' % count, cur.dereference() 48 49 __next__ = next 50 51 def __init__(self, val): 52 self.val = val 53 54 def children(self): 55 t = self.val.type.template_argument(0).pointer() 56 begin = self.val['BeginX'].cast(t) 57 end = self.val['EndX'].cast(t) 58 return self._iterator(begin, end) 59 60 def to_string(self): 61 t = self.val.type.template_argument(0).pointer() 62 begin = self.val['BeginX'].cast(t) 63 end = self.val['EndX'].cast(t) 64 capacity = self.val['CapacityX'].cast(t) 65 return 'llvm::SmallVector of length %d, capacity %d' % (end - begin, capacity - begin) 66 67 def display_hint (self): 68 return 'array' 69 70class ArrayRefPrinter: 71 """Print an llvm::ArrayRef object.""" 72 73 class _iterator: 74 def __init__(self, begin, end): 75 self.cur = begin 76 self.end = end 77 self.count = 0 78 79 def __iter__(self): 80 return self 81 82 def next(self): 83 if self.cur == self.end: 84 raise StopIteration 85 count = self.count 86 self.count = self.count + 1 87 cur = self.cur 88 self.cur = self.cur + 1 89 return '[%d]' % count, cur.dereference() 90 91 __next__ = next 92 93 def __init__(self, val): 94 self.val = val 95 96 def children(self): 97 data = self.val['Data'] 98 return self._iterator(data, data + self.val['Length']) 99 100 def to_string(self): 101 return 'llvm::ArrayRef of length %d' % (self.val['Length']) 102 103 def display_hint (self): 104 return 'array' 105 106class OptionalPrinter: 107 """Print an llvm::Optional object.""" 108 109 def __init__(self, value): 110 self.value = value 111 112 class _iterator: 113 def __init__(self, member, empty): 114 self.member = member 115 self.done = empty 116 117 def __iter__(self): 118 return self 119 120 def next(self): 121 if self.done: 122 raise StopIteration 123 self.done = True 124 return ('value', self.member.dereference()) 125 126 def children(self): 127 if not self.value['Storage']['hasVal']: 128 return self._iterator('', True) 129 return self._iterator(self.value['Storage']['storage']['buffer'].address.cast( 130 self.value.type.template_argument(0).pointer()), False) 131 132 def to_string(self): 133 return 'llvm::Optional is %sinitialized' % ('' if self.value['Storage']['hasVal'] else 'not ') 134 135class DenseMapPrinter: 136 "Print a DenseMap" 137 138 class _iterator: 139 def __init__(self, key_info_t, begin, end): 140 self.key_info_t = key_info_t 141 self.cur = begin 142 self.end = end 143 self.advancePastEmptyBuckets() 144 self.first = True 145 146 def __iter__(self): 147 return self 148 149 def advancePastEmptyBuckets(self): 150 # disabled until the comments below can be addressed 151 # keeping as notes/posterity/hints for future contributors 152 return 153 n = self.key_info_t.name 154 is_equal = gdb.parse_and_eval(n + '::isEqual') 155 empty = gdb.parse_and_eval(n + '::getEmptyKey()') 156 tombstone = gdb.parse_and_eval(n + '::getTombstoneKey()') 157 # the following is invalid, GDB fails with: 158 # Python Exception <class 'gdb.error'> Attempt to take address of value 159 # not located in memory. 160 # because isEqual took parameter (for the unsigned long key I was testing) 161 # by const ref, and GDB 162 # It's also not entirely general - we should be accessing the "getFirst()" 163 # member function, not the 'first' member variable, but I've yet to figure 164 # out how to find/call member functions (especially (const) overloaded 165 # ones) on a gdb.Value. 166 while self.cur != self.end and (is_equal(self.cur.dereference()['first'], empty) or is_equal(self.cur.dereference()['first'], tombstone)): 167 self.cur = self.cur + 1 168 169 def next(self): 170 if self.cur == self.end: 171 raise StopIteration 172 cur = self.cur 173 v = cur.dereference()['first' if self.first else 'second'] 174 if not self.first: 175 self.cur = self.cur + 1 176 self.advancePastEmptyBuckets() 177 self.first = True 178 else: 179 self.first = False 180 return 'x', v 181 182 def __init__(self, val): 183 self.val = val 184 185 def children(self): 186 t = self.val.type.template_argument(3).pointer() 187 begin = self.val['Buckets'].cast(t) 188 end = (begin + self.val['NumBuckets']).cast(t) 189 return self._iterator(self.val.type.template_argument(2), begin, end) 190 191 def to_string(self): 192 return 'llvm::DenseMap with %d elements' % (self.val['NumEntries']) 193 194 def display_hint(self): 195 return 'map' 196 197class TwinePrinter: 198 "Print a Twine" 199 200 def __init__(self, val): 201 self._val = val 202 203 def display_hint(self): 204 return 'string' 205 206 def string_from_pretty_printer_lookup(self, val): 207 '''Lookup the default pretty-printer for val and use it. 208 209 If no pretty-printer is defined for the type of val, print an error and 210 return a placeholder string.''' 211 212 pp = gdb.default_visualizer(val) 213 if pp: 214 s = pp.to_string() 215 216 # The pretty-printer may return a LazyString instead of an actual Python 217 # string. Convert it to a Python string. However, GDB doesn't seem to 218 # register the LazyString type, so we can't check 219 # "type(s) == gdb.LazyString". 220 if 'LazyString' in type(s).__name__: 221 s = s.value().address.string() 222 223 else: 224 print(('No pretty printer for {} found. The resulting Twine ' + 225 'representation will be incomplete.').format(val.type.name)) 226 s = '(missing {})'.format(val.type.name) 227 228 return s 229 230 def is_twine_kind(self, kind, expected): 231 if not kind.endswith(expected): 232 return False 233 # apparently some GDB versions add the NodeKind:: namespace 234 # (happens for me on GDB 7.11) 235 return kind in ('llvm::Twine::' + expected, 236 'llvm::Twine::NodeKind::' + expected) 237 238 def string_from_child(self, child, kind): 239 '''Return the string representation of the Twine::Child child.''' 240 241 if self.is_twine_kind(kind, 'EmptyKind') or self.is_twine_kind(kind, 'NullKind'): 242 return '' 243 244 if self.is_twine_kind(kind, 'TwineKind'): 245 return self.string_from_twine_object(child['twine'].dereference()) 246 247 if self.is_twine_kind(kind, 'CStringKind'): 248 return child['cString'].string() 249 250 if self.is_twine_kind(kind, 'StdStringKind'): 251 val = child['stdString'].dereference() 252 return self.string_from_pretty_printer_lookup(val) 253 254 if self.is_twine_kind(kind, 'StringRefKind'): 255 val = child['stringRef'].dereference() 256 pp = StringRefPrinter(val) 257 return pp.to_string() 258 259 if self.is_twine_kind(kind, 'SmallStringKind'): 260 val = child['smallString'].dereference() 261 pp = SmallStringPrinter(val) 262 return pp.to_string() 263 264 if self.is_twine_kind(kind, 'CharKind'): 265 return chr(child['character']) 266 267 if self.is_twine_kind(kind, 'DecUIKind'): 268 return str(child['decUI']) 269 270 if self.is_twine_kind(kind, 'DecIKind'): 271 return str(child['decI']) 272 273 if self.is_twine_kind(kind, 'DecULKind'): 274 return str(child['decUL'].dereference()) 275 276 if self.is_twine_kind(kind, 'DecLKind'): 277 return str(child['decL'].dereference()) 278 279 if self.is_twine_kind(kind, 'DecULLKind'): 280 return str(child['decULL'].dereference()) 281 282 if self.is_twine_kind(kind, 'DecLLKind'): 283 return str(child['decLL'].dereference()) 284 285 if self.is_twine_kind(kind, 'UHexKind'): 286 val = child['uHex'].dereference() 287 return hex(int(val)) 288 289 print(('Unhandled NodeKind {} in Twine pretty-printer. The result will be ' 290 'incomplete.').format(kind)) 291 292 return '(unhandled {})'.format(kind) 293 294 def string_from_twine_object(self, twine): 295 '''Return the string representation of the Twine object twine.''' 296 297 lhs_str = '' 298 rhs_str = '' 299 300 lhs = twine['LHS'] 301 rhs = twine['RHS'] 302 lhs_kind = str(twine['LHSKind']) 303 rhs_kind = str(twine['RHSKind']) 304 305 lhs_str = self.string_from_child(lhs, lhs_kind) 306 rhs_str = self.string_from_child(rhs, rhs_kind) 307 308 return lhs_str + rhs_str 309 310 def to_string(self): 311 return self.string_from_twine_object(self._val) 312 313pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport") 314pp.add_printer('llvm::SmallString', '^llvm::SmallString<.*>$', SmallStringPrinter) 315pp.add_printer('llvm::StringRef', '^llvm::StringRef$', StringRefPrinter) 316pp.add_printer('llvm::SmallVectorImpl', '^llvm::SmallVector(Impl)?<.*>$', SmallVectorPrinter) 317pp.add_printer('llvm::ArrayRef', '^llvm::(Const)?ArrayRef<.*>$', ArrayRefPrinter) 318pp.add_printer('llvm::Optional', '^llvm::Optional<.*>$', OptionalPrinter) 319pp.add_printer('llvm::DenseMap', '^llvm::DenseMap<.*>$', DenseMapPrinter) 320pp.add_printer('llvm::Twine', '^llvm::Twine$', TwinePrinter) 321gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) 322