1#!/usr/bin/python 2''' 3From gdb 7 onwards, gdb's build can be configured --with-python, allowing gdb 4to be extended with Python code e.g. for library-specific data visualizations, 5such as for the C++ STL types. Documentation on this API can be seen at: 6http://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html 7 8 9This python module deals with the case when the process being debugged (the 10"inferior process" in gdb parlance) is itself python, or more specifically, 11linked against libpython. In this situation, almost every item of data is a 12(PyObject*), and having the debugger merely print their addresses is not very 13enlightening. 14 15This module embeds knowledge about the implementation details of libpython so 16that we can emit useful visualizations e.g. a string, a list, a dict, a frame 17giving file/line information and the state of local variables 18 19In particular, given a gdb.Value corresponding to a PyObject* in the inferior 20process, we can generate a "proxy value" within the gdb process. For example, 21given a PyObject* in the inferior process that is in fact a PyListObject* 22holding three PyObject* that turn out to be PyStringObject* instances, we can 23generate a proxy value within the gdb process that is a list of strings: 24 ["foo", "bar", "baz"] 25 26Doing so can be expensive for complicated graphs of objects, and could take 27some time, so we also have a "write_repr" method that writes a representation 28of the data to a file-like object. This allows us to stop the traversal by 29having the file-like object raise an exception if it gets too much data. 30 31With both "proxyval" and "write_repr" we keep track of the set of all addresses 32visited so far in the traversal, to avoid infinite recursion due to cycles in 33the graph of object references. 34 35We try to defer gdb.lookup_type() invocations for python types until as late as 36possible: for a dynamically linked python binary, when the process starts in 37the debugger, the libpython.so hasn't been dynamically loaded yet, so none of 38the type names are known to the debugger 39 40The module also extends gdb with some python-specific commands. 41''' 42 43# NOTE: some gdbs are linked with Python 3, so this file should be dual-syntax 44# compatible (2.6+ and 3.0+). See #19308. 45 46from __future__ import print_function, with_statement 47import gdb 48import locale 49import os 50import sys 51 52if sys.version_info[0] >= 3: 53 unichr = chr 54 xrange = range 55 long = int 56 57# Look up the gdb.Type for some standard types: 58# Those need to be refreshed as types (pointer sizes) may change when 59# gdb loads different executables 60 61def _type_char_ptr(): 62 return gdb.lookup_type('char').pointer() # char* 63 64 65def _type_unsigned_char_ptr(): 66 return gdb.lookup_type('unsigned char').pointer() # unsigned char* 67 68 69def _sizeof_void_p(): 70 return gdb.lookup_type('void').pointer().sizeof 71 72 73Py_TPFLAGS_HEAPTYPE = (1 << 9) 74 75Py_TPFLAGS_INT_SUBCLASS = (1 << 23) 76Py_TPFLAGS_LONG_SUBCLASS = (1 << 24) 77Py_TPFLAGS_LIST_SUBCLASS = (1 << 25) 78Py_TPFLAGS_TUPLE_SUBCLASS = (1 << 26) 79Py_TPFLAGS_STRING_SUBCLASS = (1 << 27) 80Py_TPFLAGS_UNICODE_SUBCLASS = (1 << 28) 81Py_TPFLAGS_DICT_SUBCLASS = (1 << 29) 82Py_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30) 83Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31) 84 85 86MAX_OUTPUT_LEN=1024 87 88ENCODING = locale.getpreferredencoding() 89 90class NullPyObjectPtr(RuntimeError): 91 pass 92 93 94def safety_limit(val): 95 # Given an integer value from the process being debugged, limit it to some 96 # safety threshold so that arbitrary breakage within said process doesn't 97 # break the gdb process too much (e.g. sizes of iterations, sizes of lists) 98 return min(val, 1000) 99 100 101def safe_range(val): 102 # As per range, but don't trust the value too much: cap it to a safety 103 # threshold in case the data was corrupted 104 return xrange(safety_limit(int(val))) 105 106if sys.version_info[0] >= 3: 107 def write_unicode(file, text): 108 file.write(text) 109else: 110 def write_unicode(file, text): 111 # Write a byte or unicode string to file. Unicode strings are encoded to 112 # ENCODING encoding with 'backslashreplace' error handler to avoid 113 # UnicodeEncodeError. 114 if isinstance(text, unicode): 115 text = text.encode(ENCODING, 'backslashreplace') 116 file.write(text) 117 118 119class StringTruncated(RuntimeError): 120 pass 121 122class TruncatedStringIO(object): 123 '''Similar to cStringIO, but can truncate the output by raising a 124 StringTruncated exception''' 125 def __init__(self, maxlen=None): 126 self._val = '' 127 self.maxlen = maxlen 128 129 def write(self, data): 130 if self.maxlen: 131 if len(data) + len(self._val) > self.maxlen: 132 # Truncation: 133 self._val += data[0:self.maxlen - len(self._val)] 134 raise StringTruncated() 135 136 self._val += data 137 138 def getvalue(self): 139 return self._val 140 141class PyObjectPtr(object): 142 """ 143 Class wrapping a gdb.Value that's either a (PyObject*) within the 144 inferior process, or some subclass pointer e.g. (PyStringObject*) 145 146 There will be a subclass for every refined PyObject type that we care 147 about. 148 149 Note that at every stage the underlying pointer could be NULL, point 150 to corrupt data, etc; this is the debugger, after all. 151 """ 152 _typename = 'PyObject' 153 154 def __init__(self, gdbval, cast_to=None): 155 if cast_to: 156 self._gdbval = gdbval.cast(cast_to) 157 else: 158 self._gdbval = gdbval 159 160 def field(self, name): 161 ''' 162 Get the gdb.Value for the given field within the PyObject, coping with 163 some python 2 versus python 3 differences. 164 165 Various libpython types are defined using the "PyObject_HEAD" and 166 "PyObject_VAR_HEAD" macros. 167 168 In Python 2, this these are defined so that "ob_type" and (for a var 169 object) "ob_size" are fields of the type in question. 170 171 In Python 3, this is defined as an embedded PyVarObject type thus: 172 PyVarObject ob_base; 173 so that the "ob_size" field is located insize the "ob_base" field, and 174 the "ob_type" is most easily accessed by casting back to a (PyObject*). 175 ''' 176 if self.is_null(): 177 raise NullPyObjectPtr(self) 178 179 if name == 'ob_type': 180 pyo_ptr = self._gdbval.cast(PyObjectPtr.get_gdb_type()) 181 return pyo_ptr.dereference()[name] 182 183 if name == 'ob_size': 184 try: 185 # Python 2: 186 return self._gdbval.dereference()[name] 187 except RuntimeError: 188 # Python 3: 189 return self._gdbval.dereference()['ob_base'][name] 190 191 # General case: look it up inside the object: 192 return self._gdbval.dereference()[name] 193 194 def pyop_field(self, name): 195 ''' 196 Get a PyObjectPtr for the given PyObject* field within this PyObject, 197 coping with some python 2 versus python 3 differences. 198 ''' 199 return PyObjectPtr.from_pyobject_ptr(self.field(name)) 200 201 def write_field_repr(self, name, out, visited): 202 ''' 203 Extract the PyObject* field named "name", and write its representation 204 to file-like object "out" 205 ''' 206 field_obj = self.pyop_field(name) 207 field_obj.write_repr(out, visited) 208 209 def get_truncated_repr(self, maxlen): 210 ''' 211 Get a repr-like string for the data, but truncate it at "maxlen" bytes 212 (ending the object graph traversal as soon as you do) 213 ''' 214 out = TruncatedStringIO(maxlen) 215 try: 216 self.write_repr(out, set()) 217 except StringTruncated: 218 # Truncation occurred: 219 return out.getvalue() + '...(truncated)' 220 221 # No truncation occurred: 222 return out.getvalue() 223 224 def type(self): 225 return PyTypeObjectPtr(self.field('ob_type')) 226 227 def is_null(self): 228 return 0 == long(self._gdbval) 229 230 def is_optimized_out(self): 231 ''' 232 Is the value of the underlying PyObject* visible to the debugger? 233 234 This can vary with the precise version of the compiler used to build 235 Python, and the precise version of gdb. 236 237 See e.g. https://bugzilla.redhat.com/show_bug.cgi?id=556975 with 238 PyEval_EvalFrameEx's "f" 239 ''' 240 return self._gdbval.is_optimized_out 241 242 def safe_tp_name(self): 243 try: 244 return self.type().field('tp_name').string() 245 except NullPyObjectPtr: 246 # NULL tp_name? 247 return 'unknown' 248 except RuntimeError: 249 # Can't even read the object at all? 250 return 'unknown' 251 252 def proxyval(self, visited): 253 ''' 254 Scrape a value from the inferior process, and try to represent it 255 within the gdb process, whilst (hopefully) avoiding crashes when 256 the remote data is corrupt. 257 258 Derived classes will override this. 259 260 For example, a PyIntObject* with ob_ival 42 in the inferior process 261 should result in an int(42) in this process. 262 263 visited: a set of all gdb.Value pyobject pointers already visited 264 whilst generating this value (to guard against infinite recursion when 265 visiting object graphs with loops). Analogous to Py_ReprEnter and 266 Py_ReprLeave 267 ''' 268 269 class FakeRepr(object): 270 """ 271 Class representing a non-descript PyObject* value in the inferior 272 process for when we don't have a custom scraper, intended to have 273 a sane repr(). 274 """ 275 276 def __init__(self, tp_name, address): 277 self.tp_name = tp_name 278 self.address = address 279 280 def __repr__(self): 281 # For the NULL pointer, we have no way of knowing a type, so 282 # special-case it as per 283 # http://bugs.python.org/issue8032#msg100882 284 if self.address == 0: 285 return '0x0' 286 return '<%s at remote 0x%x>' % (self.tp_name, self.address) 287 288 return FakeRepr(self.safe_tp_name(), 289 long(self._gdbval)) 290 291 def write_repr(self, out, visited): 292 ''' 293 Write a string representation of the value scraped from the inferior 294 process to "out", a file-like object. 295 ''' 296 # Default implementation: generate a proxy value and write its repr 297 # However, this could involve a lot of work for complicated objects, 298 # so for derived classes we specialize this 299 return out.write(repr(self.proxyval(visited))) 300 301 @classmethod 302 def subclass_from_type(cls, t): 303 ''' 304 Given a PyTypeObjectPtr instance wrapping a gdb.Value that's a 305 (PyTypeObject*), determine the corresponding subclass of PyObjectPtr 306 to use 307 308 Ideally, we would look up the symbols for the global types, but that 309 isn't working yet: 310 (gdb) python print gdb.lookup_symbol('PyList_Type')[0].value 311 Traceback (most recent call last): 312 File "<string>", line 1, in <module> 313 NotImplementedError: Symbol type not yet supported in Python scripts. 314 Error while executing Python code. 315 316 For now, we use tp_flags, after doing some string comparisons on the 317 tp_name for some special-cases that don't seem to be visible through 318 flags 319 ''' 320 try: 321 tp_name = t.field('tp_name').string() 322 tp_flags = int(t.field('tp_flags')) 323 except RuntimeError: 324 # Handle any kind of error e.g. NULL ptrs by simply using the base 325 # class 326 return cls 327 328 #print('tp_flags = 0x%08x' % tp_flags) 329 #print('tp_name = %r' % tp_name) 330 331 name_map = {'bool': PyBoolObjectPtr, 332 'classobj': PyClassObjectPtr, 333 'instance': PyInstanceObjectPtr, 334 'NoneType': PyNoneStructPtr, 335 'frame': PyFrameObjectPtr, 336 'set' : PySetObjectPtr, 337 'frozenset' : PySetObjectPtr, 338 'builtin_function_or_method' : PyCFunctionObjectPtr, 339 } 340 if tp_name in name_map: 341 return name_map[tp_name] 342 343 if tp_flags & Py_TPFLAGS_HEAPTYPE: 344 return HeapTypeObjectPtr 345 346 if tp_flags & Py_TPFLAGS_INT_SUBCLASS: 347 return PyIntObjectPtr 348 if tp_flags & Py_TPFLAGS_LONG_SUBCLASS: 349 return PyLongObjectPtr 350 if tp_flags & Py_TPFLAGS_LIST_SUBCLASS: 351 return PyListObjectPtr 352 if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS: 353 return PyTupleObjectPtr 354 if tp_flags & Py_TPFLAGS_STRING_SUBCLASS: 355 return PyStringObjectPtr 356 if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS: 357 return PyUnicodeObjectPtr 358 if tp_flags & Py_TPFLAGS_DICT_SUBCLASS: 359 return PyDictObjectPtr 360 if tp_flags & Py_TPFLAGS_BASE_EXC_SUBCLASS: 361 return PyBaseExceptionObjectPtr 362 #if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS: 363 # return PyTypeObjectPtr 364 365 # Use the base class: 366 return cls 367 368 @classmethod 369 def from_pyobject_ptr(cls, gdbval): 370 ''' 371 Try to locate the appropriate derived class dynamically, and cast 372 the pointer accordingly. 373 ''' 374 try: 375 p = PyObjectPtr(gdbval) 376 cls = cls.subclass_from_type(p.type()) 377 return cls(gdbval, cast_to=cls.get_gdb_type()) 378 except RuntimeError: 379 # Handle any kind of error e.g. NULL ptrs by simply using the base 380 # class 381 pass 382 return cls(gdbval) 383 384 @classmethod 385 def get_gdb_type(cls): 386 return gdb.lookup_type(cls._typename).pointer() 387 388 def as_address(self): 389 return long(self._gdbval) 390 391 392class ProxyAlreadyVisited(object): 393 ''' 394 Placeholder proxy to use when protecting against infinite recursion due to 395 loops in the object graph. 396 397 Analogous to the values emitted by the users of Py_ReprEnter and Py_ReprLeave 398 ''' 399 def __init__(self, rep): 400 self._rep = rep 401 402 def __repr__(self): 403 return self._rep 404 405 406def _write_instance_repr(out, visited, name, pyop_attrdict, address): 407 '''Shared code for use by old-style and new-style classes: 408 write a representation to file-like object "out"''' 409 out.write('<') 410 out.write(name) 411 412 # Write dictionary of instance attributes: 413 if isinstance(pyop_attrdict, PyDictObjectPtr): 414 out.write('(') 415 first = True 416 for pyop_arg, pyop_val in pyop_attrdict.iteritems(): 417 if not first: 418 out.write(', ') 419 first = False 420 out.write(pyop_arg.proxyval(visited)) 421 out.write('=') 422 pyop_val.write_repr(out, visited) 423 out.write(')') 424 out.write(' at remote 0x%x>' % address) 425 426 427class InstanceProxy(object): 428 429 def __init__(self, cl_name, attrdict, address): 430 self.cl_name = cl_name 431 self.attrdict = attrdict 432 self.address = address 433 434 def __repr__(self): 435 if isinstance(self.attrdict, dict): 436 kwargs = ', '.join(["%s=%r" % (arg, val) 437 for arg, val in self.attrdict.iteritems()]) 438 return '<%s(%s) at remote 0x%x>' % (self.cl_name, 439 kwargs, self.address) 440 else: 441 return '<%s at remote 0x%x>' % (self.cl_name, 442 self.address) 443 444def _PyObject_VAR_SIZE(typeobj, nitems): 445 if _PyObject_VAR_SIZE._type_size_t is None: 446 _PyObject_VAR_SIZE._type_size_t = gdb.lookup_type('size_t') 447 448 return ( ( typeobj.field('tp_basicsize') + 449 nitems * typeobj.field('tp_itemsize') + 450 (_sizeof_void_p() - 1) 451 ) & ~(_sizeof_void_p() - 1) 452 ).cast(_PyObject_VAR_SIZE._type_size_t) 453_PyObject_VAR_SIZE._type_size_t = None 454 455class HeapTypeObjectPtr(PyObjectPtr): 456 _typename = 'PyObject' 457 458 def get_attr_dict(self): 459 ''' 460 Get the PyDictObject ptr representing the attribute dictionary 461 (or None if there's a problem) 462 ''' 463 try: 464 typeobj = self.type() 465 dictoffset = int_from_int(typeobj.field('tp_dictoffset')) 466 if dictoffset != 0: 467 if dictoffset < 0: 468 type_PyVarObject_ptr = gdb.lookup_type('PyVarObject').pointer() 469 tsize = int_from_int(self._gdbval.cast(type_PyVarObject_ptr)['ob_size']) 470 if tsize < 0: 471 tsize = -tsize 472 size = _PyObject_VAR_SIZE(typeobj, tsize) 473 dictoffset += size 474 assert dictoffset > 0 475 assert dictoffset % _sizeof_void_p() == 0 476 477 dictptr = self._gdbval.cast(_type_char_ptr()) + dictoffset 478 PyObjectPtrPtr = PyObjectPtr.get_gdb_type().pointer() 479 dictptr = dictptr.cast(PyObjectPtrPtr) 480 return PyObjectPtr.from_pyobject_ptr(dictptr.dereference()) 481 except RuntimeError: 482 # Corrupt data somewhere; fail safe 483 pass 484 485 # Not found, or some kind of error: 486 return None 487 488 def proxyval(self, visited): 489 ''' 490 Support for new-style classes. 491 492 Currently we just locate the dictionary using a transliteration to 493 python of _PyObject_GetDictPtr, ignoring descriptors 494 ''' 495 # Guard against infinite loops: 496 if self.as_address() in visited: 497 return ProxyAlreadyVisited('<...>') 498 visited.add(self.as_address()) 499 500 pyop_attr_dict = self.get_attr_dict() 501 if pyop_attr_dict: 502 attr_dict = pyop_attr_dict.proxyval(visited) 503 else: 504 attr_dict = {} 505 tp_name = self.safe_tp_name() 506 507 # New-style class: 508 return InstanceProxy(tp_name, attr_dict, long(self._gdbval)) 509 510 def write_repr(self, out, visited): 511 # Guard against infinite loops: 512 if self.as_address() in visited: 513 out.write('<...>') 514 return 515 visited.add(self.as_address()) 516 517 pyop_attrdict = self.get_attr_dict() 518 _write_instance_repr(out, visited, 519 self.safe_tp_name(), pyop_attrdict, self.as_address()) 520 521class ProxyException(Exception): 522 def __init__(self, tp_name, args): 523 self.tp_name = tp_name 524 self.args = args 525 526 def __repr__(self): 527 return '%s%r' % (self.tp_name, self.args) 528 529class PyBaseExceptionObjectPtr(PyObjectPtr): 530 """ 531 Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception 532 within the process being debugged. 533 """ 534 _typename = 'PyBaseExceptionObject' 535 536 def proxyval(self, visited): 537 # Guard against infinite loops: 538 if self.as_address() in visited: 539 return ProxyAlreadyVisited('(...)') 540 visited.add(self.as_address()) 541 arg_proxy = self.pyop_field('args').proxyval(visited) 542 return ProxyException(self.safe_tp_name(), 543 arg_proxy) 544 545 def write_repr(self, out, visited): 546 # Guard against infinite loops: 547 if self.as_address() in visited: 548 out.write('(...)') 549 return 550 visited.add(self.as_address()) 551 552 out.write(self.safe_tp_name()) 553 self.write_field_repr('args', out, visited) 554 555class PyBoolObjectPtr(PyObjectPtr): 556 """ 557 Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two 558 <bool> instances (Py_True/Py_False) within the process being debugged. 559 """ 560 _typename = 'PyBoolObject' 561 562 def proxyval(self, visited): 563 if int_from_int(self.field('ob_ival')): 564 return True 565 else: 566 return False 567 568 569class PyClassObjectPtr(PyObjectPtr): 570 """ 571 Class wrapping a gdb.Value that's a PyClassObject* i.e. a <classobj> 572 instance within the process being debugged. 573 """ 574 _typename = 'PyClassObject' 575 576 577class BuiltInFunctionProxy(object): 578 def __init__(self, ml_name): 579 self.ml_name = ml_name 580 581 def __repr__(self): 582 return "<built-in function %s>" % self.ml_name 583 584class BuiltInMethodProxy(object): 585 def __init__(self, ml_name, pyop_m_self): 586 self.ml_name = ml_name 587 self.pyop_m_self = pyop_m_self 588 589 def __repr__(self): 590 return ('<built-in method %s of %s object at remote 0x%x>' 591 % (self.ml_name, 592 self.pyop_m_self.safe_tp_name(), 593 self.pyop_m_self.as_address()) 594 ) 595 596class PyCFunctionObjectPtr(PyObjectPtr): 597 """ 598 Class wrapping a gdb.Value that's a PyCFunctionObject* 599 (see Include/methodobject.h and Objects/methodobject.c) 600 """ 601 _typename = 'PyCFunctionObject' 602 603 def proxyval(self, visited): 604 m_ml = self.field('m_ml') # m_ml is a (PyMethodDef*) 605 ml_name = m_ml['ml_name'].string() 606 607 pyop_m_self = self.pyop_field('m_self') 608 if pyop_m_self.is_null(): 609 return BuiltInFunctionProxy(ml_name) 610 else: 611 return BuiltInMethodProxy(ml_name, pyop_m_self) 612 613 614class PyCodeObjectPtr(PyObjectPtr): 615 """ 616 Class wrapping a gdb.Value that's a PyCodeObject* i.e. a <code> instance 617 within the process being debugged. 618 """ 619 _typename = 'PyCodeObject' 620 621 def addr2line(self, addrq): 622 ''' 623 Get the line number for a given bytecode offset 624 625 Analogous to PyCode_Addr2Line; translated from pseudocode in 626 Objects/lnotab_notes.txt 627 ''' 628 co_lnotab = self.pyop_field('co_lnotab').proxyval(set()) 629 630 # Initialize lineno to co_firstlineno as per PyCode_Addr2Line 631 # not 0, as lnotab_notes.txt has it: 632 lineno = int_from_int(self.field('co_firstlineno')) 633 634 addr = 0 635 for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]): 636 addr += ord(addr_incr) 637 if addr > addrq: 638 return lineno 639 lineno += ord(line_incr) 640 return lineno 641 642 643class PyDictObjectPtr(PyObjectPtr): 644 """ 645 Class wrapping a gdb.Value that's a PyDictObject* i.e. a dict instance 646 within the process being debugged. 647 """ 648 _typename = 'PyDictObject' 649 650 def iteritems(self): 651 ''' 652 Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs, 653 analogous to dict.iteritems() 654 ''' 655 for i in safe_range(self.field('ma_mask') + 1): 656 ep = self.field('ma_table') + i 657 pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value']) 658 if not pyop_value.is_null(): 659 pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key']) 660 yield (pyop_key, pyop_value) 661 662 def proxyval(self, visited): 663 # Guard against infinite loops: 664 if self.as_address() in visited: 665 return ProxyAlreadyVisited('{...}') 666 visited.add(self.as_address()) 667 668 result = {} 669 for pyop_key, pyop_value in self.iteritems(): 670 proxy_key = pyop_key.proxyval(visited) 671 proxy_value = pyop_value.proxyval(visited) 672 result[proxy_key] = proxy_value 673 return result 674 675 def write_repr(self, out, visited): 676 # Guard against infinite loops: 677 if self.as_address() in visited: 678 out.write('{...}') 679 return 680 visited.add(self.as_address()) 681 682 out.write('{') 683 first = True 684 for pyop_key, pyop_value in self.iteritems(): 685 if not first: 686 out.write(', ') 687 first = False 688 pyop_key.write_repr(out, visited) 689 out.write(': ') 690 pyop_value.write_repr(out, visited) 691 out.write('}') 692 693class PyInstanceObjectPtr(PyObjectPtr): 694 _typename = 'PyInstanceObject' 695 696 def proxyval(self, visited): 697 # Guard against infinite loops: 698 if self.as_address() in visited: 699 return ProxyAlreadyVisited('<...>') 700 visited.add(self.as_address()) 701 702 # Get name of class: 703 in_class = self.pyop_field('in_class') 704 cl_name = in_class.pyop_field('cl_name').proxyval(visited) 705 706 # Get dictionary of instance attributes: 707 in_dict = self.pyop_field('in_dict').proxyval(visited) 708 709 # Old-style class: 710 return InstanceProxy(cl_name, in_dict, long(self._gdbval)) 711 712 def write_repr(self, out, visited): 713 # Guard against infinite loops: 714 if self.as_address() in visited: 715 out.write('<...>') 716 return 717 visited.add(self.as_address()) 718 719 # Old-style class: 720 721 # Get name of class: 722 in_class = self.pyop_field('in_class') 723 cl_name = in_class.pyop_field('cl_name').proxyval(visited) 724 725 # Get dictionary of instance attributes: 726 pyop_in_dict = self.pyop_field('in_dict') 727 728 _write_instance_repr(out, visited, 729 cl_name, pyop_in_dict, self.as_address()) 730 731class PyIntObjectPtr(PyObjectPtr): 732 _typename = 'PyIntObject' 733 734 def proxyval(self, visited): 735 result = int_from_int(self.field('ob_ival')) 736 return result 737 738class PyListObjectPtr(PyObjectPtr): 739 _typename = 'PyListObject' 740 741 def __getitem__(self, i): 742 # Get the gdb.Value for the (PyObject*) with the given index: 743 field_ob_item = self.field('ob_item') 744 return field_ob_item[i] 745 746 def proxyval(self, visited): 747 # Guard against infinite loops: 748 if self.as_address() in visited: 749 return ProxyAlreadyVisited('[...]') 750 visited.add(self.as_address()) 751 752 result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited) 753 for i in safe_range(int_from_int(self.field('ob_size')))] 754 return result 755 756 def write_repr(self, out, visited): 757 # Guard against infinite loops: 758 if self.as_address() in visited: 759 out.write('[...]') 760 return 761 visited.add(self.as_address()) 762 763 out.write('[') 764 for i in safe_range(int_from_int(self.field('ob_size'))): 765 if i > 0: 766 out.write(', ') 767 element = PyObjectPtr.from_pyobject_ptr(self[i]) 768 element.write_repr(out, visited) 769 out.write(']') 770 771class PyLongObjectPtr(PyObjectPtr): 772 _typename = 'PyLongObject' 773 774 def proxyval(self, visited): 775 ''' 776 Python's Include/longobjrep.h has this declaration: 777 struct _longobject { 778 PyObject_VAR_HEAD 779 digit ob_digit[1]; 780 }; 781 782 with this description: 783 The absolute value of a number is equal to 784 SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) 785 Negative numbers are represented with ob_size < 0; 786 zero is represented by ob_size == 0. 787 788 where SHIFT can be either: 789 #define PyLong_SHIFT 30 790 #define PyLong_SHIFT 15 791 ''' 792 ob_size = long(self.field('ob_size')) 793 if ob_size == 0: 794 return 0 795 796 ob_digit = self.field('ob_digit') 797 798 if gdb.lookup_type('digit').sizeof == 2: 799 SHIFT = 15 800 else: 801 SHIFT = 30 802 803 digits = [long(ob_digit[i]) * 2**(SHIFT*i) 804 for i in safe_range(abs(ob_size))] 805 result = sum(digits) 806 if ob_size < 0: 807 result = -result 808 return result 809 810 def write_repr(self, out, visited): 811 # This ensures the trailing 'L' is printed when gdb is linked 812 # with a Python 3 interpreter. 813 out.write(repr(self.proxyval(visited)).rstrip('L')) 814 out.write('L') 815 816 817class PyNoneStructPtr(PyObjectPtr): 818 """ 819 Class wrapping a gdb.Value that's a PyObject* pointing to the 820 singleton (we hope) _Py_NoneStruct with ob_type PyNone_Type 821 """ 822 _typename = 'PyObject' 823 824 def proxyval(self, visited): 825 return None 826 827 828class PyFrameObjectPtr(PyObjectPtr): 829 _typename = 'PyFrameObject' 830 831 def __init__(self, gdbval, cast_to=None): 832 PyObjectPtr.__init__(self, gdbval, cast_to) 833 834 if not self.is_optimized_out(): 835 self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code')) 836 self.co_name = self.co.pyop_field('co_name') 837 self.co_filename = self.co.pyop_field('co_filename') 838 839 self.f_lineno = int_from_int(self.field('f_lineno')) 840 self.f_lasti = int_from_int(self.field('f_lasti')) 841 self.co_nlocals = int_from_int(self.co.field('co_nlocals')) 842 self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames')) 843 844 def iter_locals(self): 845 ''' 846 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for 847 the local variables of this frame 848 ''' 849 if self.is_optimized_out(): 850 return 851 852 f_localsplus = self.field('f_localsplus') 853 for i in safe_range(self.co_nlocals): 854 pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i]) 855 if not pyop_value.is_null(): 856 pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_varnames[i]) 857 yield (pyop_name, pyop_value) 858 859 def iter_globals(self): 860 ''' 861 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for 862 the global variables of this frame 863 ''' 864 if self.is_optimized_out(): 865 return () 866 867 pyop_globals = self.pyop_field('f_globals') 868 return pyop_globals.iteritems() 869 870 def iter_builtins(self): 871 ''' 872 Yield a sequence of (name,value) pairs of PyObjectPtr instances, for 873 the builtin variables 874 ''' 875 if self.is_optimized_out(): 876 return () 877 878 pyop_builtins = self.pyop_field('f_builtins') 879 return pyop_builtins.iteritems() 880 881 def get_var_by_name(self, name): 882 ''' 883 Look for the named local variable, returning a (PyObjectPtr, scope) pair 884 where scope is a string 'local', 'global', 'builtin' 885 886 If not found, return (None, None) 887 ''' 888 for pyop_name, pyop_value in self.iter_locals(): 889 if name == pyop_name.proxyval(set()): 890 return pyop_value, 'local' 891 for pyop_name, pyop_value in self.iter_globals(): 892 if name == pyop_name.proxyval(set()): 893 return pyop_value, 'global' 894 for pyop_name, pyop_value in self.iter_builtins(): 895 if name == pyop_name.proxyval(set()): 896 return pyop_value, 'builtin' 897 return None, None 898 899 def filename(self): 900 '''Get the path of the current Python source file, as a string''' 901 if self.is_optimized_out(): 902 return '(frame information optimized out)' 903 return self.co_filename.proxyval(set()) 904 905 def current_line_num(self): 906 '''Get current line number as an integer (1-based) 907 908 Translated from PyFrame_GetLineNumber and PyCode_Addr2Line 909 910 See Objects/lnotab_notes.txt 911 ''' 912 if self.is_optimized_out(): 913 return None 914 f_trace = self.field('f_trace') 915 if long(f_trace) != 0: 916 # we have a non-NULL f_trace: 917 return self.f_lineno 918 else: 919 #try: 920 return self.co.addr2line(self.f_lasti) 921 #except ValueError: 922 # return self.f_lineno 923 924 def current_line(self): 925 '''Get the text of the current source line as a string, with a trailing 926 newline character''' 927 if self.is_optimized_out(): 928 return '(frame information optimized out)' 929 filename = self.filename() 930 try: 931 f = open(filename, 'r') 932 except IOError: 933 return None 934 with f: 935 all_lines = f.readlines() 936 # Convert from 1-based current_line_num to 0-based list offset: 937 return all_lines[self.current_line_num()-1] 938 939 def write_repr(self, out, visited): 940 if self.is_optimized_out(): 941 out.write('(frame information optimized out)') 942 return 943 out.write('Frame 0x%x, for file %s, line %i, in %s (' 944 % (self.as_address(), 945 self.co_filename.proxyval(visited), 946 self.current_line_num(), 947 self.co_name.proxyval(visited))) 948 first = True 949 for pyop_name, pyop_value in self.iter_locals(): 950 if not first: 951 out.write(', ') 952 first = False 953 954 out.write(pyop_name.proxyval(visited)) 955 out.write('=') 956 pyop_value.write_repr(out, visited) 957 958 out.write(')') 959 960 def print_traceback(self): 961 if self.is_optimized_out(): 962 sys.stdout.write(' (frame information optimized out)\n') 963 return 964 visited = set() 965 sys.stdout.write(' File "%s", line %i, in %s\n' 966 % (self.co_filename.proxyval(visited), 967 self.current_line_num(), 968 self.co_name.proxyval(visited))) 969 970class PySetObjectPtr(PyObjectPtr): 971 _typename = 'PySetObject' 972 973 def proxyval(self, visited): 974 # Guard against infinite loops: 975 if self.as_address() in visited: 976 return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name()) 977 visited.add(self.as_address()) 978 979 members = [] 980 table = self.field('table') 981 for i in safe_range(self.field('mask')+1): 982 setentry = table[i] 983 key = setentry['key'] 984 if key != 0: 985 key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited) 986 if key_proxy != '<dummy key>': 987 members.append(key_proxy) 988 if self.safe_tp_name() == 'frozenset': 989 return frozenset(members) 990 else: 991 return set(members) 992 993 def write_repr(self, out, visited): 994 out.write(self.safe_tp_name()) 995 996 # Guard against infinite loops: 997 if self.as_address() in visited: 998 out.write('(...)') 999 return 1000 visited.add(self.as_address()) 1001 1002 out.write('([') 1003 first = True 1004 table = self.field('table') 1005 for i in safe_range(self.field('mask')+1): 1006 setentry = table[i] 1007 key = setentry['key'] 1008 if key != 0: 1009 pyop_key = PyObjectPtr.from_pyobject_ptr(key) 1010 key_proxy = pyop_key.proxyval(visited) # FIXME! 1011 if key_proxy != '<dummy key>': 1012 if not first: 1013 out.write(', ') 1014 first = False 1015 pyop_key.write_repr(out, visited) 1016 out.write('])') 1017 1018 1019class PyStringObjectPtr(PyObjectPtr): 1020 _typename = 'PyStringObject' 1021 1022 def __str__(self): 1023 field_ob_size = self.field('ob_size') 1024 field_ob_sval = self.field('ob_sval') 1025 char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr()) 1026 # When gdb is linked with a Python 3 interpreter, this is really 1027 # a latin-1 mojibake decoding of the original string... 1028 return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)]) 1029 1030 def proxyval(self, visited): 1031 return str(self) 1032 1033 def write_repr(self, out, visited): 1034 val = repr(self.proxyval(visited)) 1035 if sys.version_info[0] >= 3: 1036 val = val.encode('ascii', 'backslashreplace').decode('ascii') 1037 out.write(val) 1038 1039class PyTupleObjectPtr(PyObjectPtr): 1040 _typename = 'PyTupleObject' 1041 1042 def __getitem__(self, i): 1043 # Get the gdb.Value for the (PyObject*) with the given index: 1044 field_ob_item = self.field('ob_item') 1045 return field_ob_item[i] 1046 1047 def proxyval(self, visited): 1048 # Guard against infinite loops: 1049 if self.as_address() in visited: 1050 return ProxyAlreadyVisited('(...)') 1051 visited.add(self.as_address()) 1052 1053 result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited) 1054 for i in safe_range(int_from_int(self.field('ob_size')))]) 1055 return result 1056 1057 def write_repr(self, out, visited): 1058 # Guard against infinite loops: 1059 if self.as_address() in visited: 1060 out.write('(...)') 1061 return 1062 visited.add(self.as_address()) 1063 1064 out.write('(') 1065 for i in safe_range(int_from_int(self.field('ob_size'))): 1066 if i > 0: 1067 out.write(', ') 1068 element = PyObjectPtr.from_pyobject_ptr(self[i]) 1069 element.write_repr(out, visited) 1070 if self.field('ob_size') == 1: 1071 out.write(',)') 1072 else: 1073 out.write(')') 1074 1075class PyTypeObjectPtr(PyObjectPtr): 1076 _typename = 'PyTypeObject' 1077 1078 1079if sys.maxunicode >= 0x10000: 1080 _unichr = unichr 1081else: 1082 # Needed for proper surrogate support if sizeof(Py_UNICODE) is 2 in gdb 1083 def _unichr(x): 1084 if x < 0x10000: 1085 return unichr(x) 1086 x -= 0x10000 1087 ch1 = 0xD800 | (x >> 10) 1088 ch2 = 0xDC00 | (x & 0x3FF) 1089 return unichr(ch1) + unichr(ch2) 1090 1091class PyUnicodeObjectPtr(PyObjectPtr): 1092 _typename = 'PyUnicodeObject' 1093 1094 def char_width(self): 1095 _type_Py_UNICODE = gdb.lookup_type('Py_UNICODE') 1096 return _type_Py_UNICODE.sizeof 1097 1098 def proxyval(self, visited): 1099 # From unicodeobject.h: 1100 # Py_ssize_t length; /* Length of raw Unicode data in buffer */ 1101 # Py_UNICODE *str; /* Raw Unicode buffer */ 1102 field_length = long(self.field('length')) 1103 field_str = self.field('str') 1104 1105 # Gather a list of ints from the Py_UNICODE array; these are either 1106 # UCS-2 or UCS-4 code points: 1107 if self.char_width() > 2: 1108 Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)] 1109 else: 1110 # A more elaborate routine if sizeof(Py_UNICODE) is 2 in the 1111 # inferior process: we must join surrogate pairs. 1112 Py_UNICODEs = [] 1113 i = 0 1114 limit = safety_limit(field_length) 1115 while i < limit: 1116 ucs = int(field_str[i]) 1117 i += 1 1118 if ucs < 0xD800 or ucs >= 0xDC00 or i == field_length: 1119 Py_UNICODEs.append(ucs) 1120 continue 1121 # This could be a surrogate pair. 1122 ucs2 = int(field_str[i]) 1123 if ucs2 < 0xDC00 or ucs2 > 0xDFFF: 1124 continue 1125 code = (ucs & 0x03FF) << 10 1126 code |= ucs2 & 0x03FF 1127 code += 0x00010000 1128 Py_UNICODEs.append(code) 1129 i += 1 1130 1131 # Convert the int code points to unicode characters, and generate a 1132 # local unicode instance. 1133 # This splits surrogate pairs if sizeof(Py_UNICODE) is 2 here (in gdb). 1134 result = u''.join([_unichr(ucs) for ucs in Py_UNICODEs]) 1135 return result 1136 1137 def write_repr(self, out, visited): 1138 val = repr(self.proxyval(visited)) 1139 if sys.version_info[0] >= 3: 1140 val = val.encode('ascii', 'backslashreplace').decode('ascii') 1141 # This ensures the 'u' prefix is printed when gdb is linked 1142 # with a Python 3 interpreter. 1143 out.write('u') 1144 out.write(val.lstrip('u')) 1145 1146 1147def int_from_int(gdbval): 1148 return int(str(gdbval)) 1149 1150 1151def stringify(val): 1152 # TODO: repr() puts everything on one line; pformat can be nicer, but 1153 # can lead to v.long results; this function isolates the choice 1154 if True: 1155 return repr(val) 1156 else: 1157 from pprint import pformat 1158 return pformat(val) 1159 1160 1161class PyObjectPtrPrinter: 1162 "Prints a (PyObject*)" 1163 1164 def __init__ (self, gdbval): 1165 self.gdbval = gdbval 1166 1167 def to_string (self): 1168 pyop = PyObjectPtr.from_pyobject_ptr(self.gdbval) 1169 if True: 1170 return pyop.get_truncated_repr(MAX_OUTPUT_LEN) 1171 else: 1172 # Generate full proxy value then stringify it. 1173 # Doing so could be expensive 1174 proxyval = pyop.proxyval(set()) 1175 return stringify(proxyval) 1176 1177def pretty_printer_lookup(gdbval): 1178 type = gdbval.type.unqualified() 1179 if type.code == gdb.TYPE_CODE_PTR: 1180 type = type.target().unqualified() 1181 t = str(type) 1182 if t in ("PyObject", "PyFrameObject"): 1183 return PyObjectPtrPrinter(gdbval) 1184 1185""" 1186During development, I've been manually invoking the code in this way: 1187(gdb) python 1188 1189import sys 1190sys.path.append('/home/david/coding/python-gdb') 1191import libpython 1192end 1193 1194then reloading it after each edit like this: 1195(gdb) python reload(libpython) 1196 1197The following code should ensure that the prettyprinter is registered 1198if the code is autoloaded by gdb when visiting libpython.so, provided 1199that this python file is installed to the same path as the library (or its 1200.debug file) plus a "-gdb.py" suffix, e.g: 1201 /usr/lib/libpython2.6.so.1.0-gdb.py 1202 /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py 1203""" 1204def register (obj): 1205 if obj == None: 1206 obj = gdb 1207 1208 # Wire up the pretty-printer 1209 obj.pretty_printers.append(pretty_printer_lookup) 1210 1211register (gdb.current_objfile ()) 1212 1213 1214 1215# Unfortunately, the exact API exposed by the gdb module varies somewhat 1216# from build to build 1217# See http://bugs.python.org/issue8279?#msg102276 1218 1219class Frame(object): 1220 ''' 1221 Wrapper for gdb.Frame, adding various methods 1222 ''' 1223 def __init__(self, gdbframe): 1224 self._gdbframe = gdbframe 1225 1226 def older(self): 1227 older = self._gdbframe.older() 1228 if older: 1229 return Frame(older) 1230 else: 1231 return None 1232 1233 def newer(self): 1234 newer = self._gdbframe.newer() 1235 if newer: 1236 return Frame(newer) 1237 else: 1238 return None 1239 1240 def select(self): 1241 '''If supported, select this frame and return True; return False if unsupported 1242 1243 Not all builds have a gdb.Frame.select method; seems to be present on Fedora 12 1244 onwards, but absent on Ubuntu buildbot''' 1245 if not hasattr(self._gdbframe, 'select'): 1246 print ('Unable to select frame: ' 1247 'this build of gdb does not expose a gdb.Frame.select method') 1248 return False 1249 self._gdbframe.select() 1250 return True 1251 1252 def get_index(self): 1253 '''Calculate index of frame, starting at 0 for the newest frame within 1254 this thread''' 1255 index = 0 1256 # Go down until you reach the newest frame: 1257 iter_frame = self 1258 while iter_frame.newer(): 1259 index += 1 1260 iter_frame = iter_frame.newer() 1261 return index 1262 1263 # We divide frames into: 1264 # - "python frames": 1265 # - "bytecode frames" i.e. PyEval_EvalFrameEx 1266 # - "other python frames": things that are of interest from a python 1267 # POV, but aren't bytecode (e.g. GC, GIL) 1268 # - everything else 1269 1270 def is_python_frame(self): 1271 '''Is this a PyEval_EvalFrameEx frame, or some other important 1272 frame? (see is_other_python_frame for what "important" means in this 1273 context)''' 1274 if self.is_evalframeex(): 1275 return True 1276 if self.is_other_python_frame(): 1277 return True 1278 return False 1279 1280 def is_evalframeex(self): 1281 '''Is this a PyEval_EvalFrameEx frame?''' 1282 if self._gdbframe.name() == 'PyEval_EvalFrameEx': 1283 ''' 1284 I believe we also need to filter on the inline 1285 struct frame_id.inline_depth, only regarding frames with 1286 an inline depth of 0 as actually being this function 1287 1288 So we reject those with type gdb.INLINE_FRAME 1289 ''' 1290 if self._gdbframe.type() == gdb.NORMAL_FRAME: 1291 # We have a PyEval_EvalFrameEx frame: 1292 return True 1293 1294 return False 1295 1296 def is_other_python_frame(self): 1297 '''Is this frame worth displaying in python backtraces? 1298 Examples: 1299 - waiting on the GIL 1300 - garbage-collecting 1301 - within a CFunction 1302 If it is, return a descriptive string 1303 For other frames, return False 1304 ''' 1305 if self.is_waiting_for_gil(): 1306 return 'Waiting for the GIL' 1307 elif self.is_gc_collect(): 1308 return 'Garbage-collecting' 1309 else: 1310 # Detect invocations of PyCFunction instances: 1311 older = self.older() 1312 if older and older._gdbframe.name() == 'PyCFunction_Call': 1313 # Within that frame: 1314 # "func" is the local containing the PyObject* of the 1315 # PyCFunctionObject instance 1316 # "f" is the same value, but cast to (PyCFunctionObject*) 1317 # "self" is the (PyObject*) of the 'self' 1318 try: 1319 # Use the prettyprinter for the func: 1320 func = older._gdbframe.read_var('func') 1321 return str(func) 1322 except RuntimeError: 1323 return 'PyCFunction invocation (unable to read "func")' 1324 1325 # This frame isn't worth reporting: 1326 return False 1327 1328 def is_waiting_for_gil(self): 1329 '''Is this frame waiting on the GIL?''' 1330 # This assumes the _POSIX_THREADS version of Python/ceval_gil.h: 1331 name = self._gdbframe.name() 1332 if name: 1333 return ('PyThread_acquire_lock' in name 1334 and 'lock_PyThread_acquire_lock' not in name) 1335 1336 def is_gc_collect(self): 1337 '''Is this frame "collect" within the garbage-collector?''' 1338 return self._gdbframe.name() == 'collect' 1339 1340 def get_pyop(self): 1341 try: 1342 f = self._gdbframe.read_var('f') 1343 frame = PyFrameObjectPtr.from_pyobject_ptr(f) 1344 if not frame.is_optimized_out(): 1345 return frame 1346 # gdb is unable to get the "f" argument of PyEval_EvalFrameEx() 1347 # because it was "optimized out". Try to get "f" from the frame 1348 # of the caller, PyEval_EvalCodeEx(). 1349 orig_frame = frame 1350 caller = self._gdbframe.older() 1351 if caller: 1352 f = caller.read_var('f') 1353 frame = PyFrameObjectPtr.from_pyobject_ptr(f) 1354 if not frame.is_optimized_out(): 1355 return frame 1356 return orig_frame 1357 except ValueError: 1358 return None 1359 1360 @classmethod 1361 def get_selected_frame(cls): 1362 _gdbframe = gdb.selected_frame() 1363 if _gdbframe: 1364 return Frame(_gdbframe) 1365 return None 1366 1367 @classmethod 1368 def get_selected_python_frame(cls): 1369 '''Try to obtain the Frame for the python-related code in the selected 1370 frame, or None''' 1371 frame = cls.get_selected_frame() 1372 1373 while frame: 1374 if frame.is_python_frame(): 1375 return frame 1376 frame = frame.older() 1377 1378 # Not found: 1379 return None 1380 1381 @classmethod 1382 def get_selected_bytecode_frame(cls): 1383 '''Try to obtain the Frame for the python bytecode interpreter in the 1384 selected GDB frame, or None''' 1385 frame = cls.get_selected_frame() 1386 1387 while frame: 1388 if frame.is_evalframeex(): 1389 return frame 1390 frame = frame.older() 1391 1392 # Not found: 1393 return None 1394 1395 def print_summary(self): 1396 if self.is_evalframeex(): 1397 pyop = self.get_pyop() 1398 if pyop: 1399 line = pyop.get_truncated_repr(MAX_OUTPUT_LEN) 1400 write_unicode(sys.stdout, '#%i %s\n' % (self.get_index(), line)) 1401 if not pyop.is_optimized_out(): 1402 line = pyop.current_line() 1403 if line is not None: 1404 sys.stdout.write(' %s\n' % line.strip()) 1405 else: 1406 sys.stdout.write('#%i (unable to read python frame information)\n' % self.get_index()) 1407 else: 1408 info = self.is_other_python_frame() 1409 if info: 1410 sys.stdout.write('#%i %s\n' % (self.get_index(), info)) 1411 else: 1412 sys.stdout.write('#%i\n' % self.get_index()) 1413 1414 def print_traceback(self): 1415 if self.is_evalframeex(): 1416 pyop = self.get_pyop() 1417 if pyop: 1418 pyop.print_traceback() 1419 if not pyop.is_optimized_out(): 1420 line = pyop.current_line() 1421 if line is not None: 1422 sys.stdout.write(' %s\n' % line.strip()) 1423 else: 1424 sys.stdout.write(' (unable to read python frame information)\n') 1425 else: 1426 info = self.is_other_python_frame() 1427 if info: 1428 sys.stdout.write(' %s\n' % info) 1429 else: 1430 sys.stdout.write(' (not a python frame)\n') 1431 1432class PyList(gdb.Command): 1433 '''List the current Python source code, if any 1434 1435 Use 1436 py-list START 1437 to list at a different line number within the python source. 1438 1439 Use 1440 py-list START, END 1441 to list a specific range of lines within the python source. 1442 ''' 1443 1444 def __init__(self): 1445 gdb.Command.__init__ (self, 1446 "py-list", 1447 gdb.COMMAND_FILES, 1448 gdb.COMPLETE_NONE) 1449 1450 1451 def invoke(self, args, from_tty): 1452 import re 1453 1454 start = None 1455 end = None 1456 1457 m = re.match(r'\s*(\d+)\s*', args) 1458 if m: 1459 start = int(m.group(0)) 1460 end = start + 10 1461 1462 m = re.match(r'\s*(\d+)\s*,\s*(\d+)\s*', args) 1463 if m: 1464 start, end = map(int, m.groups()) 1465 1466 # py-list requires an actual PyEval_EvalFrameEx frame: 1467 frame = Frame.get_selected_bytecode_frame() 1468 if not frame: 1469 print('Unable to locate gdb frame for python bytecode interpreter') 1470 return 1471 1472 pyop = frame.get_pyop() 1473 if not pyop or pyop.is_optimized_out(): 1474 print('Unable to read information on python frame') 1475 return 1476 1477 filename = pyop.filename() 1478 lineno = pyop.current_line_num() 1479 1480 if start is None: 1481 start = lineno - 5 1482 end = lineno + 5 1483 1484 if start<1: 1485 start = 1 1486 1487 try: 1488 f = open(filename, 'r') 1489 except IOError as err: 1490 sys.stdout.write('Unable to open %s: %s\n' 1491 % (filename, err)) 1492 return 1493 with f: 1494 all_lines = f.readlines() 1495 # start and end are 1-based, all_lines is 0-based; 1496 # so [start-1:end] as a python slice gives us [start, end] as a 1497 # closed interval 1498 for i, line in enumerate(all_lines[start-1:end]): 1499 linestr = str(i+start) 1500 # Highlight current line: 1501 if i + start == lineno: 1502 linestr = '>' + linestr 1503 sys.stdout.write('%4s %s' % (linestr, line)) 1504 1505 1506# ...and register the command: 1507PyList() 1508 1509def move_in_stack(move_up): 1510 '''Move up or down the stack (for the py-up/py-down command)''' 1511 frame = Frame.get_selected_python_frame() 1512 while frame: 1513 if move_up: 1514 iter_frame = frame.older() 1515 else: 1516 iter_frame = frame.newer() 1517 1518 if not iter_frame: 1519 break 1520 1521 if iter_frame.is_python_frame(): 1522 # Result: 1523 if iter_frame.select(): 1524 iter_frame.print_summary() 1525 return 1526 1527 frame = iter_frame 1528 1529 if move_up: 1530 print('Unable to find an older python frame') 1531 else: 1532 print('Unable to find a newer python frame') 1533 1534class PyUp(gdb.Command): 1535 'Select and print the python stack frame that called this one (if any)' 1536 def __init__(self): 1537 gdb.Command.__init__ (self, 1538 "py-up", 1539 gdb.COMMAND_STACK, 1540 gdb.COMPLETE_NONE) 1541 1542 1543 def invoke(self, args, from_tty): 1544 move_in_stack(move_up=True) 1545 1546class PyDown(gdb.Command): 1547 'Select and print the python stack frame called by this one (if any)' 1548 def __init__(self): 1549 gdb.Command.__init__ (self, 1550 "py-down", 1551 gdb.COMMAND_STACK, 1552 gdb.COMPLETE_NONE) 1553 1554 1555 def invoke(self, args, from_tty): 1556 move_in_stack(move_up=False) 1557 1558# Not all builds of gdb have gdb.Frame.select 1559if hasattr(gdb.Frame, 'select'): 1560 PyUp() 1561 PyDown() 1562 1563class PyBacktraceFull(gdb.Command): 1564 'Display the current python frame and all the frames within its call stack (if any)' 1565 def __init__(self): 1566 gdb.Command.__init__ (self, 1567 "py-bt-full", 1568 gdb.COMMAND_STACK, 1569 gdb.COMPLETE_NONE) 1570 1571 1572 def invoke(self, args, from_tty): 1573 frame = Frame.get_selected_python_frame() 1574 while frame: 1575 if frame.is_python_frame(): 1576 frame.print_summary() 1577 frame = frame.older() 1578 1579PyBacktraceFull() 1580 1581class PyBacktrace(gdb.Command): 1582 'Display the current python frame and all the frames within its call stack (if any)' 1583 def __init__(self): 1584 gdb.Command.__init__ (self, 1585 "py-bt", 1586 gdb.COMMAND_STACK, 1587 gdb.COMPLETE_NONE) 1588 1589 1590 def invoke(self, args, from_tty): 1591 sys.stdout.write('Traceback (most recent call first):\n') 1592 frame = Frame.get_selected_python_frame() 1593 while frame: 1594 if frame.is_python_frame(): 1595 frame.print_traceback() 1596 frame = frame.older() 1597 1598PyBacktrace() 1599 1600class PyPrint(gdb.Command): 1601 'Look up the given python variable name, and print it' 1602 def __init__(self): 1603 gdb.Command.__init__ (self, 1604 "py-print", 1605 gdb.COMMAND_DATA, 1606 gdb.COMPLETE_NONE) 1607 1608 1609 def invoke(self, args, from_tty): 1610 name = str(args) 1611 1612 frame = Frame.get_selected_python_frame() 1613 if not frame: 1614 print('Unable to locate python frame') 1615 return 1616 1617 pyop_frame = frame.get_pyop() 1618 if not pyop_frame: 1619 print('Unable to read information on python frame') 1620 return 1621 1622 pyop_var, scope = pyop_frame.get_var_by_name(name) 1623 1624 if pyop_var: 1625 print('%s %r = %s' 1626 % (scope, 1627 name, 1628 pyop_var.get_truncated_repr(MAX_OUTPUT_LEN))) 1629 else: 1630 print('%r not found' % name) 1631 1632PyPrint() 1633 1634class PyLocals(gdb.Command): 1635 'Look up the given python variable name, and print it' 1636 def __init__(self): 1637 gdb.Command.__init__ (self, 1638 "py-locals", 1639 gdb.COMMAND_DATA, 1640 gdb.COMPLETE_NONE) 1641 1642 1643 def invoke(self, args, from_tty): 1644 name = str(args) 1645 1646 frame = Frame.get_selected_python_frame() 1647 if not frame: 1648 print('Unable to locate python frame') 1649 return 1650 1651 pyop_frame = frame.get_pyop() 1652 if not pyop_frame: 1653 print('Unable to read information on python frame') 1654 return 1655 1656 for pyop_name, pyop_value in pyop_frame.iter_locals(): 1657 print('%s = %s' 1658 % (pyop_name.proxyval(set()), 1659 pyop_value.get_truncated_repr(MAX_OUTPUT_LEN))) 1660 1661PyLocals() 1662