1"""Module for supporting unit testing of the lldb-server debug monitor exe. 2""" 3 4from __future__ import print_function 5 6 7 8import os 9import os.path 10import platform 11import re 12import six 13import socket_packet_pump 14import subprocess 15import time 16from lldbsuite.test.lldbtest import * 17 18from six.moves import queue 19 20def _get_debug_monitor_from_lldb(lldb_exe, debug_monitor_basename): 21 """Return the debug monitor exe path given the lldb exe path. 22 23 This method attempts to construct a valid debug monitor exe name 24 from a given lldb exe name. It will return None if the synthesized 25 debug monitor name is not found to exist. 26 27 The debug monitor exe path is synthesized by taking the directory 28 of the lldb exe, and replacing the portion of the base name that 29 matches "lldb" (case insensitive) and replacing with the value of 30 debug_monitor_basename. 31 32 Args: 33 lldb_exe: the path to an lldb executable. 34 35 debug_monitor_basename: the base name portion of the debug monitor 36 that will replace 'lldb'. 37 38 Returns: 39 A path to the debug monitor exe if it is found to exist; otherwise, 40 returns None. 41 42 """ 43 if not lldb_exe: 44 return None 45 46 exe_dir = os.path.dirname(lldb_exe) 47 exe_base = os.path.basename(lldb_exe) 48 49 # we'll rebuild the filename by replacing lldb with 50 # the debug monitor basename, keeping any prefix or suffix in place. 51 regex = re.compile(r"lldb", re.IGNORECASE) 52 new_base = regex.sub(debug_monitor_basename, exe_base) 53 54 debug_monitor_exe = os.path.join(exe_dir, new_base) 55 if os.path.exists(debug_monitor_exe): 56 return debug_monitor_exe 57 58 new_base = regex.sub( 'LLDB.framework/Versions/A/Resources/' + debug_monitor_basename, exe_base) 59 debug_monitor_exe = os.path.join(exe_dir, new_base) 60 if os.path.exists(debug_monitor_exe): 61 return debug_monitor_exe 62 63 return None 64 65 66def get_lldb_server_exe(): 67 """Return the lldb-server exe path. 68 69 Returns: 70 A path to the lldb-server exe if it is found to exist; otherwise, 71 returns None. 72 """ 73 if "LLDB_DEBUGSERVER_PATH" in os.environ: 74 return os.environ["LLDB_DEBUGSERVER_PATH"] 75 76 return _get_debug_monitor_from_lldb(lldbtest_config.lldbExec, "lldb-server") 77 78def get_debugserver_exe(): 79 """Return the debugserver exe path. 80 81 Returns: 82 A path to the debugserver exe if it is found to exist; otherwise, 83 returns None. 84 """ 85 if "LLDB_DEBUGSERVER_PATH" in os.environ: 86 return os.environ["LLDB_DEBUGSERVER_PATH"] 87 88 return _get_debug_monitor_from_lldb(lldbtest_config.lldbExec, "debugserver") 89 90_LOG_LINE_REGEX = re.compile(r'^(lldb-server|debugserver)\s+<\s*(\d+)>' + 91 '\s+(read|send)\s+packet:\s+(.+)$') 92 93 94def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read): 95 """Return whether a given packet is input for lldb-gdbserver. 96 97 Args: 98 packet_type: a string indicating 'send' or 'receive', from a 99 gdbremote packet protocol log. 100 101 llgs_input_is_read: true if lldb-gdbserver input (content sent to 102 lldb-gdbserver) is listed as 'read' or 'send' in the packet 103 log entry. 104 105 Returns: 106 True if the packet should be considered input for lldb-gdbserver; False 107 otherwise. 108 """ 109 if packet_type == 'read': 110 # when llgs is the read side, then a read packet is meant for 111 # input to llgs (when captured from the llgs/debugserver exe). 112 return llgs_input_is_read 113 elif packet_type == 'send': 114 # when llgs is the send side, then a send packet is meant to 115 # be input to llgs (when captured from the lldb exe). 116 return not llgs_input_is_read 117 else: 118 # don't understand what type of packet this is 119 raise "Unknown packet type: {}".format(packet_type) 120 121 122def handle_O_packet(context, packet_contents, logger): 123 """Handle O packets.""" 124 if (not packet_contents) or (len(packet_contents) < 1): 125 return False 126 elif packet_contents[0] != "O": 127 return False 128 elif packet_contents == "OK": 129 return False 130 131 new_text = gdbremote_hex_decode_string(packet_contents[1:]) 132 context["O_content"] += new_text 133 context["O_count"] += 1 134 135 if logger: 136 logger.debug("text: new \"{}\", cumulative: \"{}\"".format(new_text, context["O_content"])) 137 138 return True 139 140_STRIP_CHECKSUM_REGEX = re.compile(r'#[0-9a-fA-F]{2}$') 141_STRIP_COMMAND_PREFIX_REGEX = re.compile(r"^\$") 142_STRIP_COMMAND_PREFIX_M_REGEX = re.compile(r"^\$m") 143 144 145def assert_packets_equal(asserter, actual_packet, expected_packet): 146 # strip off the checksum digits of the packet. When we're in 147 # no-ack mode, the # checksum is ignored, and should not be cause 148 # for a mismatched packet. 149 actual_stripped = _STRIP_CHECKSUM_REGEX.sub('', actual_packet) 150 expected_stripped = _STRIP_CHECKSUM_REGEX.sub('', expected_packet) 151 asserter.assertEqual(actual_stripped, expected_stripped) 152 153def expect_lldb_gdbserver_replay( 154 asserter, 155 sock, 156 test_sequence, 157 pump_queues, 158 timeout_seconds, 159 logger=None): 160 """Replay socket communication with lldb-gdbserver and verify responses. 161 162 Args: 163 asserter: the object providing assertEqual(first, second, msg=None), e.g. TestCase instance. 164 165 sock: the TCP socket connected to the lldb-gdbserver exe. 166 167 test_sequence: a GdbRemoteTestSequence instance that describes 168 the messages sent to the gdb remote and the responses 169 expected from it. 170 171 timeout_seconds: any response taking more than this number of 172 seconds will cause an exception to be raised. 173 174 logger: a Python logger instance. 175 176 Returns: 177 The context dictionary from running the given gdbremote 178 protocol sequence. This will contain any of the capture 179 elements specified to any GdbRemoteEntry instances in 180 test_sequence. 181 182 The context will also contain an entry, context["O_content"] 183 which contains the text from the inferior received via $O 184 packets. $O packets should not attempt to be matched 185 directly since they are not entirely deterministic as to 186 how many arrive and how much text is in each one. 187 188 context["O_count"] will contain an integer of the number of 189 O packets received. 190 """ 191 192 # Ensure we have some work to do. 193 if len(test_sequence.entries) < 1: 194 return {} 195 196 context = {"O_count":0, "O_content":""} 197 with socket_packet_pump.SocketPacketPump(sock, pump_queues, logger) as pump: 198 # Grab the first sequence entry. 199 sequence_entry = test_sequence.entries.pop(0) 200 201 # While we have an active sequence entry, send messages 202 # destined for the stub and collect/match/process responses 203 # expected from the stub. 204 while sequence_entry: 205 if sequence_entry.is_send_to_remote(): 206 # This is an entry to send to the remote debug monitor. 207 send_packet = sequence_entry.get_send_packet() 208 if logger: 209 if len(send_packet) == 1 and send_packet[0] == chr(3): 210 packet_desc = "^C" 211 else: 212 packet_desc = send_packet 213 logger.info("sending packet to remote: {}".format(packet_desc)) 214 sock.sendall(send_packet) 215 else: 216 # This is an entry expecting to receive content from the remote debug monitor. 217 218 # We'll pull from (and wait on) the queue appropriate for the type of matcher. 219 # We keep separate queues for process output (coming from non-deterministic 220 # $O packet division) and for all other packets. 221 if sequence_entry.is_output_matcher(): 222 try: 223 # Grab next entry from the output queue. 224 content = pump_queues.output_queue().get(True, timeout_seconds) 225 except queue.Empty: 226 if logger: 227 logger.warning("timeout waiting for stub output (accumulated output:{})".format(pump.get_accumulated_output())) 228 raise Exception("timed out while waiting for output match (accumulated output: {})".format(pump.get_accumulated_output())) 229 else: 230 try: 231 content = pump_queues.packet_queue().get(True, timeout_seconds) 232 except queue.Empty: 233 if logger: 234 logger.warning("timeout waiting for packet match (receive buffer: {})".format(pump.get_receive_buffer())) 235 raise Exception("timed out while waiting for packet match (receive buffer: {})".format(pump.get_receive_buffer())) 236 237 # Give the sequence entry the opportunity to match the content. 238 # Output matchers might match or pass after more output accumulates. 239 # Other packet types generally must match. 240 asserter.assertIsNotNone(content) 241 context = sequence_entry.assert_match(asserter, content, context=context) 242 243 # Move on to next sequence entry as needed. Some sequence entries support executing multiple 244 # times in different states (for looping over query/response packets). 245 if sequence_entry.is_consumed(): 246 if len(test_sequence.entries) > 0: 247 sequence_entry = test_sequence.entries.pop(0) 248 else: 249 sequence_entry = None 250 251 # Fill in the O_content entries. 252 context["O_count"] = 1 253 context["O_content"] = pump.get_accumulated_output() 254 255 return context 256 257def gdbremote_hex_encode_string(str): 258 output = '' 259 for c in str: 260 output += '{0:02x}'.format(ord(c)) 261 return output 262 263def gdbremote_hex_decode_string(str): 264 return str.decode("hex") 265 266def gdbremote_packet_encode_string(str): 267 checksum = 0 268 for c in str: 269 checksum += ord(c) 270 return '$' + str + '#{0:02x}'.format(checksum % 256) 271 272def build_gdbremote_A_packet(args_list): 273 """Given a list of args, create a properly-formed $A packet containing each arg. 274 """ 275 payload = "A" 276 277 # build the arg content 278 arg_index = 0 279 for arg in args_list: 280 # Comma-separate the args. 281 if arg_index > 0: 282 payload += ',' 283 284 # Hex-encode the arg. 285 hex_arg = gdbremote_hex_encode_string(arg) 286 287 # Build the A entry. 288 payload += "{},{},{}".format(len(hex_arg), arg_index, hex_arg) 289 290 # Next arg index, please. 291 arg_index += 1 292 293 # return the packetized payload 294 return gdbremote_packet_encode_string(payload) 295 296 297def parse_reg_info_response(response_packet): 298 if not response_packet: 299 raise Exception("response_packet cannot be None") 300 301 # Strip off prefix $ and suffix #xx if present. 302 response_packet = _STRIP_COMMAND_PREFIX_REGEX.sub("", response_packet) 303 response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet) 304 305 # Build keyval pairs 306 values = {} 307 for kv in response_packet.split(";"): 308 if len(kv) < 1: 309 continue 310 (key, val) = kv.split(':') 311 values[key] = val 312 313 return values 314 315 316def parse_threadinfo_response(response_packet): 317 if not response_packet: 318 raise Exception("response_packet cannot be None") 319 320 # Strip off prefix $ and suffix #xx if present. 321 response_packet = _STRIP_COMMAND_PREFIX_M_REGEX.sub("", response_packet) 322 response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet) 323 324 # Return list of thread ids 325 return [int(thread_id_hex,16) for thread_id_hex in response_packet.split(",") if len(thread_id_hex) > 0] 326 327def unpack_endian_binary_string(endian, value_string): 328 """Unpack a gdb-remote binary (post-unescaped, i.e. not escaped) response to an unsigned int given endianness of the inferior.""" 329 if not endian: 330 raise Exception("endian cannot be None") 331 if not value_string or len(value_string) < 1: 332 raise Exception("value_string cannot be None or empty") 333 334 if endian == 'little': 335 value = 0 336 i = 0 337 while len(value_string) > 0: 338 value += (ord(value_string[0]) << i) 339 value_string = value_string[1:] 340 i += 8 341 return value 342 elif endian == 'big': 343 value = 0 344 while len(value_string) > 0: 345 value = (value << 8) + ord(value_string[0]) 346 value_string = value_string[1:] 347 return value 348 else: 349 # pdp is valid but need to add parse code once needed. 350 raise Exception("unsupported endian:{}".format(endian)) 351 352def unpack_register_hex_unsigned(endian, value_string): 353 """Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior.""" 354 if not endian: 355 raise Exception("endian cannot be None") 356 if not value_string or len(value_string) < 1: 357 raise Exception("value_string cannot be None or empty") 358 359 if endian == 'little': 360 value = 0 361 i = 0 362 while len(value_string) > 0: 363 value += (int(value_string[0:2], 16) << i) 364 value_string = value_string[2:] 365 i += 8 366 return value 367 elif endian == 'big': 368 return int(value_string, 16) 369 else: 370 # pdp is valid but need to add parse code once needed. 371 raise Exception("unsupported endian:{}".format(endian)) 372 373def pack_register_hex(endian, value, byte_size=None): 374 """Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior.""" 375 if not endian: 376 raise Exception("endian cannot be None") 377 378 if endian == 'little': 379 # Create the litt-endian return value. 380 retval = "" 381 while value != 0: 382 retval = retval + "{:02x}".format(value & 0xff) 383 value = value >> 8 384 if byte_size: 385 # Add zero-fill to the right/end (MSB side) of the value. 386 retval += "00" * (byte_size - len(retval)/2) 387 return retval 388 389 elif endian == 'big': 390 retval = "" 391 while value != 0: 392 retval = "{:02x}".format(value & 0xff) + retval 393 value = value >> 8 394 if byte_size: 395 # Add zero-fill to the left/front (MSB side) of the value. 396 retval = ("00" * (byte_size - len(retval)/2)) + retval 397 return retval 398 399 else: 400 # pdp is valid but need to add parse code once needed. 401 raise Exception("unsupported endian:{}".format(endian)) 402 403class GdbRemoteEntryBase(object): 404 def is_output_matcher(self): 405 return False 406 407class GdbRemoteEntry(GdbRemoteEntryBase): 408 409 def __init__(self, is_send_to_remote=True, exact_payload=None, regex=None, capture=None, expect_captures=None): 410 """Create an entry representing one piece of the I/O to/from a gdb remote debug monitor. 411 412 Args: 413 414 is_send_to_remote: True if this entry is a message to be 415 sent to the gdbremote debug monitor; False if this 416 entry represents text to be matched against the reply 417 from the gdbremote debug monitor. 418 419 exact_payload: if not None, then this packet is an exact 420 send (when sending to the remote) or an exact match of 421 the response from the gdbremote. The checksums are 422 ignored on exact match requests since negotiation of 423 no-ack makes the checksum content essentially 424 undefined. 425 426 regex: currently only valid for receives from gdbremote. 427 When specified (and only if exact_payload is None), 428 indicates the gdbremote response must match the given 429 regex. Match groups in the regex can be used for two 430 different purposes: saving the match (see capture 431 arg), or validating that a match group matches a 432 previously established value (see expect_captures). It 433 is perfectly valid to have just a regex arg and to 434 specify neither capture or expect_captures args. This 435 arg only makes sense if exact_payload is not 436 specified. 437 438 capture: if specified, is a dictionary of regex match 439 group indices (should start with 1) to variable names 440 that will store the capture group indicated by the 441 index. For example, {1:"thread_id"} will store capture 442 group 1's content in the context dictionary where 443 "thread_id" is the key and the match group value is 444 the value. The value stored off can be used later in a 445 expect_captures expression. This arg only makes sense 446 when regex is specified. 447 448 expect_captures: if specified, is a dictionary of regex 449 match group indices (should start with 1) to variable 450 names, where the match group should match the value 451 existing in the context at the given variable name. 452 For example, {2:"thread_id"} indicates that the second 453 match group must match the value stored under the 454 context's previously stored "thread_id" key. This arg 455 only makes sense when regex is specified. 456 """ 457 self._is_send_to_remote = is_send_to_remote 458 self.exact_payload = exact_payload 459 self.regex = regex 460 self.capture = capture 461 self.expect_captures = expect_captures 462 463 def is_send_to_remote(self): 464 return self._is_send_to_remote 465 466 def is_consumed(self): 467 # For now, all packets are consumed after first use. 468 return True 469 470 def get_send_packet(self): 471 if not self.is_send_to_remote(): 472 raise Exception("get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet") 473 if not self.exact_payload: 474 raise Exception("get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload") 475 return self.exact_payload 476 477 def _assert_exact_payload_match(self, asserter, actual_packet): 478 assert_packets_equal(asserter, actual_packet, self.exact_payload) 479 return None 480 481 def _assert_regex_match(self, asserter, actual_packet, context): 482 # Ensure the actual packet matches from the start of the actual packet. 483 match = self.regex.match(actual_packet) 484 if not match: 485 asserter.fail("regex '{}' failed to match against content '{}'".format(self.regex.pattern, actual_packet)) 486 487 if self.capture: 488 # Handle captures. 489 for group_index, var_name in list(self.capture.items()): 490 capture_text = match.group(group_index) 491 # It is okay for capture text to be None - which it will be if it is a group that can match nothing. 492 # The user must be okay with it since the regex itself matched above. 493 context[var_name] = capture_text 494 495 if self.expect_captures: 496 # Handle comparing matched groups to context dictionary entries. 497 for group_index, var_name in list(self.expect_captures.items()): 498 capture_text = match.group(group_index) 499 if not capture_text: 500 raise Exception("No content to expect for group index {}".format(group_index)) 501 asserter.assertEqual(capture_text, context[var_name]) 502 503 return context 504 505 def assert_match(self, asserter, actual_packet, context=None): 506 # This only makes sense for matching lines coming from the 507 # remote debug monitor. 508 if self.is_send_to_remote(): 509 raise Exception("Attempted to match a packet being sent to the remote debug monitor, doesn't make sense.") 510 511 # Create a new context if needed. 512 if not context: 513 context = {} 514 515 # If this is an exact payload, ensure they match exactly, 516 # ignoring the packet checksum which is optional for no-ack 517 # mode. 518 if self.exact_payload: 519 self._assert_exact_payload_match(asserter, actual_packet) 520 return context 521 elif self.regex: 522 return self._assert_regex_match(asserter, actual_packet, context) 523 else: 524 raise Exception("Don't know how to match a remote-sent packet when exact_payload isn't specified.") 525 526class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase): 527 """Represents a query/response style packet. 528 529 Assumes the first item is sent to the gdb remote. 530 An end sequence regex indicates the end of the query/response 531 packet sequence. All responses up through (but not including) the 532 end response are stored in a context variable. 533 534 Settings accepted from params: 535 536 next_query or query: required. The typical query packet without the $ prefix or #xx suffix. 537 If there is a special first packet to start the iteration query, see the 538 first_query key. 539 540 first_query: optional. If the first query requires a special query command, specify 541 it with this key. Do not specify the $ prefix or #xx suffix. 542 543 append_iteration_suffix: defaults to False. Specify True if the 0-based iteration 544 index should be appended as a suffix to the command. e.g. qRegisterInfo with 545 this key set true will generate query packets of qRegisterInfo0, qRegisterInfo1, 546 etc. 547 548 end_regex: required. Specifies a compiled regex object that will match the full text 549 of any response that signals an end to the iteration. It must include the 550 initial $ and ending #xx and must match the whole packet. 551 552 save_key: required. Specifies the key within the context where an array will be stored. 553 Each packet received from the gdb remote that does not match the end_regex will get 554 appended to the array stored within the context at that key. 555 556 runaway_response_count: optional. Defaults to 10000. If this many responses are retrieved, 557 assume there is something wrong with either the response collection or the ending 558 detection regex and throw an exception. 559 """ 560 def __init__(self, params): 561 self._next_query = params.get("next_query", params.get("query")) 562 if not self._next_query: 563 raise "either next_query or query key must be specified for MultiResponseGdbRemoteEntry" 564 565 self._first_query = params.get("first_query", self._next_query) 566 self._append_iteration_suffix = params.get("append_iteration_suffix", False) 567 self._iteration = 0 568 self._end_regex = params["end_regex"] 569 self._save_key = params["save_key"] 570 self._runaway_response_count = params.get("runaway_response_count", 10000) 571 self._is_send_to_remote = True 572 self._end_matched = False 573 574 def is_send_to_remote(self): 575 return self._is_send_to_remote 576 577 def get_send_packet(self): 578 if not self.is_send_to_remote(): 579 raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state") 580 if self._end_matched: 581 raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.") 582 583 # Choose the first or next query for the base payload. 584 if self._iteration == 0 and self._first_query: 585 payload = self._first_query 586 else: 587 payload = self._next_query 588 589 # Append the suffix as needed. 590 if self._append_iteration_suffix: 591 payload += "%x" % self._iteration 592 593 # Keep track of the iteration. 594 self._iteration += 1 595 596 # Now that we've given the query packet, flip the mode to receive/match. 597 self._is_send_to_remote = False 598 599 # Return the result, converted to packet form. 600 return gdbremote_packet_encode_string(payload) 601 602 def is_consumed(self): 603 return self._end_matched 604 605 def assert_match(self, asserter, actual_packet, context=None): 606 # This only makes sense for matching lines coming from the remote debug monitor. 607 if self.is_send_to_remote(): 608 raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet.") 609 610 if self._end_matched: 611 raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.") 612 613 # Set up a context as needed. 614 if not context: 615 context = {} 616 617 # Check if the packet matches the end condition. 618 match = self._end_regex.match(actual_packet) 619 if match: 620 # We're done iterating. 621 self._end_matched = True 622 return context 623 624 # Not done iterating - save the packet. 625 context[self._save_key] = context.get(self._save_key, []) 626 context[self._save_key].append(actual_packet) 627 628 # Check for a runaway response cycle. 629 if len(context[self._save_key]) >= self._runaway_response_count: 630 raise Exception("runaway query/response cycle detected: %d responses captured so far. Last response: %s" % 631 (len(context[self._save_key]), context[self._save_key][-1])) 632 633 # Flip the mode to send for generating the query. 634 self._is_send_to_remote = True 635 return context 636 637class MatchRemoteOutputEntry(GdbRemoteEntryBase): 638 """Waits for output from the debug monitor to match a regex or time out. 639 640 This entry type tries to match each time new gdb remote output is accumulated 641 using a provided regex. If the output does not match the regex within the 642 given timeframe, the command fails the playback session. If the regex does 643 match, any capture fields are recorded in the context. 644 645 Settings accepted from params: 646 647 regex: required. Specifies a compiled regex object that must either succeed 648 with re.match or re.search (see regex_mode below) within the given timeout 649 (see timeout_seconds below) or cause the playback to fail. 650 651 regex_mode: optional. Available values: "match" or "search". If "match", the entire 652 stub output as collected so far must match the regex. If search, then the regex 653 must match starting somewhere within the output text accumulated thus far. 654 Default: "match" (i.e. the regex must match the entirety of the accumulated output 655 buffer, so unexpected text will generally fail the match). 656 657 capture: optional. If specified, is a dictionary of regex match group indices (should start 658 with 1) to variable names that will store the capture group indicated by the 659 index. For example, {1:"thread_id"} will store capture group 1's content in the 660 context dictionary where "thread_id" is the key and the match group value is 661 the value. The value stored off can be used later in a expect_captures expression. 662 This arg only makes sense when regex is specified. 663 """ 664 def __init__(self, regex=None, regex_mode="match", capture=None): 665 self._regex = regex 666 self._regex_mode = regex_mode 667 self._capture = capture 668 self._matched = False 669 670 if not self._regex: 671 raise Exception("regex cannot be None") 672 673 if not self._regex_mode in ["match", "search"]: 674 raise Exception("unsupported regex mode \"{}\": must be \"match\" or \"search\"".format(self._regex_mode)) 675 676 def is_output_matcher(self): 677 return True 678 679 def is_send_to_remote(self): 680 # This is always a "wait for remote" command. 681 return False 682 683 def is_consumed(self): 684 return self._matched 685 686 def assert_match(self, asserter, accumulated_output, context): 687 # Validate args. 688 if not accumulated_output: 689 raise Exception("accumulated_output cannot be none") 690 if not context: 691 raise Exception("context cannot be none") 692 693 # Validate that we haven't already matched. 694 if self._matched: 695 raise Exception("invalid state - already matched, attempting to match again") 696 697 # If we don't have any content yet, we don't match. 698 if len(accumulated_output) < 1: 699 return context 700 701 # Check if we match 702 if self._regex_mode == "match": 703 match = self._regex.match(accumulated_output) 704 elif self._regex_mode == "search": 705 match = self._regex.search(accumulated_output) 706 else: 707 raise Exception("Unexpected regex mode: {}".format(self._regex_mode)) 708 709 # If we don't match, wait to try again after next $O content, or time out. 710 if not match: 711 # print("re pattern \"{}\" did not match against \"{}\"".format(self._regex.pattern, accumulated_output)) 712 return context 713 714 # We do match. 715 self._matched = True 716 # print("re pattern \"{}\" matched against \"{}\"".format(self._regex.pattern, accumulated_output)) 717 718 # Collect up any captures into the context. 719 if self._capture: 720 # Handle captures. 721 for group_index, var_name in list(self._capture.items()): 722 capture_text = match.group(group_index) 723 if not capture_text: 724 raise Exception("No content for group index {}".format(group_index)) 725 context[var_name] = capture_text 726 727 return context 728 729 730class GdbRemoteTestSequence(object): 731 732 _LOG_LINE_REGEX = re.compile(r'^.*(read|send)\s+packet:\s+(.+)$') 733 734 def __init__(self, logger): 735 self.entries = [] 736 self.logger = logger 737 738 def add_log_lines(self, log_lines, remote_input_is_read): 739 for line in log_lines: 740 if type(line) == str: 741 # Handle log line import 742 # if self.logger: 743 # self.logger.debug("processing log line: {}".format(line)) 744 match = self._LOG_LINE_REGEX.match(line) 745 if match: 746 playback_packet = match.group(2) 747 direction = match.group(1) 748 if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read): 749 # Handle as something to send to the remote debug monitor. 750 # if self.logger: 751 # self.logger.info("processed packet to send to remote: {}".format(playback_packet)) 752 self.entries.append(GdbRemoteEntry(is_send_to_remote=True, exact_payload=playback_packet)) 753 else: 754 # Log line represents content to be expected from the remote debug monitor. 755 # if self.logger: 756 # self.logger.info("receiving packet from llgs, should match: {}".format(playback_packet)) 757 self.entries.append(GdbRemoteEntry(is_send_to_remote=False,exact_payload=playback_packet)) 758 else: 759 raise Exception("failed to interpret log line: {}".format(line)) 760 elif type(line) == dict: 761 entry_type = line.get("type", "regex_capture") 762 if entry_type == "regex_capture": 763 # Handle more explicit control over details via dictionary. 764 direction = line.get("direction", None) 765 regex = line.get("regex", None) 766 capture = line.get("capture", None) 767 expect_captures = line.get("expect_captures", None) 768 769 # Compile the regex. 770 if regex and (type(regex) == str): 771 regex = re.compile(regex) 772 773 if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read): 774 # Handle as something to send to the remote debug monitor. 775 # if self.logger: 776 # self.logger.info("processed dict sequence to send to remote") 777 self.entries.append(GdbRemoteEntry(is_send_to_remote=True, regex=regex, capture=capture, expect_captures=expect_captures)) 778 else: 779 # Log line represents content to be expected from the remote debug monitor. 780 # if self.logger: 781 # self.logger.info("processed dict sequence to match receiving from remote") 782 self.entries.append(GdbRemoteEntry(is_send_to_remote=False, regex=regex, capture=capture, expect_captures=expect_captures)) 783 elif entry_type == "multi_response": 784 self.entries.append(MultiResponseGdbRemoteEntry(line)) 785 elif entry_type == "output_match": 786 787 regex = line.get("regex", None) 788 # Compile the regex. 789 if regex and (type(regex) == str): 790 regex = re.compile(regex, re.DOTALL) 791 792 regex_mode = line.get("regex_mode", "match") 793 capture = line.get("capture", None) 794 self.entries.append(MatchRemoteOutputEntry(regex=regex, regex_mode=regex_mode, capture=capture)) 795 else: 796 raise Exception("unknown entry type \"%s\"" % entry_type) 797 798def process_is_running(pid, unknown_value=True): 799 """If possible, validate that the given pid represents a running process on the local system. 800 801 Args: 802 803 pid: an OS-specific representation of a process id. Should be an integral value. 804 805 unknown_value: value used when we cannot determine how to check running local 806 processes on the OS. 807 808 Returns: 809 810 If we can figure out how to check running process ids on the given OS: 811 return True if the process is running, or False otherwise. 812 813 If we don't know how to check running process ids on the given OS: 814 return the value provided by the unknown_value arg. 815 """ 816 if not isinstance(pid, six.integer_types): 817 raise Exception("pid must be an integral type (actual type: %s)" % str(type(pid))) 818 819 process_ids = [] 820 821 if lldb.remote_platform: 822 # Don't know how to get list of running process IDs on a remote 823 # platform 824 return unknown_value 825 elif platform.system() in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']: 826 # Build the list of running process ids 827 output = subprocess.check_output("ps ax | awk '{ print $1; }'", shell=True) 828 text_process_ids = output.split('\n')[1:] 829 # Convert text pids to ints 830 process_ids = [int(text_pid) for text_pid in text_process_ids if text_pid != ''] 831 # elif {your_platform_here}: 832 # fill in process_ids as a list of int type process IDs running on 833 # the local system. 834 else: 835 # Don't know how to get list of running process IDs on this 836 # OS, so return the "don't know" value. 837 return unknown_value 838 839 # Check if the pid is in the process_ids 840 return pid in process_ids 841 842if __name__ == '__main__': 843 EXE_PATH = get_lldb_server_exe() 844 if EXE_PATH: 845 print("lldb-server path detected: {}".format(EXE_PATH)) 846 else: 847 print("lldb-server could not be found") 848