1from __future__ import print_function
2import sys
3
4import gdb.printing
5
6class Iterator:
7  def __iter__(self):
8    return self
9
10  if sys.version_info.major == 2:
11      def next(self):
12        return self.__next__()
13
14  def children(self):
15    return self
16
17def escape_bytes(val, l):
18  return '"' + val.string(encoding='Latin-1', length=l).encode('unicode_escape').decode() + '"'
19
20class SmallStringPrinter:
21  """Print an llvm::SmallString object."""
22
23  def __init__(self, val):
24    self.val = val
25
26  def to_string(self):
27    begin = self.val['BeginX']
28    return escape_bytes(begin.cast(gdb.lookup_type('char').pointer()), self.val['Size'])
29
30class StringRefPrinter:
31  """Print an llvm::StringRef object."""
32
33  def __init__(self, val):
34    self.val = val
35
36  def to_string(self):
37    return escape_bytes(self.val['Data'], self.val['Length'])
38
39class SmallVectorPrinter(Iterator):
40  """Print an llvm::SmallVector object."""
41
42  def __init__(self, val):
43    self.val = val
44    t = val.type.template_argument(0).pointer()
45    self.begin = val['BeginX'].cast(t)
46    self.size = val['Size']
47    self.i = 0
48
49  def __next__(self):
50    if self.i == self.size:
51      raise StopIteration
52    ret = '[{}]'.format(self.i), (self.begin+self.i).dereference()
53    self.i += 1
54    return ret
55
56  def to_string(self):
57    return 'llvm::SmallVector of Size {}, Capacity {}'.format(self.size, self.val['Capacity'])
58
59  def display_hint (self):
60    return 'array'
61
62class ArrayRefPrinter:
63  """Print an llvm::ArrayRef object."""
64
65  class _iterator:
66    def __init__(self, begin, end):
67      self.cur = begin
68      self.end = end
69      self.count = 0
70
71    def __iter__(self):
72      return self
73
74    def __next__(self):
75      if self.cur == self.end:
76        raise StopIteration
77      count = self.count
78      self.count = self.count + 1
79      cur = self.cur
80      self.cur = self.cur + 1
81      return '[%d]' % count, cur.dereference()
82
83    if sys.version_info.major == 2:
84        next = __next__
85
86  def __init__(self, val):
87    self.val = val
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']['value'])
133
134  def to_string(self):
135    return 'llvm::Optional{}'.format('' if self.val['Storage']['hasVal'] else ' is not initialized')
136
137class DenseMapPrinter:
138  "Print a DenseMap"
139
140  class _iterator:
141    def __init__(self, key_info_t, begin, end):
142      self.key_info_t = key_info_t
143      self.cur = begin
144      self.end = end
145      self.advancePastEmptyBuckets()
146      self.first = True
147
148    def __iter__(self):
149      return self
150
151    def advancePastEmptyBuckets(self):
152      # disabled until the comments below can be addressed
153      # keeping as notes/posterity/hints for future contributors
154      return
155      n = self.key_info_t.name
156      is_equal = gdb.parse_and_eval(n + '::isEqual')
157      empty = gdb.parse_and_eval(n + '::getEmptyKey()')
158      tombstone = gdb.parse_and_eval(n + '::getTombstoneKey()')
159      # the following is invalid, GDB fails with:
160      #   Python Exception <class 'gdb.error'> Attempt to take address of value
161      #   not located in memory.
162      # because isEqual took parameter (for the unsigned long key I was testing)
163      # by const ref, and GDB
164      # It's also not entirely general - we should be accessing the "getFirst()"
165      # member function, not the 'first' member variable, but I've yet to figure
166      # out how to find/call member functions (especially (const) overloaded
167      # ones) on a gdb.Value.
168      while self.cur != self.end and (is_equal(self.cur.dereference()['first'], empty) or is_equal(self.cur.dereference()['first'], tombstone)):
169        self.cur = self.cur + 1
170
171    def __next__(self):
172      if self.cur == self.end:
173        raise StopIteration
174      cur = self.cur
175      v = cur.dereference()['first' if self.first else 'second']
176      if not self.first:
177        self.cur = self.cur + 1
178        self.advancePastEmptyBuckets()
179        self.first = True
180      else:
181        self.first = False
182      return 'x', v
183
184    if sys.version_info.major == 2:
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::(Mutable)?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