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['hasVal']: 128 return self._iterator('', True) 129 return self._iterator(self.value['storage']['buffer'].address.cast(self.value.type.template_argument(0).pointer()), False) 130 131 def to_string(self): 132 return 'llvm::Optional is %sinitialized' % ('' if self.value['hasVal'] else 'not ') 133 134class DenseMapPrinter: 135 "Print a DenseMap" 136 137 class _iterator: 138 def __init__(self, key_info_t, begin, end): 139 self.key_info_t = key_info_t 140 self.cur = begin 141 self.end = end 142 self.advancePastEmptyBuckets() 143 self.first = True 144 145 def __iter__(self): 146 return self 147 148 def advancePastEmptyBuckets(self): 149 # disabled until the comments below can be addressed 150 # keeping as notes/posterity/hints for future contributors 151 return 152 n = self.key_info_t.name 153 is_equal = gdb.parse_and_eval(n + '::isEqual') 154 empty = gdb.parse_and_eval(n + '::getEmptyKey()') 155 tombstone = gdb.parse_and_eval(n + '::getTombstoneKey()') 156 # the following is invalid, GDB fails with: 157 # Python Exception <class 'gdb.error'> Attempt to take address of value 158 # not located in memory. 159 # because isEqual took parameter (for the unsigned long key I was testing) 160 # by const ref, and GDB 161 # It's also not entirely general - we should be accessing the "getFirst()" 162 # member function, not the 'first' member variable, but I've yet to figure 163 # out how to find/call member functions (especially (const) overloaded 164 # ones) on a gdb.Value. 165 while self.cur != self.end and (is_equal(self.cur.dereference()['first'], empty) or is_equal(self.cur.dereference()['first'], tombstone)): 166 self.cur = self.cur + 1 167 168 def next(self): 169 if self.cur == self.end: 170 raise StopIteration 171 cur = self.cur 172 v = cur.dereference()['first' if self.first else 'second'] 173 if not self.first: 174 self.cur = self.cur + 1 175 self.advancePastEmptyBuckets() 176 self.first = True 177 else: 178 self.first = False 179 return 'x', v 180 181 def __init__(self, val): 182 self.val = val 183 184 def children(self): 185 t = self.val.type.template_argument(3).pointer() 186 begin = self.val['Buckets'].cast(t) 187 end = (begin + self.val['NumBuckets']).cast(t) 188 return self._iterator(self.val.type.template_argument(2), begin, end) 189 190 def to_string(self): 191 return 'llvm::DenseMap with %d elements' % (self.val['NumEntries']) 192 193 def display_hint(self): 194 return 'map' 195 196class TwinePrinter: 197 "Print a Twine" 198 199 def __init__(self, val): 200 self._val = val 201 202 def display_hint(self): 203 return 'string' 204 205 def string_from_pretty_printer_lookup(self, val): 206 '''Lookup the default pretty-printer for val and use it. 207 208 If no pretty-printer is defined for the type of val, print an error and 209 return a placeholder string.''' 210 211 pp = gdb.default_visualizer(val) 212 if pp: 213 s = pp.to_string() 214 215 # The pretty-printer may return a LazyString instead of an actual Python 216 # string. Convert it to a Python string. However, GDB doesn't seem to 217 # register the LazyString type, so we can't check 218 # "type(s) == gdb.LazyString". 219 if 'LazyString' in type(s).__name__: 220 s = s.value().address.string() 221 222 else: 223 print(('No pretty printer for {} found. The resulting Twine ' + 224 'representation will be incomplete.').format(val.type.name)) 225 s = '(missing {})'.format(val.type.name) 226 227 return s 228 229 def is_twine_kind(self, kind, expected): 230 if not kind.endswith(expected): 231 return False 232 # apparently some GDB versions add the NodeKind:: namespace 233 # (happens for me on GDB 7.11) 234 return kind in ('llvm::Twine::' + expected, 235 'llvm::Twine::NodeKind::' + expected) 236 237 def string_from_child(self, child, kind): 238 '''Return the string representation of the Twine::Child child.''' 239 240 if self.is_twine_kind(kind, 'EmptyKind') or self.is_twine_kind(kind, 'NullKind'): 241 return '' 242 243 if self.is_twine_kind(kind, 'TwineKind'): 244 return self.string_from_twine_object(child['twine'].dereference()) 245 246 if self.is_twine_kind(kind, 'CStringKind'): 247 return child['cString'].string() 248 249 if self.is_twine_kind(kind, 'StdStringKind'): 250 val = child['stdString'].dereference() 251 return self.string_from_pretty_printer_lookup(val) 252 253 if self.is_twine_kind(kind, 'StringRefKind'): 254 val = child['stringRef'].dereference() 255 pp = StringRefPrinter(val) 256 return pp.to_string() 257 258 if self.is_twine_kind(kind, 'SmallStringKind'): 259 val = child['smallString'].dereference() 260 pp = SmallStringPrinter(val) 261 return pp.to_string() 262 263 if self.is_twine_kind(kind, 'CharKind'): 264 return chr(child['character']) 265 266 if self.is_twine_kind(kind, 'DecUIKind'): 267 return str(child['decUI']) 268 269 if self.is_twine_kind(kind, 'DecIKind'): 270 return str(child['decI']) 271 272 if self.is_twine_kind(kind, 'DecULKind'): 273 return str(child['decUL'].dereference()) 274 275 if self.is_twine_kind(kind, 'DecLKind'): 276 return str(child['decL'].dereference()) 277 278 if self.is_twine_kind(kind, 'DecULLKind'): 279 return str(child['decULL'].dereference()) 280 281 if self.is_twine_kind(kind, 'DecLLKind'): 282 return str(child['decLL'].dereference()) 283 284 if self.is_twine_kind(kind, 'UHexKind'): 285 val = child['uHex'].dereference() 286 return hex(int(val)) 287 288 print(('Unhandled NodeKind {} in Twine pretty-printer. The result will be ' 289 'incomplete.').format(kind)) 290 291 return '(unhandled {})'.format(kind) 292 293 def string_from_twine_object(self, twine): 294 '''Return the string representation of the Twine object twine.''' 295 296 lhs_str = '' 297 rhs_str = '' 298 299 lhs = twine['LHS'] 300 rhs = twine['RHS'] 301 lhs_kind = str(twine['LHSKind']) 302 rhs_kind = str(twine['RHSKind']) 303 304 lhs_str = self.string_from_child(lhs, lhs_kind) 305 rhs_str = self.string_from_child(rhs, rhs_kind) 306 307 return lhs_str + rhs_str 308 309 def to_string(self): 310 return self.string_from_twine_object(self._val) 311 312pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport") 313pp.add_printer('llvm::SmallString', '^llvm::SmallString<.*>$', SmallStringPrinter) 314pp.add_printer('llvm::StringRef', '^llvm::StringRef$', StringRefPrinter) 315pp.add_printer('llvm::SmallVectorImpl', '^llvm::SmallVector(Impl)?<.*>$', SmallVectorPrinter) 316pp.add_printer('llvm::ArrayRef', '^llvm::(Const)?ArrayRef<.*>$', ArrayRefPrinter) 317pp.add_printer('llvm::Optional', '^llvm::Optional<.*>$', OptionalPrinter) 318pp.add_printer('llvm::DenseMap', '^llvm::DenseMap<.*>$', DenseMapPrinter) 319pp.add_printer('llvm::Twine', '^llvm::Twine$', TwinePrinter) 320gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) 321