1 """Module for supporting unit testing of the lldb-server debug monitor exe.
4 from __future__ import print_function
12 import socket_packet_pump
15 from lldbsuite.test.lldbtest import *
17 from six.moves import queue
20 def _get_debug_monitor_from_lldb(lldb_exe, debug_monitor_basename):
21 """Return the debug monitor exe path given the lldb exe path.
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.
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.
33 lldb_exe: the path to an lldb executable.
35 debug_monitor_basename: the base name portion of the debug monitor
36 that will replace 'lldb'.
39 A path to the debug monitor exe if it is found to exist; otherwise,
46 exe_dir = os.path.dirname(lldb_exe)
47 exe_base = os.path.basename(lldb_exe)
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)
54 debug_monitor_exe = os.path.join(exe_dir, new_base)
55 if os.path.exists(debug_monitor_exe):
56 return debug_monitor_exe
59 'LLDB.framework/Versions/A/Resources/' +
60 debug_monitor_basename,
62 debug_monitor_exe = os.path.join(exe_dir, new_base)
63 if os.path.exists(debug_monitor_exe):
64 return debug_monitor_exe
69 def get_lldb_server_exe():
70 """Return the lldb-server exe path.
73 A path to the lldb-server exe if it is found to exist; otherwise,
76 if "LLDB_DEBUGSERVER_PATH" in os.environ:
77 return os.environ["LLDB_DEBUGSERVER_PATH"]
79 return _get_debug_monitor_from_lldb(
80 lldbtest_config.lldbExec, "lldb-server")
83 def get_debugserver_exe():
84 """Return the debugserver exe path.
87 A path to the debugserver exe if it is found to exist; otherwise,
90 if "LLDB_DEBUGSERVER_PATH" in os.environ:
91 return os.environ["LLDB_DEBUGSERVER_PATH"]
93 return _get_debug_monitor_from_lldb(
94 lldbtest_config.lldbExec, "debugserver")
96 _LOG_LINE_REGEX = re.compile(r'^(lldb-server|debugserver)\s+<\s*(\d+)>' +
97 '\s+(read|send)\s+packet:\s+(.+)$')
100 def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read):
101 """Return whether a given packet is input for lldb-gdbserver.
104 packet_type: a string indicating 'send' or 'receive', from a
105 gdbremote packet protocol log.
107 llgs_input_is_read: true if lldb-gdbserver input (content sent to
108 lldb-gdbserver) is listed as 'read' or 'send' in the packet
112 True if the packet should be considered input for lldb-gdbserver; False
115 if packet_type == 'read':
116 # when llgs is the read side, then a read packet is meant for
117 # input to llgs (when captured from the llgs/debugserver exe).
118 return llgs_input_is_read
119 elif packet_type == 'send':
120 # when llgs is the send side, then a send packet is meant to
121 # be input to llgs (when captured from the lldb exe).
122 return not llgs_input_is_read
124 # don't understand what type of packet this is
125 raise "Unknown packet type: {}".format(packet_type)
128 def handle_O_packet(context, packet_contents, logger):
129 """Handle O packets."""
130 if (not packet_contents) or (len(packet_contents) < 1):
132 elif packet_contents[0] != "O":
134 elif packet_contents == "OK":
137 new_text = gdbremote_hex_decode_string(packet_contents[1:])
138 context["O_content"] += new_text
139 context["O_count"] += 1
143 "text: new \"{}\", cumulative: \"{}\"".format(
144 new_text, context["O_content"]))
148 _STRIP_CHECKSUM_REGEX = re.compile(r'#[0-9a-fA-F]{2}$')
149 _STRIP_COMMAND_PREFIX_REGEX = re.compile(r"^\$")
150 _STRIP_COMMAND_PREFIX_M_REGEX = re.compile(r"^\$m")
153 def assert_packets_equal(asserter, actual_packet, expected_packet):
154 # strip off the checksum digits of the packet. When we're in
155 # no-ack mode, the # checksum is ignored, and should not be cause
156 # for a mismatched packet.
157 actual_stripped = _STRIP_CHECKSUM_REGEX.sub('', actual_packet)
158 expected_stripped = _STRIP_CHECKSUM_REGEX.sub('', expected_packet)
159 asserter.assertEqual(actual_stripped, expected_stripped)
162 def expect_lldb_gdbserver_replay(
169 """Replay socket communication with lldb-gdbserver and verify responses.
172 asserter: the object providing assertEqual(first, second, msg=None), e.g. TestCase instance.
174 sock: the TCP socket connected to the lldb-gdbserver exe.
176 test_sequence: a GdbRemoteTestSequence instance that describes
177 the messages sent to the gdb remote and the responses
180 timeout_seconds: any response taking more than this number of
181 seconds will cause an exception to be raised.
183 logger: a Python logger instance.
186 The context dictionary from running the given gdbremote
187 protocol sequence. This will contain any of the capture
188 elements specified to any GdbRemoteEntry instances in
191 The context will also contain an entry, context["O_content"]
192 which contains the text from the inferior received via $O
193 packets. $O packets should not attempt to be matched
194 directly since they are not entirely deterministic as to
195 how many arrive and how much text is in each one.
197 context["O_count"] will contain an integer of the number of
201 # Ensure we have some work to do.
202 if len(test_sequence.entries) < 1:
205 context = {"O_count": 0, "O_content": ""}
206 with socket_packet_pump.SocketPacketPump(sock, pump_queues, logger) as pump:
207 # Grab the first sequence entry.
208 sequence_entry = test_sequence.entries.pop(0)
210 # While we have an active sequence entry, send messages
211 # destined for the stub and collect/match/process responses
212 # expected from the stub.
213 while sequence_entry:
214 if sequence_entry.is_send_to_remote():
215 # This is an entry to send to the remote debug monitor.
216 send_packet = sequence_entry.get_send_packet()
218 if len(send_packet) == 1 and send_packet[0] == chr(3):
221 packet_desc = send_packet
223 "sending packet to remote: {}".format(packet_desc))
224 sock.sendall(send_packet)
226 # This is an entry expecting to receive content from the remote
229 # We'll pull from (and wait on) the queue appropriate for the type of matcher.
230 # We keep separate queues for process output (coming from non-deterministic
231 # $O packet division) and for all other packets.
232 if sequence_entry.is_output_matcher():
234 # Grab next entry from the output queue.
235 content = pump_queues.output_queue().get(True, timeout_seconds)
239 "timeout waiting for stub output (accumulated output:{})".format(
240 pump.get_accumulated_output()))
242 "timed out while waiting for output match (accumulated output: {})".format(
243 pump.get_accumulated_output()))
246 content = pump_queues.packet_queue().get(True, timeout_seconds)
250 "timeout waiting for packet match (receive buffer: {})".format(
251 pump.get_receive_buffer()))
253 "timed out while waiting for packet match (receive buffer: {})".format(
254 pump.get_receive_buffer()))
256 # Give the sequence entry the opportunity to match the content.
257 # Output matchers might match or pass after more output accumulates.
258 # Other packet types generally must match.
259 asserter.assertIsNotNone(content)
260 context = sequence_entry.assert_match(
261 asserter, content, context=context)
263 # Move on to next sequence entry as needed. Some sequence entries support executing multiple
264 # times in different states (for looping over query/response
266 if sequence_entry.is_consumed():
267 if len(test_sequence.entries) > 0:
268 sequence_entry = test_sequence.entries.pop(0)
270 sequence_entry = None
272 # Fill in the O_content entries.
273 context["O_count"] = 1
274 context["O_content"] = pump.get_accumulated_output()
279 def gdbremote_hex_encode_string(str):
282 output += '{0:02x}'.format(ord(c))
286 def gdbremote_hex_decode_string(str):
287 return str.decode("hex")
290 def gdbremote_packet_encode_string(str):
294 return '$' + str + '#{0:02x}'.format(checksum % 256)
297 def build_gdbremote_A_packet(args_list):
298 """Given a list of args, create a properly-formed $A packet containing each arg.
302 # build the arg content
304 for arg in args_list:
305 # Comma-separate the args.
309 # Hex-encode the arg.
310 hex_arg = gdbremote_hex_encode_string(arg)
313 payload += "{},{},{}".format(len(hex_arg), arg_index, hex_arg)
315 # Next arg index, please.
318 # return the packetized payload
319 return gdbremote_packet_encode_string(payload)
322 def parse_reg_info_response(response_packet):
323 if not response_packet:
324 raise Exception("response_packet cannot be None")
326 # Strip off prefix $ and suffix #xx if present.
327 response_packet = _STRIP_COMMAND_PREFIX_REGEX.sub("", response_packet)
328 response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet)
332 for kv in response_packet.split(";"):
335 (key, val) = kv.split(':')
341 def parse_threadinfo_response(response_packet):
342 if not response_packet:
343 raise Exception("response_packet cannot be None")
345 # Strip off prefix $ and suffix #xx if present.
346 response_packet = _STRIP_COMMAND_PREFIX_M_REGEX.sub("", response_packet)
347 response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet)
349 # Return list of thread ids
350 return [int(thread_id_hex, 16) for thread_id_hex in response_packet.split(
351 ",") if len(thread_id_hex) > 0]
354 def unpack_endian_binary_string(endian, value_string):
355 """Unpack a gdb-remote binary (post-unescaped, i.e. not escaped) response to an unsigned int given endianness of the inferior."""
357 raise Exception("endian cannot be None")
358 if not value_string or len(value_string) < 1:
359 raise Exception("value_string cannot be None or empty")
361 if endian == 'little':
364 while len(value_string) > 0:
365 value += (ord(value_string[0]) << i)
366 value_string = value_string[1:]
369 elif endian == 'big':
371 while len(value_string) > 0:
372 value = (value << 8) + ord(value_string[0])
373 value_string = value_string[1:]
376 # pdp is valid but need to add parse code once needed.
377 raise Exception("unsupported endian:{}".format(endian))
380 def unpack_register_hex_unsigned(endian, value_string):
381 """Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior."""
383 raise Exception("endian cannot be None")
384 if not value_string or len(value_string) < 1:
385 raise Exception("value_string cannot be None or empty")
387 if endian == 'little':
390 while len(value_string) > 0:
391 value += (int(value_string[0:2], 16) << i)
392 value_string = value_string[2:]
395 elif endian == 'big':
396 return int(value_string, 16)
398 # pdp is valid but need to add parse code once needed.
399 raise Exception("unsupported endian:{}".format(endian))
402 def pack_register_hex(endian, value, byte_size=None):
403 """Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior."""
405 raise Exception("endian cannot be None")
407 if endian == 'little':
408 # Create the litt-endian return value.
411 retval = retval + "{:02x}".format(value & 0xff)
414 # Add zero-fill to the right/end (MSB side) of the value.
415 retval += "00" * (byte_size - len(retval) / 2)
418 elif endian == 'big':
421 retval = "{:02x}".format(value & 0xff) + retval
424 # Add zero-fill to the left/front (MSB side) of the value.
425 retval = ("00" * (byte_size - len(retval) / 2)) + retval
429 # pdp is valid but need to add parse code once needed.
430 raise Exception("unsupported endian:{}".format(endian))
433 class GdbRemoteEntryBase(object):
435 def is_output_matcher(self):
439 class GdbRemoteEntry(GdbRemoteEntryBase):
443 is_send_to_remote=True,
447 expect_captures=None):
448 """Create an entry representing one piece of the I/O to/from a gdb remote debug monitor.
452 is_send_to_remote: True if this entry is a message to be
453 sent to the gdbremote debug monitor; False if this
454 entry represents text to be matched against the reply
455 from the gdbremote debug monitor.
457 exact_payload: if not None, then this packet is an exact
458 send (when sending to the remote) or an exact match of
459 the response from the gdbremote. The checksums are
460 ignored on exact match requests since negotiation of
461 no-ack makes the checksum content essentially
464 regex: currently only valid for receives from gdbremote.
465 When specified (and only if exact_payload is None),
466 indicates the gdbremote response must match the given
467 regex. Match groups in the regex can be used for two
468 different purposes: saving the match (see capture
469 arg), or validating that a match group matches a
470 previously established value (see expect_captures). It
471 is perfectly valid to have just a regex arg and to
472 specify neither capture or expect_captures args. This
473 arg only makes sense if exact_payload is not
476 capture: if specified, is a dictionary of regex match
477 group indices (should start with 1) to variable names
478 that will store the capture group indicated by the
479 index. For example, {1:"thread_id"} will store capture
480 group 1's content in the context dictionary where
481 "thread_id" is the key and the match group value is
482 the value. The value stored off can be used later in a
483 expect_captures expression. This arg only makes sense
484 when regex is specified.
486 expect_captures: if specified, is a dictionary of regex
487 match group indices (should start with 1) to variable
488 names, where the match group should match the value
489 existing in the context at the given variable name.
490 For example, {2:"thread_id"} indicates that the second
491 match group must match the value stored under the
492 context's previously stored "thread_id" key. This arg
493 only makes sense when regex is specified.
495 self._is_send_to_remote = is_send_to_remote
496 self.exact_payload = exact_payload
498 self.capture = capture
499 self.expect_captures = expect_captures
501 def is_send_to_remote(self):
502 return self._is_send_to_remote
504 def is_consumed(self):
505 # For now, all packets are consumed after first use.
508 def get_send_packet(self):
509 if not self.is_send_to_remote():
511 "get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet")
512 if not self.exact_payload:
514 "get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload")
515 return self.exact_payload
517 def _assert_exact_payload_match(self, asserter, actual_packet):
518 assert_packets_equal(asserter, actual_packet, self.exact_payload)
521 def _assert_regex_match(self, asserter, actual_packet, context):
522 # Ensure the actual packet matches from the start of the actual packet.
523 match = self.regex.match(actual_packet)
526 "regex '{}' failed to match against content '{}'".format(
527 self.regex.pattern, actual_packet))
531 for group_index, var_name in list(self.capture.items()):
532 capture_text = match.group(group_index)
533 # It is okay for capture text to be None - which it will be if it is a group that can match nothing.
534 # The user must be okay with it since the regex itself matched
536 context[var_name] = capture_text
538 if self.expect_captures:
539 # Handle comparing matched groups to context dictionary entries.
540 for group_index, var_name in list(self.expect_captures.items()):
541 capture_text = match.group(group_index)
544 "No content to expect for group index {}".format(group_index))
545 asserter.assertEqual(capture_text, context[var_name])
549 def assert_match(self, asserter, actual_packet, context=None):
550 # This only makes sense for matching lines coming from the
551 # remote debug monitor.
552 if self.is_send_to_remote():
554 "Attempted to match a packet being sent to the remote debug monitor, doesn't make sense.")
556 # Create a new context if needed.
560 # If this is an exact payload, ensure they match exactly,
561 # ignoring the packet checksum which is optional for no-ack
563 if self.exact_payload:
564 self._assert_exact_payload_match(asserter, actual_packet)
567 return self._assert_regex_match(asserter, actual_packet, context)
570 "Don't know how to match a remote-sent packet when exact_payload isn't specified.")
573 class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
574 """Represents a query/response style packet.
576 Assumes the first item is sent to the gdb remote.
577 An end sequence regex indicates the end of the query/response
578 packet sequence. All responses up through (but not including) the
579 end response are stored in a context variable.
581 Settings accepted from params:
583 next_query or query: required. The typical query packet without the $ prefix or #xx suffix.
584 If there is a special first packet to start the iteration query, see the
587 first_query: optional. If the first query requires a special query command, specify
588 it with this key. Do not specify the $ prefix or #xx suffix.
590 append_iteration_suffix: defaults to False. Specify True if the 0-based iteration
591 index should be appended as a suffix to the command. e.g. qRegisterInfo with
592 this key set true will generate query packets of qRegisterInfo0, qRegisterInfo1,
595 end_regex: required. Specifies a compiled regex object that will match the full text
596 of any response that signals an end to the iteration. It must include the
597 initial $ and ending #xx and must match the whole packet.
599 save_key: required. Specifies the key within the context where an array will be stored.
600 Each packet received from the gdb remote that does not match the end_regex will get
601 appended to the array stored within the context at that key.
603 runaway_response_count: optional. Defaults to 10000. If this many responses are retrieved,
604 assume there is something wrong with either the response collection or the ending
605 detection regex and throw an exception.
608 def __init__(self, params):
609 self._next_query = params.get("next_query", params.get("query"))
610 if not self._next_query:
611 raise "either next_query or query key must be specified for MultiResponseGdbRemoteEntry"
613 self._first_query = params.get("first_query", self._next_query)
614 self._append_iteration_suffix = params.get(
615 "append_iteration_suffix", False)
617 self._end_regex = params["end_regex"]
618 self._save_key = params["save_key"]
619 self._runaway_response_count = params.get(
620 "runaway_response_count", 10000)
621 self._is_send_to_remote = True
622 self._end_matched = False
624 def is_send_to_remote(self):
625 return self._is_send_to_remote
627 def get_send_packet(self):
628 if not self.is_send_to_remote():
630 "get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state")
631 if self._end_matched:
633 "get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
635 # Choose the first or next query for the base payload.
636 if self._iteration == 0 and self._first_query:
637 payload = self._first_query
639 payload = self._next_query
641 # Append the suffix as needed.
642 if self._append_iteration_suffix:
643 payload += "%x" % self._iteration
645 # Keep track of the iteration.
648 # Now that we've given the query packet, flip the mode to
650 self._is_send_to_remote = False
652 # Return the result, converted to packet form.
653 return gdbremote_packet_encode_string(payload)
655 def is_consumed(self):
656 return self._end_matched
658 def assert_match(self, asserter, actual_packet, context=None):
659 # This only makes sense for matching lines coming from the remote debug
661 if self.is_send_to_remote():
663 "assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet.")
665 if self._end_matched:
667 "assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
669 # Set up a context as needed.
673 # Check if the packet matches the end condition.
674 match = self._end_regex.match(actual_packet)
676 # We're done iterating.
677 self._end_matched = True
680 # Not done iterating - save the packet.
681 context[self._save_key] = context.get(self._save_key, [])
682 context[self._save_key].append(actual_packet)
684 # Check for a runaway response cycle.
685 if len(context[self._save_key]) >= self._runaway_response_count:
687 "runaway query/response cycle detected: %d responses captured so far. Last response: %s" %
690 self._save_key]), context[
694 # Flip the mode to send for generating the query.
695 self._is_send_to_remote = True
699 class MatchRemoteOutputEntry(GdbRemoteEntryBase):
700 """Waits for output from the debug monitor to match a regex or time out.
702 This entry type tries to match each time new gdb remote output is accumulated
703 using a provided regex. If the output does not match the regex within the
704 given timeframe, the command fails the playback session. If the regex does
705 match, any capture fields are recorded in the context.
707 Settings accepted from params:
709 regex: required. Specifies a compiled regex object that must either succeed
710 with re.match or re.search (see regex_mode below) within the given timeout
711 (see timeout_seconds below) or cause the playback to fail.
713 regex_mode: optional. Available values: "match" or "search". If "match", the entire
714 stub output as collected so far must match the regex. If search, then the regex
715 must match starting somewhere within the output text accumulated thus far.
716 Default: "match" (i.e. the regex must match the entirety of the accumulated output
717 buffer, so unexpected text will generally fail the match).
719 capture: optional. If specified, is a dictionary of regex match group indices (should start
720 with 1) to variable names that will store the capture group indicated by the
721 index. For example, {1:"thread_id"} will store capture group 1's content in the
722 context dictionary where "thread_id" is the key and the match group value is
723 the value. The value stored off can be used later in a expect_captures expression.
724 This arg only makes sense when regex is specified.
727 def __init__(self, regex=None, regex_mode="match", capture=None):
729 self._regex_mode = regex_mode
730 self._capture = capture
731 self._matched = False
734 raise Exception("regex cannot be None")
736 if not self._regex_mode in ["match", "search"]:
738 "unsupported regex mode \"{}\": must be \"match\" or \"search\"".format(
741 def is_output_matcher(self):
744 def is_send_to_remote(self):
745 # This is always a "wait for remote" command.
748 def is_consumed(self):
751 def assert_match(self, asserter, accumulated_output, context):
753 if not accumulated_output:
754 raise Exception("accumulated_output cannot be none")
756 raise Exception("context cannot be none")
758 # Validate that we haven't already matched.
761 "invalid state - already matched, attempting to match again")
763 # If we don't have any content yet, we don't match.
764 if len(accumulated_output) < 1:
768 if self._regex_mode == "match":
769 match = self._regex.match(accumulated_output)
770 elif self._regex_mode == "search":
771 match = self._regex.search(accumulated_output)
774 "Unexpected regex mode: {}".format(
777 # If we don't match, wait to try again after next $O content, or time
780 # print("re pattern \"{}\" did not match against \"{}\"".format(self._regex.pattern, accumulated_output))
785 # print("re pattern \"{}\" matched against \"{}\"".format(self._regex.pattern, accumulated_output))
787 # Collect up any captures into the context.
790 for group_index, var_name in list(self._capture.items()):
791 capture_text = match.group(group_index)
794 "No content for group index {}".format(group_index))
795 context[var_name] = capture_text
800 class GdbRemoteTestSequence(object):
802 _LOG_LINE_REGEX = re.compile(r'^.*(read|send)\s+packet:\s+(.+)$')
804 def __init__(self, logger):
808 def add_log_lines(self, log_lines, remote_input_is_read):
809 for line in log_lines:
810 if isinstance(line, str):
811 # Handle log line import
813 # self.logger.debug("processing log line: {}".format(line))
814 match = self._LOG_LINE_REGEX.match(line)
816 playback_packet = match.group(2)
817 direction = match.group(1)
818 if _is_packet_lldb_gdbserver_input(
819 direction, remote_input_is_read):
820 # Handle as something to send to the remote debug monitor.
822 # self.logger.info("processed packet to send to remote: {}".format(playback_packet))
825 is_send_to_remote=True,
826 exact_payload=playback_packet))
828 # Log line represents content to be expected from the remote debug monitor.
830 # self.logger.info("receiving packet from llgs, should match: {}".format(playback_packet))
833 is_send_to_remote=False,
834 exact_payload=playback_packet))
837 "failed to interpret log line: {}".format(line))
838 elif isinstance(line, dict):
839 entry_type = line.get("type", "regex_capture")
840 if entry_type == "regex_capture":
841 # Handle more explicit control over details via dictionary.
842 direction = line.get("direction", None)
843 regex = line.get("regex", None)
844 capture = line.get("capture", None)
845 expect_captures = line.get("expect_captures", None)
848 if regex and (isinstance(regex, str)):
849 regex = re.compile(regex)
851 if _is_packet_lldb_gdbserver_input(
852 direction, remote_input_is_read):
853 # Handle as something to send to the remote debug monitor.
855 # self.logger.info("processed dict sequence to send to remote")
858 is_send_to_remote=True,
861 expect_captures=expect_captures))
863 # Log line represents content to be expected from the remote debug monitor.
865 # self.logger.info("processed dict sequence to match receiving from remote")
868 is_send_to_remote=False,
871 expect_captures=expect_captures))
872 elif entry_type == "multi_response":
873 self.entries.append(MultiResponseGdbRemoteEntry(line))
874 elif entry_type == "output_match":
876 regex = line.get("regex", None)
878 if regex and (isinstance(regex, str)):
879 regex = re.compile(regex, re.DOTALL)
881 regex_mode = line.get("regex_mode", "match")
882 capture = line.get("capture", None)
884 MatchRemoteOutputEntry(
886 regex_mode=regex_mode,
889 raise Exception("unknown entry type \"%s\"" % entry_type)
892 def process_is_running(pid, unknown_value=True):
893 """If possible, validate that the given pid represents a running process on the local system.
897 pid: an OS-specific representation of a process id. Should be an integral value.
899 unknown_value: value used when we cannot determine how to check running local
904 If we can figure out how to check running process ids on the given OS:
905 return True if the process is running, or False otherwise.
907 If we don't know how to check running process ids on the given OS:
908 return the value provided by the unknown_value arg.
910 if not isinstance(pid, six.integer_types):
912 "pid must be an integral type (actual type: %s)" % str(
917 if lldb.remote_platform:
918 # Don't know how to get list of running process IDs on a remote
921 elif platform.system() in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']:
922 # Build the list of running process ids
923 output = subprocess.check_output(
924 "ps ax | awk '{ print $1; }'", shell=True)
925 text_process_ids = output.split('\n')[1:]
926 # Convert text pids to ints
927 process_ids = [int(text_pid)
928 for text_pid in text_process_ids if text_pid != '']
929 # elif {your_platform_here}:
930 # fill in process_ids as a list of int type process IDs running on
933 # Don't know how to get list of running process IDs on this
934 # OS, so return the "don't know" value.
937 # Check if the pid is in the process_ids
938 return pid in process_ids
940 if __name__ == '__main__':
941 EXE_PATH = get_lldb_server_exe()
943 print("lldb-server path detected: {}".format(EXE_PATH))
945 print("lldb-server could not be found")