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