1##===-- lldbutil.py ------------------------------------------*- Python -*-===## 2## 3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4# See https://llvm.org/LICENSE.txt for license information. 5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6## 7##===----------------------------------------------------------------------===## 8 9""" 10This LLDB module contains miscellaneous utilities. 11Some of the test suite takes advantage of the utility functions defined here. 12They can also be useful for general purpose lldb scripting. 13""" 14 15import lldb 16import os 17import sys 18import io 19 20# =================================================== 21# Utilities for locating/checking executable programs 22# =================================================== 23 24 25def is_exe(fpath): 26 """Returns True if fpath is an executable.""" 27 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 28 29 30def which(program): 31 """Returns the full path to a program; None otherwise.""" 32 fpath, fname = os.path.split(program) 33 if fpath: 34 if is_exe(program): 35 return program 36 else: 37 for path in os.environ["PATH"].split(os.pathsep): 38 exe_file = os.path.join(path, program) 39 if is_exe(exe_file): 40 return exe_file 41 return None 42 43 44# =================================================== 45# Disassembly for an SBFunction or an SBSymbol object 46# =================================================== 47 48 49def disassemble(target, function_or_symbol): 50 """Disassemble the function or symbol given a target. 51 52 It returns the disassembly content in a string object. 53 """ 54 buf = io.StringIO() 55 insts = function_or_symbol.GetInstructions(target) 56 for i in insts: 57 print(i, file=buf) 58 return buf.getvalue() 59 60 61# ========================================================== 62# Integer (byte size 1, 2, 4, and 8) to bytearray conversion 63# ========================================================== 64 65 66def int_to_bytearray(val, bytesize): 67 """Utility function to convert an integer into a bytearray. 68 69 It returns the bytearray in the little endian format. It is easy to get the 70 big endian format, just do ba.reverse() on the returned object. 71 """ 72 import struct 73 74 if bytesize == 1: 75 return bytearray([val]) 76 77 # Little endian followed by a format character. 78 template = "<%c" 79 if bytesize == 2: 80 fmt = template % "h" 81 elif bytesize == 4: 82 fmt = template % "i" 83 elif bytesize == 4: 84 fmt = template % "q" 85 else: 86 return None 87 88 packed = struct.pack(fmt, val) 89 return bytearray(ord(x) for x in packed) 90 91 92def bytearray_to_int(bytes, bytesize): 93 """Utility function to convert a bytearray into an integer. 94 95 It interprets the bytearray in the little endian format. For a big endian 96 bytearray, just do ba.reverse() on the object before passing it in. 97 """ 98 import struct 99 100 if bytesize == 1: 101 return bytes[0] 102 103 # Little endian followed by a format character. 104 template = "<%c" 105 if bytesize == 2: 106 fmt = template % "h" 107 elif bytesize == 4: 108 fmt = template % "i" 109 elif bytesize == 4: 110 fmt = template % "q" 111 else: 112 return None 113 114 unpacked = struct.unpack(fmt, str(bytes)) 115 return unpacked[0] 116 117 118# ============================================================== 119# Get the description of an lldb object or None if not available 120# ============================================================== 121def get_description(obj, option=None): 122 """Calls lldb_obj.GetDescription() and returns a string, or None. 123 124 For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra 125 option can be passed in to describe the detailed level of description 126 desired: 127 o lldb.eDescriptionLevelBrief 128 o lldb.eDescriptionLevelFull 129 o lldb.eDescriptionLevelVerbose 130 """ 131 method = getattr(obj, "GetDescription") 132 if not method: 133 return None 134 tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) 135 if isinstance(obj, tuple): 136 if option is None: 137 option = lldb.eDescriptionLevelBrief 138 139 stream = lldb.SBStream() 140 if option is None: 141 success = method(stream) 142 else: 143 success = method(stream, option) 144 if not success: 145 return None 146 return stream.GetData() 147 148 149# ================================================= 150# Convert some enum value to its string counterpart 151# ================================================= 152 153 154def state_type_to_str(enum): 155 """Returns the stateType string given an enum.""" 156 if enum == lldb.eStateInvalid: 157 return "invalid" 158 elif enum == lldb.eStateUnloaded: 159 return "unloaded" 160 elif enum == lldb.eStateConnected: 161 return "connected" 162 elif enum == lldb.eStateAttaching: 163 return "attaching" 164 elif enum == lldb.eStateLaunching: 165 return "launching" 166 elif enum == lldb.eStateStopped: 167 return "stopped" 168 elif enum == lldb.eStateRunning: 169 return "running" 170 elif enum == lldb.eStateStepping: 171 return "stepping" 172 elif enum == lldb.eStateCrashed: 173 return "crashed" 174 elif enum == lldb.eStateDetached: 175 return "detached" 176 elif enum == lldb.eStateExited: 177 return "exited" 178 elif enum == lldb.eStateSuspended: 179 return "suspended" 180 else: 181 raise Exception("Unknown StateType enum") 182 183 184def stop_reason_to_str(enum): 185 """Returns the stopReason string given an enum.""" 186 if enum == lldb.eStopReasonInvalid: 187 return "invalid" 188 elif enum == lldb.eStopReasonNone: 189 return "none" 190 elif enum == lldb.eStopReasonTrace: 191 return "trace" 192 elif enum == lldb.eStopReasonBreakpoint: 193 return "breakpoint" 194 elif enum == lldb.eStopReasonWatchpoint: 195 return "watchpoint" 196 elif enum == lldb.eStopReasonSignal: 197 return "signal" 198 elif enum == lldb.eStopReasonException: 199 return "exception" 200 elif enum == lldb.eStopReasonPlanComplete: 201 return "plancomplete" 202 elif enum == lldb.eStopReasonThreadExiting: 203 return "threadexiting" 204 else: 205 raise Exception("Unknown StopReason enum") 206 207 208def symbol_type_to_str(enum): 209 """Returns the symbolType string given an enum.""" 210 if enum == lldb.eSymbolTypeInvalid: 211 return "invalid" 212 elif enum == lldb.eSymbolTypeAbsolute: 213 return "absolute" 214 elif enum == lldb.eSymbolTypeCode: 215 return "code" 216 elif enum == lldb.eSymbolTypeData: 217 return "data" 218 elif enum == lldb.eSymbolTypeTrampoline: 219 return "trampoline" 220 elif enum == lldb.eSymbolTypeRuntime: 221 return "runtime" 222 elif enum == lldb.eSymbolTypeException: 223 return "exception" 224 elif enum == lldb.eSymbolTypeSourceFile: 225 return "sourcefile" 226 elif enum == lldb.eSymbolTypeHeaderFile: 227 return "headerfile" 228 elif enum == lldb.eSymbolTypeObjectFile: 229 return "objectfile" 230 elif enum == lldb.eSymbolTypeCommonBlock: 231 return "commonblock" 232 elif enum == lldb.eSymbolTypeBlock: 233 return "block" 234 elif enum == lldb.eSymbolTypeLocal: 235 return "local" 236 elif enum == lldb.eSymbolTypeParam: 237 return "param" 238 elif enum == lldb.eSymbolTypeVariable: 239 return "variable" 240 elif enum == lldb.eSymbolTypeVariableType: 241 return "variabletype" 242 elif enum == lldb.eSymbolTypeLineEntry: 243 return "lineentry" 244 elif enum == lldb.eSymbolTypeLineHeader: 245 return "lineheader" 246 elif enum == lldb.eSymbolTypeScopeBegin: 247 return "scopebegin" 248 elif enum == lldb.eSymbolTypeScopeEnd: 249 return "scopeend" 250 elif enum == lldb.eSymbolTypeAdditional: 251 return "additional" 252 elif enum == lldb.eSymbolTypeCompiler: 253 return "compiler" 254 elif enum == lldb.eSymbolTypeInstrumentation: 255 return "instrumentation" 256 elif enum == lldb.eSymbolTypeUndefined: 257 return "undefined" 258 259 260def value_type_to_str(enum): 261 """Returns the valueType string given an enum.""" 262 if enum == lldb.eValueTypeInvalid: 263 return "invalid" 264 elif enum == lldb.eValueTypeVariableGlobal: 265 return "global_variable" 266 elif enum == lldb.eValueTypeVariableStatic: 267 return "static_variable" 268 elif enum == lldb.eValueTypeVariableArgument: 269 return "argument_variable" 270 elif enum == lldb.eValueTypeVariableLocal: 271 return "local_variable" 272 elif enum == lldb.eValueTypeRegister: 273 return "register" 274 elif enum == lldb.eValueTypeRegisterSet: 275 return "register_set" 276 elif enum == lldb.eValueTypeConstResult: 277 return "constant_result" 278 else: 279 raise Exception("Unknown ValueType enum") 280 281 282# ================================================== 283# Get stopped threads due to each stop reason. 284# ================================================== 285 286 287def sort_stopped_threads( 288 process, 289 breakpoint_threads=None, 290 crashed_threads=None, 291 watchpoint_threads=None, 292 signal_threads=None, 293 exiting_threads=None, 294 other_threads=None, 295): 296 """Fills array *_threads with threads stopped for the corresponding stop 297 reason. 298 """ 299 for lst in [ 300 breakpoint_threads, 301 watchpoint_threads, 302 signal_threads, 303 exiting_threads, 304 other_threads, 305 ]: 306 if lst is not None: 307 lst[:] = [] 308 309 for thread in process: 310 dispatched = False 311 for reason, list in [ 312 (lldb.eStopReasonBreakpoint, breakpoint_threads), 313 (lldb.eStopReasonException, crashed_threads), 314 (lldb.eStopReasonWatchpoint, watchpoint_threads), 315 (lldb.eStopReasonSignal, signal_threads), 316 (lldb.eStopReasonThreadExiting, exiting_threads), 317 (None, other_threads), 318 ]: 319 if not dispatched and list is not None: 320 if thread.GetStopReason() == reason or reason is None: 321 list.append(thread) 322 dispatched = True 323 324 325# ================================================== 326# Utility functions for setting breakpoints 327# ================================================== 328 329 330def run_break_set_by_file_and_line( 331 test, 332 file_name, 333 line_number, 334 extra_options=None, 335 num_expected_locations=1, 336 loc_exact=False, 337 module_name=None, 338): 339 """Set a breakpoint by file and line, returning the breakpoint number. 340 341 If extra_options is not None, then we append it to the breakpoint set command. 342 343 If num_expected_locations is -1 we check that we got AT LEAST one location, otherwise we check that num_expected_locations equals the number of locations. 344 345 If loc_exact is true, we check that there is one location, and that location must be at the input file and line number. 346 """ 347 348 if file_name is None: 349 command = "breakpoint set -l %d" % (line_number) 350 else: 351 command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) 352 353 if module_name: 354 command += " --shlib '%s'" % (module_name) 355 356 if extra_options: 357 command += " " + extra_options 358 359 break_results = run_break_set_command(test, command) 360 361 if num_expected_locations == 1 and loc_exact: 362 check_breakpoint_result( 363 test, 364 break_results, 365 num_locations=num_expected_locations, 366 file_name=file_name, 367 line_number=line_number, 368 module_name=module_name, 369 ) 370 else: 371 check_breakpoint_result( 372 test, break_results, num_locations=num_expected_locations 373 ) 374 375 return get_bpno_from_match(break_results) 376 377 378def run_break_set_by_symbol( 379 test, 380 symbol, 381 extra_options=None, 382 num_expected_locations=-1, 383 sym_exact=False, 384 module_name=None, 385): 386 """Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line. 387 388 If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match. 389 """ 390 command = 'breakpoint set -n "%s"' % (symbol) 391 392 if module_name: 393 command += " --shlib '%s'" % (module_name) 394 395 if extra_options: 396 command += " " + extra_options 397 398 break_results = run_break_set_command(test, command) 399 400 if num_expected_locations == 1 and sym_exact: 401 check_breakpoint_result( 402 test, 403 break_results, 404 num_locations=num_expected_locations, 405 symbol_name=symbol, 406 module_name=module_name, 407 ) 408 else: 409 check_breakpoint_result( 410 test, break_results, num_locations=num_expected_locations 411 ) 412 413 return get_bpno_from_match(break_results) 414 415 416def run_break_set_by_selector( 417 test, selector, extra_options=None, num_expected_locations=-1, module_name=None 418): 419 """Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line.""" 420 421 command = 'breakpoint set -S "%s"' % (selector) 422 423 if module_name: 424 command += ' --shlib "%s"' % (module_name) 425 426 if extra_options: 427 command += " " + extra_options 428 429 break_results = run_break_set_command(test, command) 430 431 if num_expected_locations == 1: 432 check_breakpoint_result( 433 test, 434 break_results, 435 num_locations=num_expected_locations, 436 symbol_name=selector, 437 symbol_match_exact=False, 438 module_name=module_name, 439 ) 440 else: 441 check_breakpoint_result( 442 test, break_results, num_locations=num_expected_locations 443 ) 444 445 return get_bpno_from_match(break_results) 446 447 448def run_break_set_by_regexp( 449 test, regexp, extra_options=None, num_expected_locations=-1 450): 451 """Set a breakpoint by regular expression match on symbol name. Common options are the same as run_break_set_by_file_and_line.""" 452 453 command = 'breakpoint set -r "%s"' % (regexp) 454 if extra_options: 455 command += " " + extra_options 456 457 break_results = run_break_set_command(test, command) 458 459 check_breakpoint_result(test, break_results, num_locations=num_expected_locations) 460 461 return get_bpno_from_match(break_results) 462 463 464def run_break_set_by_source_regexp( 465 test, regexp, extra_options=None, num_expected_locations=-1 466): 467 """Set a breakpoint by source regular expression. Common options are the same as run_break_set_by_file_and_line.""" 468 command = 'breakpoint set -p "%s"' % (regexp) 469 if extra_options: 470 command += " " + extra_options 471 472 break_results = run_break_set_command(test, command) 473 474 check_breakpoint_result(test, break_results, num_locations=num_expected_locations) 475 476 return get_bpno_from_match(break_results) 477 478 479def run_break_set_command(test, command): 480 """Run the command passed in - it must be some break set variant - and analyze the result. 481 Returns a dictionary of information gleaned from the command-line results. 482 Will assert if the breakpoint setting fails altogether. 483 484 Dictionary will contain: 485 bpno - breakpoint of the newly created breakpoint, -1 on error. 486 num_locations - number of locations set for the breakpoint. 487 488 If there is only one location, the dictionary MAY contain: 489 file - source file name 490 line_no - source line number 491 symbol - symbol name 492 inline_symbol - inlined symbol name 493 offset - offset from the original symbol 494 module - module 495 address - address at which the breakpoint was set.""" 496 497 patterns = [ 498 r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$", 499 r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", 500 r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$", 501 r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$", 502 ] 503 match_object = test.match(command, patterns) 504 break_results = match_object.groupdict() 505 506 # We always insert the breakpoint number, setting it to -1 if we couldn't find it 507 # Also, make sure it gets stored as an integer. 508 if not "bpno" in break_results: 509 break_results["bpno"] = -1 510 else: 511 break_results["bpno"] = int(break_results["bpno"]) 512 513 # We always insert the number of locations 514 # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1... 515 # We also make sure it is an integer. 516 517 if not "num_locations" in break_results: 518 num_locations = 1 519 else: 520 num_locations = break_results["num_locations"] 521 if num_locations == "no": 522 num_locations = 0 523 else: 524 num_locations = int(break_results["num_locations"]) 525 526 break_results["num_locations"] = num_locations 527 528 if "line_no" in break_results: 529 break_results["line_no"] = int(break_results["line_no"]) 530 531 return break_results 532 533 534def get_bpno_from_match(break_results): 535 return int(break_results["bpno"]) 536 537 538def check_breakpoint_result( 539 test, 540 break_results, 541 file_name=None, 542 line_number=-1, 543 symbol_name=None, 544 symbol_match_exact=True, 545 module_name=None, 546 offset=-1, 547 num_locations=-1, 548): 549 out_num_locations = break_results["num_locations"] 550 551 if num_locations == -1: 552 test.assertTrue( 553 out_num_locations > 0, "Expecting one or more locations, got none." 554 ) 555 else: 556 test.assertTrue( 557 num_locations == out_num_locations, 558 "Expecting %d locations, got %d." % (num_locations, out_num_locations), 559 ) 560 561 if file_name: 562 out_file_name = "" 563 if "file" in break_results: 564 out_file_name = break_results["file"] 565 test.assertTrue( 566 file_name == out_file_name, 567 "Breakpoint file name '%s' doesn't match resultant name '%s'." 568 % (file_name, out_file_name), 569 ) 570 571 if line_number != -1: 572 out_file_line = -1 573 if "line_no" in break_results: 574 out_line_number = break_results["line_no"] 575 576 test.assertTrue( 577 line_number == out_line_number, 578 "Breakpoint line number %s doesn't match resultant line %s." 579 % (line_number, out_line_number), 580 ) 581 582 if symbol_name: 583 out_symbol_name = "" 584 # Look first for the inlined symbol name, otherwise use the symbol 585 # name: 586 if "inline_symbol" in break_results and break_results["inline_symbol"]: 587 out_symbol_name = break_results["inline_symbol"] 588 elif "symbol" in break_results: 589 out_symbol_name = break_results["symbol"] 590 591 if symbol_match_exact: 592 test.assertTrue( 593 symbol_name == out_symbol_name, 594 "Symbol name '%s' doesn't match resultant symbol '%s'." 595 % (symbol_name, out_symbol_name), 596 ) 597 else: 598 test.assertTrue( 599 out_symbol_name.find(symbol_name) != -1, 600 "Symbol name '%s' isn't in resultant symbol '%s'." 601 % (symbol_name, out_symbol_name), 602 ) 603 604 if module_name: 605 out_nodule_name = None 606 if "module" in break_results: 607 out_module_name = break_results["module"] 608 609 test.assertTrue( 610 module_name.find(out_module_name) != -1, 611 "Symbol module name '%s' isn't in expected module name '%s'." 612 % (out_module_name, module_name), 613 ) 614 615 616# ================================================== 617# Utility functions related to Threads and Processes 618# ================================================== 619 620 621def get_stopped_threads(process, reason): 622 """Returns the thread(s) with the specified stop reason in a list. 623 624 The list can be empty if no such thread exists. 625 """ 626 threads = [] 627 for t in process: 628 if t.GetStopReason() == reason: 629 threads.append(t) 630 return threads 631 632 633def get_stopped_thread(process, reason): 634 """A convenience function which returns the first thread with the given stop 635 reason or None. 636 637 Example usages: 638 639 1. Get the stopped thread due to a breakpoint condition 640 641 ... 642 from lldbutil import get_stopped_thread 643 thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete) 644 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition") 645 ... 646 647 2. Get the thread stopped due to a breakpoint 648 649 ... 650 from lldbutil import get_stopped_thread 651 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 652 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint") 653 ... 654 655 """ 656 threads = get_stopped_threads(process, reason) 657 if len(threads) == 0: 658 return None 659 return threads[0] 660 661 662def get_threads_stopped_at_breakpoint(process, bkpt): 663 """For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" 664 stopped_threads = [] 665 threads = [] 666 667 stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint) 668 669 if len(stopped_threads) == 0: 670 return threads 671 672 for thread in stopped_threads: 673 # Make sure we've hit our breakpoint... 674 break_id = thread.GetStopReasonDataAtIndex(0) 675 if break_id == bkpt.GetID(): 676 threads.append(thread) 677 678 return threads 679 680 681def continue_to_breakpoint(process, bkpt): 682 """Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" 683 process.Continue() 684 if process.GetState() != lldb.eStateStopped: 685 return None 686 else: 687 return get_threads_stopped_at_breakpoint(process, bkpt) 688 689 690def get_caller_symbol(thread): 691 """ 692 Returns the symbol name for the call site of the leaf function. 693 """ 694 depth = thread.GetNumFrames() 695 if depth <= 1: 696 return None 697 caller = thread.GetFrameAtIndex(1).GetSymbol() 698 if caller: 699 return caller.GetName() 700 else: 701 return None 702 703 704def get_function_names(thread): 705 """ 706 Returns a sequence of function names from the stack frames of this thread. 707 """ 708 709 def GetFuncName(i): 710 return thread.GetFrameAtIndex(i).GetFunctionName() 711 712 return [GetFuncName(i) for i in range(thread.GetNumFrames())] 713 714 715def get_symbol_names(thread): 716 """ 717 Returns a sequence of symbols for this thread. 718 """ 719 720 def GetSymbol(i): 721 return thread.GetFrameAtIndex(i).GetSymbol().GetName() 722 723 return [GetSymbol(i) for i in range(thread.GetNumFrames())] 724 725 726def get_pc_addresses(thread): 727 """ 728 Returns a sequence of pc addresses for this thread. 729 """ 730 731 def GetPCAddress(i): 732 return thread.GetFrameAtIndex(i).GetPCAddress() 733 734 return [GetPCAddress(i) for i in range(thread.GetNumFrames())] 735 736 737def get_filenames(thread): 738 """ 739 Returns a sequence of file names from the stack frames of this thread. 740 """ 741 742 def GetFilename(i): 743 return thread.GetFrameAtIndex(i).GetLineEntry().GetFileSpec().GetFilename() 744 745 return [GetFilename(i) for i in range(thread.GetNumFrames())] 746 747 748def get_line_numbers(thread): 749 """ 750 Returns a sequence of line numbers from the stack frames of this thread. 751 """ 752 753 def GetLineNumber(i): 754 return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() 755 756 return [GetLineNumber(i) for i in range(thread.GetNumFrames())] 757 758 759def get_module_names(thread): 760 """ 761 Returns a sequence of module names from the stack frames of this thread. 762 """ 763 764 def GetModuleName(i): 765 return thread.GetFrameAtIndex(i).GetModule().GetFileSpec().GetFilename() 766 767 return [GetModuleName(i) for i in range(thread.GetNumFrames())] 768 769 770def get_stack_frames(thread): 771 """ 772 Returns a sequence of stack frames for this thread. 773 """ 774 775 def GetStackFrame(i): 776 return thread.GetFrameAtIndex(i) 777 778 return [GetStackFrame(i) for i in range(thread.GetNumFrames())] 779 780 781def print_stacktrace(thread, string_buffer=False): 782 """Prints a simple stack trace of this thread.""" 783 784 output = io.StringIO() if string_buffer else sys.stdout 785 target = thread.GetProcess().GetTarget() 786 787 depth = thread.GetNumFrames() 788 789 mods = get_module_names(thread) 790 funcs = get_function_names(thread) 791 symbols = get_symbol_names(thread) 792 files = get_filenames(thread) 793 lines = get_line_numbers(thread) 794 addrs = get_pc_addresses(thread) 795 796 if thread.GetStopReason() != lldb.eStopReasonInvalid: 797 desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) 798 else: 799 desc = "" 800 print( 801 "Stack trace for thread id={0:#x} name={1} queue={2} ".format( 802 thread.GetThreadID(), thread.GetName(), thread.GetQueueName() 803 ) 804 + desc, 805 file=output, 806 ) 807 808 for i in range(depth): 809 frame = thread.GetFrameAtIndex(i) 810 function = frame.GetFunction() 811 812 load_addr = addrs[i].GetLoadAddress(target) 813 if not function: 814 file_addr = addrs[i].GetFileAddress() 815 start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress() 816 symbol_offset = file_addr - start_addr 817 print( 818 " frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format( 819 num=i, 820 addr=load_addr, 821 mod=mods[i], 822 symbol=symbols[i], 823 offset=symbol_offset, 824 ), 825 file=output, 826 ) 827 else: 828 print( 829 " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format( 830 num=i, 831 addr=load_addr, 832 mod=mods[i], 833 func="%s [inlined]" % funcs[i] if frame.IsInlined() else funcs[i], 834 file=files[i], 835 line=lines[i], 836 args=get_args_as_string(frame, showFuncName=False) 837 if not frame.IsInlined() 838 else "()", 839 ), 840 file=output, 841 ) 842 843 if string_buffer: 844 return output.getvalue() 845 846 847def print_stacktraces(process, string_buffer=False): 848 """Prints the stack traces of all the threads.""" 849 850 output = io.StringIO() if string_buffer else sys.stdout 851 852 print("Stack traces for " + str(process), file=output) 853 854 for thread in process: 855 print(print_stacktrace(thread, string_buffer=True), file=output) 856 857 if string_buffer: 858 return output.getvalue() 859 860 861# =================================== 862# Utility functions related to Frames 863# =================================== 864 865 866def get_parent_frame(frame): 867 """ 868 Returns the parent frame of the input frame object; None if not available. 869 """ 870 thread = frame.GetThread() 871 parent_found = False 872 for f in thread: 873 if parent_found: 874 return f 875 if f.GetFrameID() == frame.GetFrameID(): 876 parent_found = True 877 878 # If we reach here, no parent has been found, return None. 879 return None 880 881 882def get_args_as_string(frame, showFuncName=True): 883 """ 884 Returns the args of the input frame object as a string. 885 """ 886 # arguments => True 887 # locals => False 888 # statics => False 889 # in_scope_only => True 890 vars = frame.GetVariables(True, False, False, True) # type of SBValueList 891 args = [] # list of strings 892 for var in vars: 893 args.append("(%s)%s=%s" % (var.GetTypeName(), var.GetName(), var.GetValue())) 894 if frame.GetFunction(): 895 name = frame.GetFunction().GetName() 896 elif frame.GetSymbol(): 897 name = frame.GetSymbol().GetName() 898 else: 899 name = "" 900 if showFuncName: 901 return "%s(%s)" % (name, ", ".join(args)) 902 else: 903 return "(%s)" % (", ".join(args)) 904 905 906def print_registers(frame, string_buffer=False): 907 """Prints all the register sets of the frame.""" 908 909 output = io.StringIO() if string_buffer else sys.stdout 910 911 print("Register sets for " + str(frame), file=output) 912 913 registerSet = frame.GetRegisters() # Return type of SBValueList. 914 print( 915 "Frame registers (size of register set = %d):" % registerSet.GetSize(), 916 file=output, 917 ) 918 for value in registerSet: 919 # print >> output, value 920 print( 921 "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()), 922 file=output, 923 ) 924 for child in value: 925 print( 926 "Name: %s, Value: %s" % (child.GetName(), child.GetValue()), file=output 927 ) 928 929 if string_buffer: 930 return output.getvalue() 931 932 933def get_registers(frame, kind): 934 """Returns the registers given the frame and the kind of registers desired. 935 936 Returns None if there's no such kind. 937 """ 938 registerSet = frame.GetRegisters() # Return type of SBValueList. 939 for value in registerSet: 940 if kind.lower() in value.GetName().lower(): 941 return value 942 943 return None 944 945 946def get_GPRs(frame): 947 """Returns the general purpose registers of the frame as an SBValue. 948 949 The returned SBValue object is iterable. An example: 950 ... 951 from lldbutil import get_GPRs 952 regs = get_GPRs(frame) 953 for reg in regs: 954 print "%s => %s" % (reg.GetName(), reg.GetValue()) 955 ... 956 """ 957 return get_registers(frame, "general purpose") 958 959 960def get_FPRs(frame): 961 """Returns the floating point registers of the frame as an SBValue. 962 963 The returned SBValue object is iterable. An example: 964 ... 965 from lldbutil import get_FPRs 966 regs = get_FPRs(frame) 967 for reg in regs: 968 print "%s => %s" % (reg.GetName(), reg.GetValue()) 969 ... 970 """ 971 return get_registers(frame, "floating point") 972 973 974def get_ESRs(frame): 975 """Returns the exception state registers of the frame as an SBValue. 976 977 The returned SBValue object is iterable. An example: 978 ... 979 from lldbutil import get_ESRs 980 regs = get_ESRs(frame) 981 for reg in regs: 982 print "%s => %s" % (reg.GetName(), reg.GetValue()) 983 ... 984 """ 985 return get_registers(frame, "exception state") 986 987 988# ====================================== 989# Utility classes/functions for SBValues 990# ====================================== 991 992 993class BasicFormatter(object): 994 """The basic formatter inspects the value object and prints the value.""" 995 996 def format(self, value, buffer=None, indent=0): 997 if not buffer: 998 output = io.StringIO() 999 else: 1000 output = buffer 1001 # If there is a summary, it suffices. 1002 val = value.GetSummary() 1003 # Otherwise, get the value. 1004 if val is None: 1005 val = value.GetValue() 1006 if val is None and value.GetNumChildren() > 0: 1007 val = "%s (location)" % value.GetLocation() 1008 print( 1009 "{indentation}({type}) {name} = {value}".format( 1010 indentation=" " * indent, 1011 type=value.GetTypeName(), 1012 name=value.GetName(), 1013 value=val, 1014 ), 1015 file=output, 1016 ) 1017 return output.getvalue() 1018 1019 1020class ChildVisitingFormatter(BasicFormatter): 1021 """The child visiting formatter prints the value and its immediate children. 1022 1023 The constructor takes a keyword arg: indent_child, which defaults to 2. 1024 """ 1025 1026 def __init__(self, indent_child=2): 1027 """Default indentation of 2 SPC's for the children.""" 1028 self.cindent = indent_child 1029 1030 def format(self, value, buffer=None): 1031 if not buffer: 1032 output = io.StringIO() 1033 else: 1034 output = buffer 1035 1036 BasicFormatter.format(self, value, buffer=output) 1037 for child in value: 1038 BasicFormatter.format(self, child, buffer=output, indent=self.cindent) 1039 1040 return output.getvalue() 1041 1042 1043class RecursiveDecentFormatter(BasicFormatter): 1044 """The recursive decent formatter prints the value and the decendents. 1045 1046 The constructor takes two keyword args: indent_level, which defaults to 0, 1047 and indent_child, which defaults to 2. The current indentation level is 1048 determined by indent_level, while the immediate children has an additional 1049 indentation by inden_child. 1050 """ 1051 1052 def __init__(self, indent_level=0, indent_child=2): 1053 self.lindent = indent_level 1054 self.cindent = indent_child 1055 1056 def format(self, value, buffer=None): 1057 if not buffer: 1058 output = io.StringIO() 1059 else: 1060 output = buffer 1061 1062 BasicFormatter.format(self, value, buffer=output, indent=self.lindent) 1063 new_indent = self.lindent + self.cindent 1064 for child in value: 1065 if child.GetSummary() is not None: 1066 BasicFormatter.format(self, child, buffer=output, indent=new_indent) 1067 else: 1068 if child.GetNumChildren() > 0: 1069 rdf = RecursiveDecentFormatter(indent_level=new_indent) 1070 rdf.format(child, buffer=output) 1071 else: 1072 BasicFormatter.format(self, child, buffer=output, indent=new_indent) 1073 1074 return output.getvalue() 1075