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 errno 12import os 13import re 14import sys 15import subprocess 16 17# Third-party modules 18from six import StringIO as SixStringIO 19import six 20 21# LLDB modules 22import lldb 23from . import lldbtest_config 24from . import configuration 25 26# How often failed simulator process launches are retried. 27SIMULATOR_RETRY = 3 28 29# =================================================== 30# Utilities for locating/checking executable programs 31# =================================================== 32 33def is_exe(fpath): 34 """Returns True if fpath is an executable.""" 35 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 36 37 38def which(program): 39 """Returns the full path to a program; None otherwise.""" 40 fpath, fname = os.path.split(program) 41 if fpath: 42 if is_exe(program): 43 return program 44 else: 45 for path in os.environ["PATH"].split(os.pathsep): 46 exe_file = os.path.join(path, program) 47 if is_exe(exe_file): 48 return exe_file 49 return None 50 51def mkdir_p(path): 52 try: 53 os.makedirs(path) 54 except OSError as e: 55 if e.errno != errno.EEXIST: 56 raise 57 if not os.path.isdir(path): 58 raise OSError(errno.ENOTDIR, "%s is not a directory"%path) 59 60 61# ============================ 62# Dealing with SDK and triples 63# ============================ 64 65def get_xcode_sdk(os, env): 66 # Respect --apple-sdk <path> if it's specified. If the SDK is simply 67 # mounted from some disk image, and not actually installed, this is the 68 # only way to use it. 69 if configuration.apple_sdk: 70 return configuration.apple_sdk 71 if os == "ios": 72 if env == "simulator": 73 return "iphonesimulator" 74 if env == "macabi": 75 return "macosx" 76 return "iphoneos" 77 elif os == "tvos": 78 if env == "simulator": 79 return "appletvsimulator" 80 return "appletvos" 81 elif os == "watchos": 82 if env == "simulator": 83 return "watchsimulator" 84 return "watchos" 85 return os 86 87 88def get_xcode_sdk_version(sdk): 89 return subprocess.check_output( 90 ['xcrun', '--sdk', sdk, '--show-sdk-version']).rstrip().decode('utf-8') 91 92 93def get_xcode_sdk_root(sdk): 94 return subprocess.check_output(['xcrun', '--sdk', sdk, '--show-sdk-path' 95 ]).rstrip().decode('utf-8') 96 97 98# =================================================== 99# Disassembly for an SBFunction or an SBSymbol object 100# =================================================== 101 102 103def disassemble(target, function_or_symbol): 104 """Disassemble the function or symbol given a target. 105 106 It returns the disassembly content in a string object. 107 """ 108 buf = SixStringIO() 109 insts = function_or_symbol.GetInstructions(target) 110 for i in insts: 111 print(i, file=buf) 112 return buf.getvalue() 113 114# ========================================================== 115# Integer (byte size 1, 2, 4, and 8) to bytearray conversion 116# ========================================================== 117 118 119def int_to_bytearray(val, bytesize): 120 """Utility function to convert an integer into a bytearray. 121 122 It returns the bytearray in the little endian format. It is easy to get the 123 big endian format, just do ba.reverse() on the returned object. 124 """ 125 import struct 126 127 if bytesize == 1: 128 return bytearray([val]) 129 130 # Little endian followed by a format character. 131 template = "<%c" 132 if bytesize == 2: 133 fmt = template % 'h' 134 elif bytesize == 4: 135 fmt = template % 'i' 136 elif bytesize == 4: 137 fmt = template % 'q' 138 else: 139 return None 140 141 packed = struct.pack(fmt, val) 142 return bytearray(packed) 143 144 145def bytearray_to_int(bytes, bytesize): 146 """Utility function to convert a bytearray into an integer. 147 148 It interprets the bytearray in the little endian format. For a big endian 149 bytearray, just do ba.reverse() on the object before passing it in. 150 """ 151 import struct 152 153 if bytesize == 1: 154 return bytes[0] 155 156 # Little endian followed by a format character. 157 template = "<%c" 158 if bytesize == 2: 159 fmt = template % 'h' 160 elif bytesize == 4: 161 fmt = template % 'i' 162 elif bytesize == 4: 163 fmt = template % 'q' 164 else: 165 return None 166 167 unpacked = struct.unpack_from(fmt, bytes) 168 return unpacked[0] 169 170 171# ============================================================== 172# Get the description of an lldb object or None if not available 173# ============================================================== 174def get_description(obj, option=None): 175 """Calls lldb_obj.GetDescription() and returns a string, or None. 176 177 For SBTarget, SBBreakpointLocation, and SBWatchpoint lldb objects, an extra 178 option can be passed in to describe the detailed level of description 179 desired: 180 o lldb.eDescriptionLevelBrief 181 o lldb.eDescriptionLevelFull 182 o lldb.eDescriptionLevelVerbose 183 """ 184 method = getattr(obj, 'GetDescription') 185 if not method: 186 return None 187 tuple = (lldb.SBTarget, lldb.SBBreakpointLocation, lldb.SBWatchpoint) 188 if isinstance(obj, tuple): 189 if option is None: 190 option = lldb.eDescriptionLevelBrief 191 192 stream = lldb.SBStream() 193 if option is None: 194 success = method(stream) 195 else: 196 success = method(stream, option) 197 if not success: 198 return None 199 return stream.GetData() 200 201 202# ================================================= 203# Convert some enum value to its string counterpart 204# ================================================= 205 206def state_type_to_str(enum): 207 """Returns the stateType string given an enum.""" 208 if enum == lldb.eStateInvalid: 209 return "invalid" 210 elif enum == lldb.eStateUnloaded: 211 return "unloaded" 212 elif enum == lldb.eStateConnected: 213 return "connected" 214 elif enum == lldb.eStateAttaching: 215 return "attaching" 216 elif enum == lldb.eStateLaunching: 217 return "launching" 218 elif enum == lldb.eStateStopped: 219 return "stopped" 220 elif enum == lldb.eStateRunning: 221 return "running" 222 elif enum == lldb.eStateStepping: 223 return "stepping" 224 elif enum == lldb.eStateCrashed: 225 return "crashed" 226 elif enum == lldb.eStateDetached: 227 return "detached" 228 elif enum == lldb.eStateExited: 229 return "exited" 230 elif enum == lldb.eStateSuspended: 231 return "suspended" 232 else: 233 raise Exception("Unknown StateType enum") 234 235 236def stop_reason_to_str(enum): 237 """Returns the stopReason string given an enum.""" 238 if enum == lldb.eStopReasonInvalid: 239 return "invalid" 240 elif enum == lldb.eStopReasonNone: 241 return "none" 242 elif enum == lldb.eStopReasonTrace: 243 return "trace" 244 elif enum == lldb.eStopReasonBreakpoint: 245 return "breakpoint" 246 elif enum == lldb.eStopReasonWatchpoint: 247 return "watchpoint" 248 elif enum == lldb.eStopReasonExec: 249 return "exec" 250 elif enum == lldb.eStopReasonSignal: 251 return "signal" 252 elif enum == lldb.eStopReasonException: 253 return "exception" 254 elif enum == lldb.eStopReasonPlanComplete: 255 return "plancomplete" 256 elif enum == lldb.eStopReasonThreadExiting: 257 return "threadexiting" 258 else: 259 raise Exception("Unknown StopReason enum") 260 261 262def symbol_type_to_str(enum): 263 """Returns the symbolType string given an enum.""" 264 if enum == lldb.eSymbolTypeInvalid: 265 return "invalid" 266 elif enum == lldb.eSymbolTypeAbsolute: 267 return "absolute" 268 elif enum == lldb.eSymbolTypeCode: 269 return "code" 270 elif enum == lldb.eSymbolTypeData: 271 return "data" 272 elif enum == lldb.eSymbolTypeTrampoline: 273 return "trampoline" 274 elif enum == lldb.eSymbolTypeRuntime: 275 return "runtime" 276 elif enum == lldb.eSymbolTypeException: 277 return "exception" 278 elif enum == lldb.eSymbolTypeSourceFile: 279 return "sourcefile" 280 elif enum == lldb.eSymbolTypeHeaderFile: 281 return "headerfile" 282 elif enum == lldb.eSymbolTypeObjectFile: 283 return "objectfile" 284 elif enum == lldb.eSymbolTypeCommonBlock: 285 return "commonblock" 286 elif enum == lldb.eSymbolTypeBlock: 287 return "block" 288 elif enum == lldb.eSymbolTypeLocal: 289 return "local" 290 elif enum == lldb.eSymbolTypeParam: 291 return "param" 292 elif enum == lldb.eSymbolTypeVariable: 293 return "variable" 294 elif enum == lldb.eSymbolTypeVariableType: 295 return "variabletype" 296 elif enum == lldb.eSymbolTypeLineEntry: 297 return "lineentry" 298 elif enum == lldb.eSymbolTypeLineHeader: 299 return "lineheader" 300 elif enum == lldb.eSymbolTypeScopeBegin: 301 return "scopebegin" 302 elif enum == lldb.eSymbolTypeScopeEnd: 303 return "scopeend" 304 elif enum == lldb.eSymbolTypeAdditional: 305 return "additional" 306 elif enum == lldb.eSymbolTypeCompiler: 307 return "compiler" 308 elif enum == lldb.eSymbolTypeInstrumentation: 309 return "instrumentation" 310 elif enum == lldb.eSymbolTypeUndefined: 311 return "undefined" 312 313 314def value_type_to_str(enum): 315 """Returns the valueType string given an enum.""" 316 if enum == lldb.eValueTypeInvalid: 317 return "invalid" 318 elif enum == lldb.eValueTypeVariableGlobal: 319 return "global_variable" 320 elif enum == lldb.eValueTypeVariableStatic: 321 return "static_variable" 322 elif enum == lldb.eValueTypeVariableArgument: 323 return "argument_variable" 324 elif enum == lldb.eValueTypeVariableLocal: 325 return "local_variable" 326 elif enum == lldb.eValueTypeRegister: 327 return "register" 328 elif enum == lldb.eValueTypeRegisterSet: 329 return "register_set" 330 elif enum == lldb.eValueTypeConstResult: 331 return "constant_result" 332 else: 333 raise Exception("Unknown ValueType enum") 334 335 336# ================================================== 337# Get stopped threads due to each stop reason. 338# ================================================== 339 340def sort_stopped_threads(process, 341 breakpoint_threads=None, 342 crashed_threads=None, 343 watchpoint_threads=None, 344 signal_threads=None, 345 exiting_threads=None, 346 other_threads=None): 347 """ Fills array *_threads with threads stopped for the corresponding stop 348 reason. 349 """ 350 for lst in [breakpoint_threads, 351 watchpoint_threads, 352 signal_threads, 353 exiting_threads, 354 other_threads]: 355 if lst is not None: 356 lst[:] = [] 357 358 for thread in process: 359 dispatched = False 360 for (reason, list) in [(lldb.eStopReasonBreakpoint, breakpoint_threads), 361 (lldb.eStopReasonException, crashed_threads), 362 (lldb.eStopReasonWatchpoint, watchpoint_threads), 363 (lldb.eStopReasonSignal, signal_threads), 364 (lldb.eStopReasonThreadExiting, exiting_threads), 365 (None, other_threads)]: 366 if not dispatched and list is not None: 367 if thread.GetStopReason() == reason or reason is None: 368 list.append(thread) 369 dispatched = True 370 371# ================================================== 372# Utility functions for setting breakpoints 373# ================================================== 374 375def run_break_set_by_script( 376 test, 377 class_name, 378 extra_options=None, 379 num_expected_locations=1): 380 """Set a scripted breakpoint. Check that it got the right number of locations.""" 381 test.assertTrue(class_name is not None, "Must pass in a class name.") 382 command = "breakpoint set -P " + class_name 383 if extra_options is not None: 384 command += " " + extra_options 385 386 break_results = run_break_set_command(test, command) 387 check_breakpoint_result(test, break_results, num_locations=num_expected_locations) 388 return get_bpno_from_match(break_results) 389 390def run_break_set_by_file_and_line( 391 test, 392 file_name, 393 line_number, 394 extra_options=None, 395 num_expected_locations=1, 396 loc_exact=False, 397 module_name=None): 398 """Set a breakpoint by file and line, returning the breakpoint number. 399 400 If extra_options is not None, then we append it to the breakpoint set command. 401 402 If num_expected_locations is -1, we check that we got AT LEAST one location. If num_expected_locations is -2, we don't 403 check the actual number at all. Otherwise, we check that num_expected_locations equals the number of locations. 404 405 If loc_exact is true, we check that there is one location, and that location must be at the input file and line number.""" 406 407 if file_name is None: 408 command = 'breakpoint set -l %d' % (line_number) 409 else: 410 command = 'breakpoint set -f "%s" -l %d' % (file_name, line_number) 411 412 if module_name: 413 command += " --shlib '%s'" % (module_name) 414 415 if extra_options: 416 command += " " + extra_options 417 418 break_results = run_break_set_command(test, command) 419 420 if num_expected_locations == 1 and loc_exact: 421 check_breakpoint_result( 422 test, 423 break_results, 424 num_locations=num_expected_locations, 425 file_name=file_name, 426 line_number=line_number, 427 module_name=module_name) 428 else: 429 check_breakpoint_result( 430 test, 431 break_results, 432 num_locations=num_expected_locations) 433 434 return get_bpno_from_match(break_results) 435 436 437def run_break_set_by_symbol( 438 test, 439 symbol, 440 extra_options=None, 441 num_expected_locations=-1, 442 sym_exact=False, 443 module_name=None): 444 """Set a breakpoint by symbol name. Common options are the same as run_break_set_by_file_and_line. 445 446 If sym_exact is true, then the output symbol must match the input exactly, otherwise we do a substring match.""" 447 command = 'breakpoint set -n "%s"' % (symbol) 448 449 if module_name: 450 command += " --shlib '%s'" % (module_name) 451 452 if extra_options: 453 command += " " + extra_options 454 455 break_results = run_break_set_command(test, command) 456 457 if num_expected_locations == 1 and sym_exact: 458 check_breakpoint_result( 459 test, 460 break_results, 461 num_locations=num_expected_locations, 462 symbol_name=symbol, 463 module_name=module_name) 464 else: 465 check_breakpoint_result( 466 test, 467 break_results, 468 num_locations=num_expected_locations) 469 470 return get_bpno_from_match(break_results) 471 472 473def run_break_set_by_selector( 474 test, 475 selector, 476 extra_options=None, 477 num_expected_locations=-1, 478 module_name=None): 479 """Set a breakpoint by selector. Common options are the same as run_break_set_by_file_and_line.""" 480 481 command = 'breakpoint set -S "%s"' % (selector) 482 483 if module_name: 484 command += ' --shlib "%s"' % (module_name) 485 486 if extra_options: 487 command += " " + extra_options 488 489 break_results = run_break_set_command(test, command) 490 491 if num_expected_locations == 1: 492 check_breakpoint_result( 493 test, 494 break_results, 495 num_locations=num_expected_locations, 496 symbol_name=selector, 497 symbol_match_exact=False, 498 module_name=module_name) 499 else: 500 check_breakpoint_result( 501 test, 502 break_results, 503 num_locations=num_expected_locations) 504 505 return get_bpno_from_match(break_results) 506 507 508def run_break_set_by_regexp( 509 test, 510 regexp, 511 extra_options=None, 512 num_expected_locations=-1): 513 """Set a breakpoint by regular expression match on symbol name. Common options are the same as run_break_set_by_file_and_line.""" 514 515 command = 'breakpoint set -r "%s"' % (regexp) 516 if extra_options: 517 command += " " + extra_options 518 519 break_results = run_break_set_command(test, command) 520 521 check_breakpoint_result( 522 test, 523 break_results, 524 num_locations=num_expected_locations) 525 526 return get_bpno_from_match(break_results) 527 528 529def run_break_set_by_source_regexp( 530 test, 531 regexp, 532 extra_options=None, 533 num_expected_locations=-1): 534 """Set a breakpoint by source regular expression. Common options are the same as run_break_set_by_file_and_line.""" 535 command = 'breakpoint set -p "%s"' % (regexp) 536 if extra_options: 537 command += " " + extra_options 538 539 break_results = run_break_set_command(test, command) 540 541 check_breakpoint_result( 542 test, 543 break_results, 544 num_locations=num_expected_locations) 545 546 return get_bpno_from_match(break_results) 547 548def run_break_set_by_file_colon_line( 549 test, 550 specifier, 551 path, 552 line_number, 553 column_number = 0, 554 extra_options=None, 555 num_expected_locations=-1): 556 command = 'breakpoint set -y "%s"'%(specifier) 557 if extra_options: 558 command += " " + extra_options 559 560 print("About to run: '%s'", command) 561 break_results = run_break_set_command(test, command) 562 check_breakpoint_result( 563 test, 564 break_results, 565 num_locations = num_expected_locations, 566 file_name = path, 567 line_number = line_number, 568 column_number = column_number) 569 570 return get_bpno_from_match(break_results) 571 572def run_break_set_command(test, command): 573 """Run the command passed in - it must be some break set variant - and analyze the result. 574 Returns a dictionary of information gleaned from the command-line results. 575 Will assert if the breakpoint setting fails altogether. 576 577 Dictionary will contain: 578 bpno - breakpoint of the newly created breakpoint, -1 on error. 579 num_locations - number of locations set for the breakpoint. 580 581 If there is only one location, the dictionary MAY contain: 582 file - source file name 583 line_no - source line number 584 column - source column number 585 symbol - symbol name 586 inline_symbol - inlined symbol name 587 offset - offset from the original symbol 588 module - module 589 address - address at which the breakpoint was set.""" 590 591 patterns = [ 592 r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$", 593 r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.", 594 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]+)(?P<column>(:[0-9]+)?), address = (?P<address>0x[0-9a-fA-F]+)$", 595 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]+)$"] 596 match_object = test.match(command, patterns) 597 break_results = match_object.groupdict() 598 599 # We always insert the breakpoint number, setting it to -1 if we couldn't find it 600 # Also, make sure it gets stored as an integer. 601 if not 'bpno' in break_results: 602 break_results['bpno'] = -1 603 else: 604 break_results['bpno'] = int(break_results['bpno']) 605 606 # We always insert the number of locations 607 # If ONE location is set for the breakpoint, then the output doesn't mention locations, but it has to be 1... 608 # We also make sure it is an integer. 609 610 if not 'num_locations' in break_results: 611 num_locations = 1 612 else: 613 num_locations = break_results['num_locations'] 614 if num_locations == 'no': 615 num_locations = 0 616 else: 617 num_locations = int(break_results['num_locations']) 618 619 break_results['num_locations'] = num_locations 620 621 if 'line_no' in break_results: 622 break_results['line_no'] = int(break_results['line_no']) 623 624 return break_results 625 626 627def get_bpno_from_match(break_results): 628 return int(break_results['bpno']) 629 630 631def check_breakpoint_result( 632 test, 633 break_results, 634 file_name=None, 635 line_number=-1, 636 column_number=0, 637 symbol_name=None, 638 symbol_match_exact=True, 639 module_name=None, 640 offset=-1, 641 num_locations=-1): 642 643 out_num_locations = break_results['num_locations'] 644 645 if num_locations == -1: 646 test.assertTrue(out_num_locations > 0, 647 "Expecting one or more locations, got none.") 648 elif num_locations != -2: 649 test.assertTrue( 650 num_locations == out_num_locations, 651 "Expecting %d locations, got %d." % 652 (num_locations, 653 out_num_locations)) 654 655 if file_name: 656 out_file_name = "" 657 if 'file' in break_results: 658 out_file_name = break_results['file'] 659 test.assertTrue( 660 file_name.endswith(out_file_name), 661 "Breakpoint file name '%s' doesn't match resultant name '%s'." % 662 (file_name, 663 out_file_name)) 664 665 if line_number != -1: 666 out_line_number = -1 667 if 'line_no' in break_results: 668 out_line_number = break_results['line_no'] 669 670 test.assertTrue( 671 line_number == out_line_number, 672 "Breakpoint line number %s doesn't match resultant line %s." % 673 (line_number, 674 out_line_number)) 675 676 if column_number != 0: 677 out_column_number = 0 678 if 'column' in break_results: 679 out_column_number = break_results['column'] 680 681 test.assertTrue( 682 column_number == out_column_number, 683 "Breakpoint column number %s doesn't match resultant column %s." % 684 (column_number, 685 out_column_number)) 686 687 if symbol_name: 688 out_symbol_name = "" 689 # Look first for the inlined symbol name, otherwise use the symbol 690 # name: 691 if 'inline_symbol' in break_results and break_results['inline_symbol']: 692 out_symbol_name = break_results['inline_symbol'] 693 elif 'symbol' in break_results: 694 out_symbol_name = break_results['symbol'] 695 696 if symbol_match_exact: 697 test.assertTrue( 698 symbol_name == out_symbol_name, 699 "Symbol name '%s' doesn't match resultant symbol '%s'." % 700 (symbol_name, 701 out_symbol_name)) 702 else: 703 test.assertTrue( 704 out_symbol_name.find(symbol_name) != - 705 1, 706 "Symbol name '%s' isn't in resultant symbol '%s'." % 707 (symbol_name, 708 out_symbol_name)) 709 710 if module_name: 711 out_module_name = None 712 if 'module' in break_results: 713 out_module_name = break_results['module'] 714 715 test.assertTrue( 716 module_name.find(out_module_name) != - 717 1, 718 "Symbol module name '%s' isn't in expected module name '%s'." % 719 (out_module_name, 720 module_name)) 721 722# ================================================== 723# Utility functions related to Threads and Processes 724# ================================================== 725 726 727def get_stopped_threads(process, reason): 728 """Returns the thread(s) with the specified stop reason in a list. 729 730 The list can be empty if no such thread exists. 731 """ 732 threads = [] 733 for t in process: 734 if t.GetStopReason() == reason: 735 threads.append(t) 736 return threads 737 738 739def get_stopped_thread(process, reason): 740 """A convenience function which returns the first thread with the given stop 741 reason or None. 742 743 Example usages: 744 745 1. Get the stopped thread due to a breakpoint condition 746 747 ... 748 from lldbutil import get_stopped_thread 749 thread = get_stopped_thread(process, lldb.eStopReasonPlanComplete) 750 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint condition") 751 ... 752 753 2. Get the thread stopped due to a breakpoint 754 755 ... 756 from lldbutil import get_stopped_thread 757 thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) 758 self.assertTrue(thread.IsValid(), "There should be a thread stopped due to breakpoint") 759 ... 760 761 """ 762 threads = get_stopped_threads(process, reason) 763 if len(threads) == 0: 764 return None 765 return threads[0] 766 767 768def get_threads_stopped_at_breakpoint_id(process, bpid): 769 """ For a stopped process returns the thread stopped at the breakpoint passed in bkpt""" 770 stopped_threads = [] 771 threads = [] 772 773 stopped_threads = get_stopped_threads(process, lldb.eStopReasonBreakpoint) 774 775 if len(stopped_threads) == 0: 776 return threads 777 778 for thread in stopped_threads: 779 # Make sure we've hit our breakpoint... 780 break_id = thread.GetStopReasonDataAtIndex(0) 781 if break_id == bpid: 782 threads.append(thread) 783 784 return threads 785 786 787def get_threads_stopped_at_breakpoint(process, bkpt): 788 return get_threads_stopped_at_breakpoint_id(process, bkpt.GetID()) 789 790 791def get_one_thread_stopped_at_breakpoint_id( 792 process, bpid, require_exactly_one=True): 793 threads = get_threads_stopped_at_breakpoint_id(process, bpid) 794 if len(threads) == 0: 795 return None 796 if require_exactly_one and len(threads) != 1: 797 return None 798 799 return threads[0] 800 801 802def get_one_thread_stopped_at_breakpoint( 803 process, bkpt, require_exactly_one=True): 804 return get_one_thread_stopped_at_breakpoint_id( 805 process, bkpt.GetID(), require_exactly_one) 806 807 808def is_thread_crashed(test, thread): 809 """In the test suite we dereference a null pointer to simulate a crash. The way this is 810 reported depends on the platform.""" 811 if test.platformIsDarwin(): 812 return thread.GetStopReason( 813 ) == lldb.eStopReasonException and "EXC_BAD_ACCESS" in thread.GetStopDescription(100) 814 elif test.getPlatform() == "linux": 815 return thread.GetStopReason() == lldb.eStopReasonSignal and thread.GetStopReasonDataAtIndex( 816 0) == thread.GetProcess().GetUnixSignals().GetSignalNumberFromName("SIGSEGV") 817 elif test.getPlatform() == "windows": 818 return "Exception 0xc0000005" in thread.GetStopDescription(200) 819 else: 820 return "invalid address" in thread.GetStopDescription(100) 821 822 823def get_crashed_threads(test, process): 824 threads = [] 825 if process.GetState() != lldb.eStateStopped: 826 return threads 827 for thread in process: 828 if is_thread_crashed(test, thread): 829 threads.append(thread) 830 return threads 831 832# Helper functions for run_to_{source,name}_breakpoint: 833 834def run_to_breakpoint_make_target(test, exe_name = "a.out", in_cwd = True): 835 if in_cwd: 836 exe = test.getBuildArtifact(exe_name) 837 838 # Create the target 839 target = test.dbg.CreateTarget(exe) 840 test.assertTrue(target, "Target: %s is not valid."%(exe_name)) 841 842 # Set environment variables for the inferior. 843 if lldbtest_config.inferior_env: 844 test.runCmd('settings set target.env-vars {}'.format( 845 lldbtest_config.inferior_env)) 846 847 return target 848 849def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None, 850 only_one_thread = True, extra_images = None): 851 852 # Launch the process, and do not stop at the entry point. 853 if not launch_info: 854 launch_info = target.GetLaunchInfo() 855 launch_info.SetWorkingDirectory(test.get_process_working_directory()) 856 857 if extra_images: 858 environ = test.registerSharedLibrariesWithTarget(target, extra_images) 859 launch_info.SetEnvironmentEntries(environ, True) 860 861 error = lldb.SBError() 862 process = target.Launch(launch_info, error) 863 864 # Unfortunate workaround for the iPhone simulator. 865 retry = SIMULATOR_RETRY 866 while (retry and error.Fail() and error.GetCString() and 867 "Unable to boot the Simulator" in error.GetCString()): 868 retry -= 1 869 print("** Simulator is unresponsive. Retrying %d more time(s)"%retry) 870 import time 871 time.sleep(60) 872 error = lldb.SBError() 873 process = target.Launch(launch_info, error) 874 875 test.assertTrue(process, 876 "Could not create a valid process for %s: %s" % 877 (target.GetExecutable().GetFilename(), error.GetCString())) 878 test.assertFalse(error.Fail(), 879 "Process launch failed: %s" % (error.GetCString())) 880 881 test.assertEqual(process.GetState(), lldb.eStateStopped) 882 883 # Frame #0 should be at our breakpoint. 884 threads = get_threads_stopped_at_breakpoint( 885 process, bkpt) 886 887 num_threads = len(threads) 888 if only_one_thread: 889 test.assertEqual(num_threads, 1, "Expected 1 thread to stop at breakpoint, %d did."%(num_threads)) 890 else: 891 test.assertGreater(num_threads, 0, "No threads stopped at breakpoint") 892 893 thread = threads[0] 894 return (target, process, thread, bkpt) 895 896def run_to_name_breakpoint (test, bkpt_name, launch_info = None, 897 exe_name = "a.out", 898 bkpt_module = None, 899 in_cwd = True, 900 only_one_thread = True, 901 extra_images = None): 902 """Start up a target, using exe_name as the executable, and run it to 903 a breakpoint set by name on bkpt_name restricted to bkpt_module. 904 905 If you want to pass in launch arguments or environment 906 variables, you can optionally pass in an SBLaunchInfo. If you 907 do that, remember to set the working directory as well. 908 909 If your executable isn't called a.out, you can pass that in. 910 And if your executable isn't in the CWD, pass in the absolute 911 path to the executable in exe_name, and set in_cwd to False. 912 913 If you need to restrict the breakpoint to a particular module, 914 pass the module name (a string not a FileSpec) in bkpt_module. If 915 nothing is passed in setting will be unrestricted. 916 917 If the target isn't valid, the breakpoint isn't found, or hit, the 918 function will cause a testsuite failure. 919 920 If successful it returns a tuple with the target process and 921 thread that hit the breakpoint, and the breakpoint that we set 922 for you. 923 924 If only_one_thread is true, we require that there be only one 925 thread stopped at the breakpoint. Otherwise we only require one 926 or more threads stop there. If there are more than one, we return 927 the first thread that stopped. 928 """ 929 930 target = run_to_breakpoint_make_target(test, exe_name, in_cwd) 931 932 breakpoint = target.BreakpointCreateByName(bkpt_name, bkpt_module) 933 934 935 test.assertTrue(breakpoint.GetNumLocations() > 0, 936 "No locations found for name breakpoint: '%s'."%(bkpt_name)) 937 return run_to_breakpoint_do_run(test, target, breakpoint, launch_info, 938 only_one_thread, extra_images) 939 940def run_to_source_breakpoint(test, bkpt_pattern, source_spec, 941 launch_info = None, exe_name = "a.out", 942 bkpt_module = None, 943 in_cwd = True, 944 only_one_thread = True, 945 extra_images = None): 946 """Start up a target, using exe_name as the executable, and run it to 947 a breakpoint set by source regex bkpt_pattern. 948 949 The rest of the behavior is the same as run_to_name_breakpoint. 950 """ 951 952 target = run_to_breakpoint_make_target(test, exe_name, in_cwd) 953 # Set the breakpoints 954 breakpoint = target.BreakpointCreateBySourceRegex( 955 bkpt_pattern, source_spec, bkpt_module) 956 test.assertTrue(breakpoint.GetNumLocations() > 0, 957 'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"' 958 %(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory())) 959 return run_to_breakpoint_do_run(test, target, breakpoint, launch_info, 960 only_one_thread, extra_images) 961 962def run_to_line_breakpoint(test, source_spec, line_number, column = 0, 963 launch_info = None, exe_name = "a.out", 964 bkpt_module = None, 965 in_cwd = True, 966 only_one_thread = True, 967 extra_images = None): 968 """Start up a target, using exe_name as the executable, and run it to 969 a breakpoint set by (source_spec, line_number(, column)). 970 971 The rest of the behavior is the same as run_to_name_breakpoint. 972 """ 973 974 target = run_to_breakpoint_make_target(test, exe_name, in_cwd) 975 # Set the breakpoints 976 breakpoint = target.BreakpointCreateByLocation( 977 source_spec, line_number, column, 0, lldb.SBFileSpecList()) 978 test.assertTrue(breakpoint.GetNumLocations() > 0, 979 'No locations found for line breakpoint: "%s:%d(:%d)", dir: "%s"' 980 %(source_spec.GetFilename(), line_number, column, 981 source_spec.GetDirectory())) 982 return run_to_breakpoint_do_run(test, target, breakpoint, launch_info, 983 only_one_thread, extra_images) 984 985 986def continue_to_breakpoint(process, bkpt): 987 """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None""" 988 process.Continue() 989 if process.GetState() != lldb.eStateStopped: 990 return None 991 else: 992 return get_threads_stopped_at_breakpoint(process, bkpt) 993 994 995def get_caller_symbol(thread): 996 """ 997 Returns the symbol name for the call site of the leaf function. 998 """ 999 depth = thread.GetNumFrames() 1000 if depth <= 1: 1001 return None 1002 caller = thread.GetFrameAtIndex(1).GetSymbol() 1003 if caller: 1004 return caller.GetName() 1005 else: 1006 return None 1007 1008 1009def get_function_names(thread): 1010 """ 1011 Returns a sequence of function names from the stack frames of this thread. 1012 """ 1013 def GetFuncName(i): 1014 return thread.GetFrameAtIndex(i).GetFunctionName() 1015 1016 return list(map(GetFuncName, list(range(thread.GetNumFrames())))) 1017 1018 1019def get_symbol_names(thread): 1020 """ 1021 Returns a sequence of symbols for this thread. 1022 """ 1023 def GetSymbol(i): 1024 return thread.GetFrameAtIndex(i).GetSymbol().GetName() 1025 1026 return list(map(GetSymbol, list(range(thread.GetNumFrames())))) 1027 1028 1029def get_pc_addresses(thread): 1030 """ 1031 Returns a sequence of pc addresses for this thread. 1032 """ 1033 def GetPCAddress(i): 1034 return thread.GetFrameAtIndex(i).GetPCAddress() 1035 1036 return list(map(GetPCAddress, list(range(thread.GetNumFrames())))) 1037 1038 1039def get_filenames(thread): 1040 """ 1041 Returns a sequence of file names from the stack frames of this thread. 1042 """ 1043 def GetFilename(i): 1044 return thread.GetFrameAtIndex( 1045 i).GetLineEntry().GetFileSpec().GetFilename() 1046 1047 return list(map(GetFilename, list(range(thread.GetNumFrames())))) 1048 1049 1050def get_line_numbers(thread): 1051 """ 1052 Returns a sequence of line numbers from the stack frames of this thread. 1053 """ 1054 def GetLineNumber(i): 1055 return thread.GetFrameAtIndex(i).GetLineEntry().GetLine() 1056 1057 return list(map(GetLineNumber, list(range(thread.GetNumFrames())))) 1058 1059 1060def get_module_names(thread): 1061 """ 1062 Returns a sequence of module names from the stack frames of this thread. 1063 """ 1064 def GetModuleName(i): 1065 return thread.GetFrameAtIndex( 1066 i).GetModule().GetFileSpec().GetFilename() 1067 1068 return list(map(GetModuleName, list(range(thread.GetNumFrames())))) 1069 1070 1071def get_stack_frames(thread): 1072 """ 1073 Returns a sequence of stack frames for this thread. 1074 """ 1075 def GetStackFrame(i): 1076 return thread.GetFrameAtIndex(i) 1077 1078 return list(map(GetStackFrame, list(range(thread.GetNumFrames())))) 1079 1080 1081def print_stacktrace(thread, string_buffer=False): 1082 """Prints a simple stack trace of this thread.""" 1083 1084 output = SixStringIO() if string_buffer else sys.stdout 1085 target = thread.GetProcess().GetTarget() 1086 1087 depth = thread.GetNumFrames() 1088 1089 mods = get_module_names(thread) 1090 funcs = get_function_names(thread) 1091 symbols = get_symbol_names(thread) 1092 files = get_filenames(thread) 1093 lines = get_line_numbers(thread) 1094 addrs = get_pc_addresses(thread) 1095 1096 if thread.GetStopReason() != lldb.eStopReasonInvalid: 1097 desc = "stop reason=" + stop_reason_to_str(thread.GetStopReason()) 1098 else: 1099 desc = "" 1100 print( 1101 "Stack trace for thread id={0:#x} name={1} queue={2} ".format( 1102 thread.GetThreadID(), 1103 thread.GetName(), 1104 thread.GetQueueName()) + desc, 1105 file=output) 1106 1107 for i in range(depth): 1108 frame = thread.GetFrameAtIndex(i) 1109 function = frame.GetFunction() 1110 1111 load_addr = addrs[i].GetLoadAddress(target) 1112 if not function: 1113 file_addr = addrs[i].GetFileAddress() 1114 start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress() 1115 symbol_offset = file_addr - start_addr 1116 print( 1117 " frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}".format( 1118 num=i, 1119 addr=load_addr, 1120 mod=mods[i], 1121 symbol=symbols[i], 1122 offset=symbol_offset), 1123 file=output) 1124 else: 1125 print( 1126 " frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}".format( 1127 num=i, 1128 addr=load_addr, 1129 mod=mods[i], 1130 func='%s [inlined]' % 1131 funcs[i] if frame.IsInlined() else funcs[i], 1132 file=files[i], 1133 line=lines[i], 1134 args=get_args_as_string( 1135 frame, 1136 showFuncName=False) if not frame.IsInlined() else '()'), 1137 file=output) 1138 1139 if string_buffer: 1140 return output.getvalue() 1141 1142 1143def print_stacktraces(process, string_buffer=False): 1144 """Prints the stack traces of all the threads.""" 1145 1146 output = SixStringIO() if string_buffer else sys.stdout 1147 1148 print("Stack traces for " + str(process), file=output) 1149 1150 for thread in process: 1151 print(print_stacktrace(thread, string_buffer=True), file=output) 1152 1153 if string_buffer: 1154 return output.getvalue() 1155 1156 1157def expect_state_changes(test, listener, process, states, timeout=30): 1158 """Listens for state changed events on the listener and makes sure they match what we 1159 expect. Stop-and-restart events (where GetRestartedFromEvent() returns true) are ignored.""" 1160 1161 for expected_state in states: 1162 def get_next_event(): 1163 event = lldb.SBEvent() 1164 if not listener.WaitForEventForBroadcasterWithType( 1165 timeout, 1166 process.GetBroadcaster(), 1167 lldb.SBProcess.eBroadcastBitStateChanged, 1168 event): 1169 test.fail( 1170 "Timed out while waiting for a transition to state %s" % 1171 lldb.SBDebugger.StateAsCString(expected_state)) 1172 return event 1173 1174 event = get_next_event() 1175 while (lldb.SBProcess.GetStateFromEvent(event) == lldb.eStateStopped and 1176 lldb.SBProcess.GetRestartedFromEvent(event)): 1177 # Ignore restarted event and the subsequent running event. 1178 event = get_next_event() 1179 test.assertEqual( 1180 lldb.SBProcess.GetStateFromEvent(event), 1181 lldb.eStateRunning, 1182 "Restarted event followed by a running event") 1183 event = get_next_event() 1184 1185 test.assertEqual( 1186 lldb.SBProcess.GetStateFromEvent(event), 1187 expected_state) 1188 1189# =================================== 1190# Utility functions related to Frames 1191# =================================== 1192 1193 1194def get_parent_frame(frame): 1195 """ 1196 Returns the parent frame of the input frame object; None if not available. 1197 """ 1198 thread = frame.GetThread() 1199 parent_found = False 1200 for f in thread: 1201 if parent_found: 1202 return f 1203 if f.GetFrameID() == frame.GetFrameID(): 1204 parent_found = True 1205 1206 # If we reach here, no parent has been found, return None. 1207 return None 1208 1209 1210def get_args_as_string(frame, showFuncName=True): 1211 """ 1212 Returns the args of the input frame object as a string. 1213 """ 1214 # arguments => True 1215 # locals => False 1216 # statics => False 1217 # in_scope_only => True 1218 vars = frame.GetVariables(True, False, False, True) # type of SBValueList 1219 args = [] # list of strings 1220 for var in vars: 1221 args.append("(%s)%s=%s" % (var.GetTypeName(), 1222 var.GetName(), 1223 var.GetValue())) 1224 if frame.GetFunction(): 1225 name = frame.GetFunction().GetName() 1226 elif frame.GetSymbol(): 1227 name = frame.GetSymbol().GetName() 1228 else: 1229 name = "" 1230 if showFuncName: 1231 return "%s(%s)" % (name, ", ".join(args)) 1232 else: 1233 return "(%s)" % (", ".join(args)) 1234 1235 1236def print_registers(frame, string_buffer=False): 1237 """Prints all the register sets of the frame.""" 1238 1239 output = SixStringIO() if string_buffer else sys.stdout 1240 1241 print("Register sets for " + str(frame), file=output) 1242 1243 registerSet = frame.GetRegisters() # Return type of SBValueList. 1244 print("Frame registers (size of register set = %d):" % 1245 registerSet.GetSize(), file=output) 1246 for value in registerSet: 1247 #print(value, file=output) 1248 print("%s (number of children = %d):" % 1249 (value.GetName(), value.GetNumChildren()), file=output) 1250 for child in value: 1251 print( 1252 "Name: %s, Value: %s" % 1253 (child.GetName(), 1254 child.GetValue()), 1255 file=output) 1256 1257 if string_buffer: 1258 return output.getvalue() 1259 1260 1261def get_registers(frame, kind): 1262 """Returns the registers given the frame and the kind of registers desired. 1263 1264 Returns None if there's no such kind. 1265 """ 1266 registerSet = frame.GetRegisters() # Return type of SBValueList. 1267 for value in registerSet: 1268 if kind.lower() in value.GetName().lower(): 1269 return value 1270 1271 return None 1272 1273 1274def get_GPRs(frame): 1275 """Returns the general purpose registers of the frame as an SBValue. 1276 1277 The returned SBValue object is iterable. An example: 1278 ... 1279 from lldbutil import get_GPRs 1280 regs = get_GPRs(frame) 1281 for reg in regs: 1282 print("%s => %s" % (reg.GetName(), reg.GetValue())) 1283 ... 1284 """ 1285 return get_registers(frame, "general purpose") 1286 1287 1288def get_FPRs(frame): 1289 """Returns the floating point registers of the frame as an SBValue. 1290 1291 The returned SBValue object is iterable. An example: 1292 ... 1293 from lldbutil import get_FPRs 1294 regs = get_FPRs(frame) 1295 for reg in regs: 1296 print("%s => %s" % (reg.GetName(), reg.GetValue())) 1297 ... 1298 """ 1299 return get_registers(frame, "floating point") 1300 1301 1302def get_ESRs(frame): 1303 """Returns the exception state registers of the frame as an SBValue. 1304 1305 The returned SBValue object is iterable. An example: 1306 ... 1307 from lldbutil import get_ESRs 1308 regs = get_ESRs(frame) 1309 for reg in regs: 1310 print("%s => %s" % (reg.GetName(), reg.GetValue())) 1311 ... 1312 """ 1313 return get_registers(frame, "exception state") 1314 1315# ====================================== 1316# Utility classes/functions for SBValues 1317# ====================================== 1318 1319 1320class BasicFormatter(object): 1321 """The basic formatter inspects the value object and prints the value.""" 1322 1323 def format(self, value, buffer=None, indent=0): 1324 if not buffer: 1325 output = SixStringIO() 1326 else: 1327 output = buffer 1328 # If there is a summary, it suffices. 1329 val = value.GetSummary() 1330 # Otherwise, get the value. 1331 if val is None: 1332 val = value.GetValue() 1333 if val is None and value.GetNumChildren() > 0: 1334 val = "%s (location)" % value.GetLocation() 1335 print("{indentation}({type}) {name} = {value}".format( 1336 indentation=' ' * indent, 1337 type=value.GetTypeName(), 1338 name=value.GetName(), 1339 value=val), file=output) 1340 return output.getvalue() 1341 1342 1343class ChildVisitingFormatter(BasicFormatter): 1344 """The child visiting formatter prints the value and its immediate children. 1345 1346 The constructor takes a keyword arg: indent_child, which defaults to 2. 1347 """ 1348 1349 def __init__(self, indent_child=2): 1350 """Default indentation of 2 SPC's for the children.""" 1351 self.cindent = indent_child 1352 1353 def format(self, value, buffer=None): 1354 if not buffer: 1355 output = SixStringIO() 1356 else: 1357 output = buffer 1358 1359 BasicFormatter.format(self, value, buffer=output) 1360 for child in value: 1361 BasicFormatter.format( 1362 self, child, buffer=output, indent=self.cindent) 1363 1364 return output.getvalue() 1365 1366 1367class RecursiveDecentFormatter(BasicFormatter): 1368 """The recursive decent formatter prints the value and the decendents. 1369 1370 The constructor takes two keyword args: indent_level, which defaults to 0, 1371 and indent_child, which defaults to 2. The current indentation level is 1372 determined by indent_level, while the immediate children has an additional 1373 indentation by inden_child. 1374 """ 1375 1376 def __init__(self, indent_level=0, indent_child=2): 1377 self.lindent = indent_level 1378 self.cindent = indent_child 1379 1380 def format(self, value, buffer=None): 1381 if not buffer: 1382 output = SixStringIO() 1383 else: 1384 output = buffer 1385 1386 BasicFormatter.format(self, value, buffer=output, indent=self.lindent) 1387 new_indent = self.lindent + self.cindent 1388 for child in value: 1389 if child.GetSummary() is not None: 1390 BasicFormatter.format( 1391 self, child, buffer=output, indent=new_indent) 1392 else: 1393 if child.GetNumChildren() > 0: 1394 rdf = RecursiveDecentFormatter(indent_level=new_indent) 1395 rdf.format(child, buffer=output) 1396 else: 1397 BasicFormatter.format( 1398 self, child, buffer=output, indent=new_indent) 1399 1400 return output.getvalue() 1401 1402# =========================================================== 1403# Utility functions for path manipulation on remote platforms 1404# =========================================================== 1405 1406 1407def join_remote_paths(*paths): 1408 # TODO: update with actual platform name for remote windows once it exists 1409 if lldb.remote_platform.GetName() == 'remote-windows': 1410 return os.path.join(*paths).replace(os.path.sep, '\\') 1411 return os.path.join(*paths).replace(os.path.sep, '/') 1412 1413 1414def append_to_process_working_directory(test, *paths): 1415 remote = lldb.remote_platform 1416 if remote: 1417 return join_remote_paths(remote.GetWorkingDirectory(), *paths) 1418 return os.path.join(test.getBuildDir(), *paths) 1419 1420# ================================================== 1421# Utility functions to get the correct signal number 1422# ================================================== 1423 1424import signal 1425 1426 1427def get_signal_number(signal_name): 1428 platform = lldb.remote_platform 1429 if platform and platform.IsValid(): 1430 signals = platform.GetUnixSignals() 1431 if signals.IsValid(): 1432 signal_number = signals.GetSignalNumberFromName(signal_name) 1433 if signal_number > 0: 1434 return signal_number 1435 # No remote platform; fall back to using local python signals. 1436 return getattr(signal, signal_name) 1437 1438 1439class PrintableRegex(object): 1440 1441 def __init__(self, text): 1442 self.regex = re.compile(text) 1443 self.text = text 1444 1445 def match(self, str): 1446 return self.regex.match(str) 1447 1448 def __str__(self): 1449 return "%s" % (self.text) 1450 1451 def __repr__(self): 1452 return "re.compile(%s) -> %s" % (self.text, self.regex) 1453 1454 1455def skip_if_callable(test, mycallable, reason): 1456 if six.callable(mycallable): 1457 if mycallable(test): 1458 test.skipTest(reason) 1459 return True 1460 return False 1461 1462 1463def skip_if_library_missing(test, target, library): 1464 def find_library(target, library): 1465 for module in target.modules: 1466 filename = module.file.GetFilename() 1467 if isinstance(library, str): 1468 if library == filename: 1469 return False 1470 elif hasattr(library, 'match'): 1471 if library.match(filename): 1472 return False 1473 return True 1474 1475 def find_library_callable(test): 1476 return find_library(target, library) 1477 return skip_if_callable( 1478 test, 1479 find_library_callable, 1480 "could not find library matching '%s' in target %s" % 1481 (library, 1482 target)) 1483 1484 1485def read_file_on_target(test, remote): 1486 if lldb.remote_platform: 1487 local = test.getBuildArtifact("file_from_target") 1488 error = lldb.remote_platform.Get(lldb.SBFileSpec(remote, False), 1489 lldb.SBFileSpec(local, True)) 1490 test.assertTrue(error.Success(), "Reading file {0} failed: {1}".format(remote, error)) 1491 else: 1492 local = remote 1493 with open(local, 'r') as f: 1494 return f.read() 1495 1496def read_file_from_process_wd(test, name): 1497 path = append_to_process_working_directory(test, name) 1498 return read_file_on_target(test, path) 1499 1500def wait_for_file_on_target(testcase, file_path, max_attempts=6): 1501 for i in range(max_attempts): 1502 err, retcode, msg = testcase.run_platform_command("ls %s" % file_path) 1503 if err.Success() and retcode == 0: 1504 break 1505 if i < max_attempts: 1506 # Exponential backoff! 1507 import time 1508 time.sleep(pow(2, i) * 0.25) 1509 else: 1510 testcase.fail( 1511 "File %s not found even after %d attempts." % 1512 (file_path, max_attempts)) 1513 1514 return read_file_on_target(testcase, file_path) 1515 1516def packetlog_get_process_info(log): 1517 """parse a gdb-remote packet log file and extract the response to qProcessInfo""" 1518 process_info = dict() 1519 with open(log, "r") as logfile: 1520 process_info_ostype = None 1521 expect_process_info_response = False 1522 for line in logfile: 1523 if expect_process_info_response: 1524 for pair in line.split(';'): 1525 keyval = pair.split(':') 1526 if len(keyval) == 2: 1527 process_info[keyval[0]] = keyval[1] 1528 break 1529 if 'send packet: $qProcessInfo#' in line: 1530 expect_process_info_response = True 1531 return process_info 1532 1533def packetlog_get_dylib_info(log): 1534 """parse a gdb-remote packet log file and extract the *last* complete 1535 (=> fetch_all_solibs=true) response to jGetLoadedDynamicLibrariesInfos""" 1536 import json 1537 dylib_info = None 1538 with open(log, "r") as logfile: 1539 dylib_info = None 1540 expect_dylib_info_response = False 1541 for line in logfile: 1542 if expect_dylib_info_response: 1543 while line[0] != '$': 1544 line = line[1:] 1545 line = line[1:] 1546 # Unescape '}'. 1547 dylib_info = json.loads(line.replace('}]','}')[:-4]) 1548 expect_dylib_info_response = False 1549 if 'send packet: $jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}' in line: 1550 expect_dylib_info_response = True 1551 1552 return dylib_info 1553