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