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