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 196 197pp = gdb.printing.RegexpCollectionPrettyPrinter("LLVMSupport") 198pp.add_printer('llvm::SmallString', '^llvm::SmallString<.*>$', SmallStringPrinter) 199pp.add_printer('llvm::StringRef', '^llvm::StringRef$', StringRefPrinter) 200pp.add_printer('llvm::SmallVectorImpl', '^llvm::SmallVector(Impl)?<.*>$', SmallVectorPrinter) 201pp.add_printer('llvm::ArrayRef', '^llvm::(Const)?ArrayRef<.*>$', ArrayRefPrinter) 202pp.add_printer('llvm::Optional', '^llvm::Optional<.*>$', OptionalPrinter) 203pp.add_printer('llvm::DenseMap', '^llvm::DenseMap<.*>$', DenseMapPrinter) 204gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) 205