Remove unused @lint-avoid-pyflakes* and others
[hiphop-php.git] / hphp / tools / gdb / gdbutils.py
blobd410a6dfe65149ead72a355b28d837ccca30e5ed
1 """
2 Assorted utilities for HHVM GDB bindings.
3 """
5 from compatibility import *
7 import collections
8 import functools
9 import gdb
10 import re
11 import struct
12 import traceback
13 import types
16 #------------------------------------------------------------------------------
17 # Memoization.
19 _all_caches = []
21 def memoized(func):
22 """Simple memoization decorator that ignores **kwargs."""
23 global _all_caches
25 cache = {}
26 _all_caches.append(cache)
28 @functools.wraps(func)
29 def memoizer(*args):
30 if not isinstance(args, collections.Hashable):
31 return func(*args)
32 if args not in cache:
33 cache[args] = func(*args)
34 return cache[args]
35 return memoizer
38 def invalidate_all_memoizers():
39 global _all_caches
41 for cache in _all_caches:
42 cache.clear()
45 #------------------------------------------------------------------------------
46 # Exception debugging.
48 def errorwrap(func):
49 @functools.wraps(func)
50 def wrapped(*args, **kwds):
51 try:
52 return func(*args, **kwds)
53 except:
54 print('')
55 traceback.print_exc()
56 print('')
57 raise
58 return wrapped
61 #------------------------------------------------------------------------------
62 # General-purpose helpers.
64 def parse_argv(args, limit=None):
65 """Explode a gdb argument string, then eval all args up to `limit'."""
66 if limit is None:
67 limit = len(args)
68 return [gdb.parse_and_eval(arg) if i < limit else arg
69 for i, arg in enumerate(gdb.string_to_argv(args))]
72 def gdbprint(val, ty=None):
73 if ty is None:
74 ty = val.type
75 gdb.execute('print (%s)%s' % (str(ty), str(val)))
78 def plural_suffix(num, suffix='s'):
79 return '' if num == 1 else suffix
82 #------------------------------------------------------------------------------
83 # Intel CRC32.
85 def _bit_reflect(num, nbits):
86 """Perform bit reflection on the bottom `nbits' of `num."""
87 out = 0
88 mask = 1 << (nbits - 1)
89 for i in xrange(nbits):
90 if num & (1 << i):
91 out |= mask
92 mask >>= 1
93 return out
96 def crc32q(crc, quad):
97 """Intel SSE4 CRC32 implementation."""
99 crc = _bit_reflect(crc, 32)
100 quad = _bit_reflect(quad, 64)
102 msb = 1 << 63
104 dividend = quad ^ (crc << 32)
105 divisor = 0x11edc6f41 << 31
107 for i in xrange(64):
108 if dividend & msb:
109 dividend ^= divisor
110 dividend <<= 1
112 return _bit_reflect(dividend, 64)
115 #------------------------------------------------------------------------------
116 # String helpers.
118 def string_data_val(val, keep_case=True):
119 """Convert an HPHP::StringData[*] to a Python string."""
121 if V('HPHP::use_lowptr'):
122 data = (deref(val).address + 1).cast(T('char').pointer())
123 else:
124 data = val['m_data']
126 s = data.string('utf-8', 'ignore', val['m_len'])
127 return s if keep_case else s.lower()
130 def _unpack(s):
131 return 0xdfdfdfdfdfdfdfdf & struct.unpack('<Q', s)[0]
133 def hash_string(s):
134 """Hash a string as in hphp/util/hash-crc.S."""
136 size = len(s)
137 tail_sz = size % 8
138 size -= tail_sz
140 crc = 0xffffffff
142 for i in xrange(0, size, 8):
143 crc = crc32q(crc, _unpack(s[i:i+8]))
145 if tail_sz == 0:
146 return crc >> 1
148 shift = -((tail_sz - 8) << 3) & 0b111111
149 tail = _unpack(s[size:].ljust(8, '\0'))
151 crc = crc32q(crc, tail << shift)
152 return crc >> 1
155 def strinfo(s, keep_case=True):
156 """Return the Python string and HHVM hash for `s', or None if `s' is not a
157 stringish gdb.Value."""
159 data = None
160 addr = None
161 h = None
163 t = rawtype(s.type)
165 if (t == T('char').pointer() or
166 re.match(r"char \[\d*\]$", str(t)) is not None):
167 data = s.string()
168 else:
169 sd = deref(s)
171 if rawtype(sd.type).name != 'HPHP::StringData':
172 return None
174 data = string_data_val(sd)
176 if int(sd['m_hash']) != 0:
177 h = sd['m_hash'] & 0x7fffffff
179 if data is None:
180 return None
182 retval = {
183 'data': data if keep_case else data.lower(),
184 'hash': h if h is not None else hash_string(str(data)),
186 return retval
189 def vstr(value):
190 """Stringify a value without pretty-printing."""
192 for pp in gdb.pretty_printers:
193 try:
194 pp.saved = pp.enabled
195 except AttributeError:
196 pp.saved = True
198 pp.enabled = False
200 try:
201 ret = unicode(value)
202 except:
203 ret = str(value)
205 for pp in gdb.pretty_printers:
206 pp.enabled = pp.saved
208 return ret
211 #------------------------------------------------------------------------------
212 # Caching lookups.
214 @memoized
215 def T(name):
216 return gdb.lookup_type(name)
218 @memoized
219 def K(name):
220 return gdb.lookup_global_symbol(name).value()
222 @memoized
223 def V(name):
224 return TL(name)
226 @memoized
227 def nullptr():
228 return gdb.Value(0).cast(T('void').pointer())
231 def TL(name):
232 try:
233 return gdb.lookup_symbol(name)[0].value()
234 except gdb.error:
235 return gdb.lookup_symbol(name)[0].value(gdb.selected_frame())
238 #------------------------------------------------------------------------------
239 # Type manipulations.
241 def rawtype(t):
242 return t.unqualified().strip_typedefs()
245 def template_type(t):
246 """Get the unparametrized name of a template type."""
247 return str(t).split('<')[0]
250 def rawptr(val):
251 """Fully strip a smart pointer type to a raw pointer. References are
252 re-cast as pointers."""
254 t = rawtype(val.type)
256 if t.code == gdb.TYPE_CODE_PTR:
257 return val
258 elif t.code == gdb.TYPE_CODE_REF:
259 return val.referenced_value().address
261 name = template_type(t)
262 ptr = None
264 if name == 'std::unique_ptr':
265 ptr = val['_M_t']['_M_head_impl']
267 if name == 'HPHP::default_ptr':
268 ptr = val['m_p']
270 if name == 'HPHP::req::ptr' or name == 'HPHP::AtomicSharedPtrImpl':
271 ptr = val['m_px']
273 if name == 'HPHP::LowPtr' or name == 'HPHP::detail::LowPtrImpl':
274 inner = t.template_argument(0)
275 ptr = val['m_s'].cast(inner.pointer())
277 if name == 'HPHP::CompactTaggedPtr':
278 inner = t.template_argument(0)
279 ptr = (val['m_data'] & 0xffffffffffff).cast(inner.pointer())
281 if name == 'HPHP::CompactSizedPtr':
282 ptr = rawptr(val['m_data'])
284 if ptr is not None:
285 return rawptr(ptr)
287 return None
290 def deref(val):
291 """Fully dereference a value, stripping away *, &, and all known smart
292 pointer wrappers (as well as const/volatile qualifiers)."""
294 p = rawptr(val)
296 if p is None:
297 return val.cast(rawtype(val.type))
298 else:
299 return deref(p.referenced_value())