aboutsummaryrefslogtreecommitdiff
path: root/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py')
-rw-r--r--packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py248
1 files changed, 173 insertions, 75 deletions
diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py b/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
index 0c73bed9ea0a..c89cd301899a 100644
--- a/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
+++ b/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
@@ -4,7 +4,6 @@
from __future__ import print_function
-
import os
import os.path
import platform
@@ -17,6 +16,7 @@ from lldbsuite.test.lldbtest import *
from six.moves import queue
+
def _get_debug_monitor_from_lldb(lldb_exe, debug_monitor_basename):
"""Return the debug monitor exe path given the lldb exe path.
@@ -55,7 +55,10 @@ def _get_debug_monitor_from_lldb(lldb_exe, debug_monitor_basename):
if os.path.exists(debug_monitor_exe):
return debug_monitor_exe
- new_base = regex.sub( 'LLDB.framework/Versions/A/Resources/' + debug_monitor_basename, exe_base)
+ new_base = regex.sub(
+ 'LLDB.framework/Versions/A/Resources/' +
+ debug_monitor_basename,
+ exe_base)
debug_monitor_exe = os.path.join(exe_dir, new_base)
if os.path.exists(debug_monitor_exe):
return debug_monitor_exe
@@ -73,7 +76,9 @@ def get_lldb_server_exe():
if "LLDB_DEBUGSERVER_PATH" in os.environ:
return os.environ["LLDB_DEBUGSERVER_PATH"]
- return _get_debug_monitor_from_lldb(lldbtest_config.lldbExec, "lldb-server")
+ return _get_debug_monitor_from_lldb(
+ lldbtest_config.lldbExec, "lldb-server")
+
def get_debugserver_exe():
"""Return the debugserver exe path.
@@ -85,10 +90,11 @@ def get_debugserver_exe():
if "LLDB_DEBUGSERVER_PATH" in os.environ:
return os.environ["LLDB_DEBUGSERVER_PATH"]
- return _get_debug_monitor_from_lldb(lldbtest_config.lldbExec, "debugserver")
+ return _get_debug_monitor_from_lldb(
+ lldbtest_config.lldbExec, "debugserver")
_LOG_LINE_REGEX = re.compile(r'^(lldb-server|debugserver)\s+<\s*(\d+)>' +
- '\s+(read|send)\s+packet:\s+(.+)$')
+ '\s+(read|send)\s+packet:\s+(.+)$')
def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read):
@@ -131,10 +137,12 @@ def handle_O_packet(context, packet_contents, logger):
new_text = gdbremote_hex_decode_string(packet_contents[1:])
context["O_content"] += new_text
context["O_count"] += 1
-
+
if logger:
- logger.debug("text: new \"{}\", cumulative: \"{}\"".format(new_text, context["O_content"]))
-
+ logger.debug(
+ "text: new \"{}\", cumulative: \"{}\"".format(
+ new_text, context["O_content"]))
+
return True
_STRIP_CHECKSUM_REGEX = re.compile(r'#[0-9a-fA-F]{2}$')
@@ -150,13 +158,14 @@ def assert_packets_equal(asserter, actual_packet, expected_packet):
expected_stripped = _STRIP_CHECKSUM_REGEX.sub('', expected_packet)
asserter.assertEqual(actual_stripped, expected_stripped)
+
def expect_lldb_gdbserver_replay(
- asserter,
- sock,
- test_sequence,
- pump_queues,
- timeout_seconds,
- logger=None):
+ asserter,
+ sock,
+ test_sequence,
+ pump_queues,
+ timeout_seconds,
+ logger=None):
"""Replay socket communication with lldb-gdbserver and verify responses.
Args:
@@ -188,16 +197,16 @@ def expect_lldb_gdbserver_replay(
context["O_count"] will contain an integer of the number of
O packets received.
"""
-
+
# Ensure we have some work to do.
if len(test_sequence.entries) < 1:
return {}
- context = {"O_count":0, "O_content":""}
+ context = {"O_count": 0, "O_content": ""}
with socket_packet_pump.SocketPacketPump(sock, pump_queues, logger) as pump:
# Grab the first sequence entry.
sequence_entry = test_sequence.entries.pop(0)
-
+
# While we have an active sequence entry, send messages
# destined for the stub and collect/match/process responses
# expected from the stub.
@@ -210,10 +219,12 @@ def expect_lldb_gdbserver_replay(
packet_desc = "^C"
else:
packet_desc = send_packet
- logger.info("sending packet to remote: {}".format(packet_desc))
+ logger.info(
+ "sending packet to remote: {}".format(packet_desc))
sock.sendall(send_packet)
else:
- # This is an entry expecting to receive content from the remote debug monitor.
+ # This is an entry expecting to receive content from the remote
+ # debug monitor.
# We'll pull from (and wait on) the queue appropriate for the type of matcher.
# We keep separate queues for process output (coming from non-deterministic
@@ -224,51 +235,65 @@ def expect_lldb_gdbserver_replay(
content = pump_queues.output_queue().get(True, timeout_seconds)
except queue.Empty:
if logger:
- logger.warning("timeout waiting for stub output (accumulated output:{})".format(pump.get_accumulated_output()))
- raise Exception("timed out while waiting for output match (accumulated output: {})".format(pump.get_accumulated_output()))
+ logger.warning(
+ "timeout waiting for stub output (accumulated output:{})".format(
+ pump.get_accumulated_output()))
+ raise Exception(
+ "timed out while waiting for output match (accumulated output: {})".format(
+ pump.get_accumulated_output()))
else:
try:
content = pump_queues.packet_queue().get(True, timeout_seconds)
except queue.Empty:
if logger:
- logger.warning("timeout waiting for packet match (receive buffer: {})".format(pump.get_receive_buffer()))
- raise Exception("timed out while waiting for packet match (receive buffer: {})".format(pump.get_receive_buffer()))
-
+ logger.warning(
+ "timeout waiting for packet match (receive buffer: {})".format(
+ pump.get_receive_buffer()))
+ raise Exception(
+ "timed out while waiting for packet match (receive buffer: {})".format(
+ pump.get_receive_buffer()))
+
# Give the sequence entry the opportunity to match the content.
# Output matchers might match or pass after more output accumulates.
# Other packet types generally must match.
asserter.assertIsNotNone(content)
- context = sequence_entry.assert_match(asserter, content, context=context)
+ context = sequence_entry.assert_match(
+ asserter, content, context=context)
# Move on to next sequence entry as needed. Some sequence entries support executing multiple
- # times in different states (for looping over query/response packets).
+ # times in different states (for looping over query/response
+ # packets).
if sequence_entry.is_consumed():
if len(test_sequence.entries) > 0:
sequence_entry = test_sequence.entries.pop(0)
else:
sequence_entry = None
-
+
# Fill in the O_content entries.
context["O_count"] = 1
context["O_content"] = pump.get_accumulated_output()
-
+
return context
+
def gdbremote_hex_encode_string(str):
output = ''
for c in str:
output += '{0:02x}'.format(ord(c))
return output
+
def gdbremote_hex_decode_string(str):
return str.decode("hex")
+
def gdbremote_packet_encode_string(str):
checksum = 0
for c in str:
checksum += ord(c)
return '$' + str + '#{0:02x}'.format(checksum % 256)
+
def build_gdbremote_A_packet(args_list):
"""Given a list of args, create a properly-formed $A packet containing each arg.
"""
@@ -322,7 +347,9 @@ def parse_threadinfo_response(response_packet):
response_packet = _STRIP_CHECKSUM_REGEX.sub("", response_packet)
# Return list of thread ids
- return [int(thread_id_hex,16) for thread_id_hex in response_packet.split(",") if len(thread_id_hex) > 0]
+ return [int(thread_id_hex, 16) for thread_id_hex in response_packet.split(
+ ",") if len(thread_id_hex) > 0]
+
def unpack_endian_binary_string(endian, value_string):
"""Unpack a gdb-remote binary (post-unescaped, i.e. not escaped) response to an unsigned int given endianness of the inferior."""
@@ -349,6 +376,7 @@ def unpack_endian_binary_string(endian, value_string):
# pdp is valid but need to add parse code once needed.
raise Exception("unsupported endian:{}".format(endian))
+
def unpack_register_hex_unsigned(endian, value_string):
"""Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior."""
if not endian:
@@ -370,6 +398,7 @@ def unpack_register_hex_unsigned(endian, value_string):
# pdp is valid but need to add parse code once needed.
raise Exception("unsupported endian:{}".format(endian))
+
def pack_register_hex(endian, value, byte_size=None):
"""Unpack a gdb-remote $p-style response to an unsigned int given endianness of inferior."""
if not endian:
@@ -383,7 +412,7 @@ def pack_register_hex(endian, value, byte_size=None):
value = value >> 8
if byte_size:
# Add zero-fill to the right/end (MSB side) of the value.
- retval += "00" * (byte_size - len(retval)/2)
+ retval += "00" * (byte_size - len(retval) / 2)
return retval
elif endian == 'big':
@@ -393,20 +422,29 @@ def pack_register_hex(endian, value, byte_size=None):
value = value >> 8
if byte_size:
# Add zero-fill to the left/front (MSB side) of the value.
- retval = ("00" * (byte_size - len(retval)/2)) + retval
+ retval = ("00" * (byte_size - len(retval) / 2)) + retval
return retval
else:
# pdp is valid but need to add parse code once needed.
raise Exception("unsupported endian:{}".format(endian))
+
class GdbRemoteEntryBase(object):
+
def is_output_matcher(self):
return False
+
class GdbRemoteEntry(GdbRemoteEntryBase):
- def __init__(self, is_send_to_remote=True, exact_payload=None, regex=None, capture=None, expect_captures=None):
+ def __init__(
+ self,
+ is_send_to_remote=True,
+ exact_payload=None,
+ regex=None,
+ capture=None,
+ expect_captures=None):
"""Create an entry representing one piece of the I/O to/from a gdb remote debug monitor.
Args:
@@ -469,9 +507,11 @@ class GdbRemoteEntry(GdbRemoteEntryBase):
def get_send_packet(self):
if not self.is_send_to_remote():
- raise Exception("get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet")
+ raise Exception(
+ "get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet")
if not self.exact_payload:
- raise Exception("get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload")
+ raise Exception(
+ "get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload")
return self.exact_payload
def _assert_exact_payload_match(self, asserter, actual_packet):
@@ -482,14 +522,17 @@ class GdbRemoteEntry(GdbRemoteEntryBase):
# Ensure the actual packet matches from the start of the actual packet.
match = self.regex.match(actual_packet)
if not match:
- asserter.fail("regex '{}' failed to match against content '{}'".format(self.regex.pattern, actual_packet))
+ asserter.fail(
+ "regex '{}' failed to match against content '{}'".format(
+ self.regex.pattern, actual_packet))
if self.capture:
# Handle captures.
for group_index, var_name in list(self.capture.items()):
capture_text = match.group(group_index)
# It is okay for capture text to be None - which it will be if it is a group that can match nothing.
- # The user must be okay with it since the regex itself matched above.
+ # The user must be okay with it since the regex itself matched
+ # above.
context[var_name] = capture_text
if self.expect_captures:
@@ -497,7 +540,8 @@ class GdbRemoteEntry(GdbRemoteEntryBase):
for group_index, var_name in list(self.expect_captures.items()):
capture_text = match.group(group_index)
if not capture_text:
- raise Exception("No content to expect for group index {}".format(group_index))
+ raise Exception(
+ "No content to expect for group index {}".format(group_index))
asserter.assertEqual(capture_text, context[var_name])
return context
@@ -506,7 +550,8 @@ class GdbRemoteEntry(GdbRemoteEntryBase):
# This only makes sense for matching lines coming from the
# remote debug monitor.
if self.is_send_to_remote():
- raise Exception("Attempted to match a packet being sent to the remote debug monitor, doesn't make sense.")
+ raise Exception(
+ "Attempted to match a packet being sent to the remote debug monitor, doesn't make sense.")
# Create a new context if needed.
if not context:
@@ -521,16 +566,18 @@ class GdbRemoteEntry(GdbRemoteEntryBase):
elif self.regex:
return self._assert_regex_match(asserter, actual_packet, context)
else:
- raise Exception("Don't know how to match a remote-sent packet when exact_payload isn't specified.")
+ raise Exception(
+ "Don't know how to match a remote-sent packet when exact_payload isn't specified.")
+
class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
"""Represents a query/response style packet.
-
+
Assumes the first item is sent to the gdb remote.
An end sequence regex indicates the end of the query/response
packet sequence. All responses up through (but not including) the
end response are stored in a context variable.
-
+
Settings accepted from params:
next_query or query: required. The typical query packet without the $ prefix or #xx suffix.
@@ -557,17 +604,20 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
assume there is something wrong with either the response collection or the ending
detection regex and throw an exception.
"""
+
def __init__(self, params):
self._next_query = params.get("next_query", params.get("query"))
if not self._next_query:
raise "either next_query or query key must be specified for MultiResponseGdbRemoteEntry"
-
+
self._first_query = params.get("first_query", self._next_query)
- self._append_iteration_suffix = params.get("append_iteration_suffix", False)
+ self._append_iteration_suffix = params.get(
+ "append_iteration_suffix", False)
self._iteration = 0
self._end_regex = params["end_regex"]
self._save_key = params["save_key"]
- self._runaway_response_count = params.get("runaway_response_count", 10000)
+ self._runaway_response_count = params.get(
+ "runaway_response_count", 10000)
self._is_send_to_remote = True
self._end_matched = False
@@ -576,9 +626,11 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
def get_send_packet(self):
if not self.is_send_to_remote():
- raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state")
+ raise Exception(
+ "get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state")
if self._end_matched:
- raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
+ raise Exception(
+ "get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
# Choose the first or next query for the base payload.
if self._iteration == 0 and self._first_query:
@@ -593,7 +645,8 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
# Keep track of the iteration.
self._iteration += 1
- # Now that we've given the query packet, flip the mode to receive/match.
+ # Now that we've given the query packet, flip the mode to
+ # receive/match.
self._is_send_to_remote = False
# Return the result, converted to packet form.
@@ -603,12 +656,15 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
return self._end_matched
def assert_match(self, asserter, actual_packet, context=None):
- # This only makes sense for matching lines coming from the remote debug monitor.
+ # This only makes sense for matching lines coming from the remote debug
+ # monitor.
if self.is_send_to_remote():
- raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet.")
+ raise Exception(
+ "assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet.")
if self._end_matched:
- raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
+ raise Exception(
+ "assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
# Set up a context as needed.
if not context:
@@ -627,21 +683,27 @@ class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
# Check for a runaway response cycle.
if len(context[self._save_key]) >= self._runaway_response_count:
- raise Exception("runaway query/response cycle detected: %d responses captured so far. Last response: %s" %
- (len(context[self._save_key]), context[self._save_key][-1]))
+ raise Exception(
+ "runaway query/response cycle detected: %d responses captured so far. Last response: %s" %
+ (len(
+ context[
+ self._save_key]), context[
+ self._save_key][
+ -1]))
# Flip the mode to send for generating the query.
self._is_send_to_remote = True
return context
+
class MatchRemoteOutputEntry(GdbRemoteEntryBase):
"""Waits for output from the debug monitor to match a regex or time out.
-
+
This entry type tries to match each time new gdb remote output is accumulated
using a provided regex. If the output does not match the regex within the
given timeframe, the command fails the playback session. If the regex does
match, any capture fields are recorded in the context.
-
+
Settings accepted from params:
regex: required. Specifies a compiled regex object that must either succeed
@@ -653,7 +715,7 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase):
must match starting somewhere within the output text accumulated thus far.
Default: "match" (i.e. the regex must match the entirety of the accumulated output
buffer, so unexpected text will generally fail the match).
-
+
capture: optional. If specified, is a dictionary of regex match group indices (should start
with 1) to variable names that will store the capture group indicated by the
index. For example, {1:"thread_id"} will store capture group 1's content in the
@@ -661,6 +723,7 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase):
the value. The value stored off can be used later in a expect_captures expression.
This arg only makes sense when regex is specified.
"""
+
def __init__(self, regex=None, regex_mode="match", capture=None):
self._regex = regex
self._regex_mode = regex_mode
@@ -671,7 +734,9 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase):
raise Exception("regex cannot be None")
if not self._regex_mode in ["match", "search"]:
- raise Exception("unsupported regex mode \"{}\": must be \"match\" or \"search\"".format(self._regex_mode))
+ raise Exception(
+ "unsupported regex mode \"{}\": must be \"match\" or \"search\"".format(
+ self._regex_mode))
def is_output_matcher(self):
return True
@@ -692,7 +757,8 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase):
# Validate that we haven't already matched.
if self._matched:
- raise Exception("invalid state - already matched, attempting to match again")
+ raise Exception(
+ "invalid state - already matched, attempting to match again")
# If we don't have any content yet, we don't match.
if len(accumulated_output) < 1:
@@ -704,9 +770,12 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase):
elif self._regex_mode == "search":
match = self._regex.search(accumulated_output)
else:
- raise Exception("Unexpected regex mode: {}".format(self._regex_mode))
+ raise Exception(
+ "Unexpected regex mode: {}".format(
+ self._regex_mode))
- # If we don't match, wait to try again after next $O content, or time out.
+ # If we don't match, wait to try again after next $O content, or time
+ # out.
if not match:
# print("re pattern \"{}\" did not match against \"{}\"".format(self._regex.pattern, accumulated_output))
return context
@@ -721,7 +790,8 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase):
for group_index, var_name in list(self._capture.items()):
capture_text = match.group(group_index)
if not capture_text:
- raise Exception("No content for group index {}".format(group_index))
+ raise Exception(
+ "No content for group index {}".format(group_index))
context[var_name] = capture_text
return context
@@ -737,7 +807,7 @@ class GdbRemoteTestSequence(object):
def add_log_lines(self, log_lines, remote_input_is_read):
for line in log_lines:
- if type(line) == str:
+ if isinstance(line, str):
# Handle log line import
# if self.logger:
# self.logger.debug("processing log line: {}".format(line))
@@ -745,19 +815,27 @@ class GdbRemoteTestSequence(object):
if match:
playback_packet = match.group(2)
direction = match.group(1)
- if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read):
+ if _is_packet_lldb_gdbserver_input(
+ direction, remote_input_is_read):
# Handle as something to send to the remote debug monitor.
# if self.logger:
# self.logger.info("processed packet to send to remote: {}".format(playback_packet))
- self.entries.append(GdbRemoteEntry(is_send_to_remote=True, exact_payload=playback_packet))
+ self.entries.append(
+ GdbRemoteEntry(
+ is_send_to_remote=True,
+ exact_payload=playback_packet))
else:
# Log line represents content to be expected from the remote debug monitor.
# if self.logger:
# self.logger.info("receiving packet from llgs, should match: {}".format(playback_packet))
- self.entries.append(GdbRemoteEntry(is_send_to_remote=False,exact_payload=playback_packet))
+ self.entries.append(
+ GdbRemoteEntry(
+ is_send_to_remote=False,
+ exact_payload=playback_packet))
else:
- raise Exception("failed to interpret log line: {}".format(line))
- elif type(line) == dict:
+ raise Exception(
+ "failed to interpret log line: {}".format(line))
+ elif isinstance(line, dict):
entry_type = line.get("type", "regex_capture")
if entry_type == "regex_capture":
# Handle more explicit control over details via dictionary.
@@ -767,34 +845,50 @@ class GdbRemoteTestSequence(object):
expect_captures = line.get("expect_captures", None)
# Compile the regex.
- if regex and (type(regex) == str):
+ if regex and (isinstance(regex, str)):
regex = re.compile(regex)
- if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read):
+ if _is_packet_lldb_gdbserver_input(
+ direction, remote_input_is_read):
# Handle as something to send to the remote debug monitor.
# if self.logger:
# self.logger.info("processed dict sequence to send to remote")
- self.entries.append(GdbRemoteEntry(is_send_to_remote=True, regex=regex, capture=capture, expect_captures=expect_captures))
+ self.entries.append(
+ GdbRemoteEntry(
+ is_send_to_remote=True,
+ regex=regex,
+ capture=capture,
+ expect_captures=expect_captures))
else:
# Log line represents content to be expected from the remote debug monitor.
# if self.logger:
# self.logger.info("processed dict sequence to match receiving from remote")
- self.entries.append(GdbRemoteEntry(is_send_to_remote=False, regex=regex, capture=capture, expect_captures=expect_captures))
+ self.entries.append(
+ GdbRemoteEntry(
+ is_send_to_remote=False,
+ regex=regex,
+ capture=capture,
+ expect_captures=expect_captures))
elif entry_type == "multi_response":
self.entries.append(MultiResponseGdbRemoteEntry(line))
elif entry_type == "output_match":
regex = line.get("regex", None)
# Compile the regex.
- if regex and (type(regex) == str):
+ if regex and (isinstance(regex, str)):
regex = re.compile(regex, re.DOTALL)
regex_mode = line.get("regex_mode", "match")
capture = line.get("capture", None)
- self.entries.append(MatchRemoteOutputEntry(regex=regex, regex_mode=regex_mode, capture=capture))
+ self.entries.append(
+ MatchRemoteOutputEntry(
+ regex=regex,
+ regex_mode=regex_mode,
+ capture=capture))
else:
raise Exception("unknown entry type \"%s\"" % entry_type)
+
def process_is_running(pid, unknown_value=True):
"""If possible, validate that the given pid represents a running process on the local system.
@@ -814,7 +908,9 @@ def process_is_running(pid, unknown_value=True):
return the value provided by the unknown_value arg.
"""
if not isinstance(pid, six.integer_types):
- raise Exception("pid must be an integral type (actual type: %s)" % str(type(pid)))
+ raise Exception(
+ "pid must be an integral type (actual type: %s)" % str(
+ type(pid)))
process_ids = []
@@ -824,10 +920,12 @@ def process_is_running(pid, unknown_value=True):
return unknown_value
elif platform.system() in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']:
# Build the list of running process ids
- output = subprocess.check_output("ps ax | awk '{ print $1; }'", shell=True)
+ output = subprocess.check_output(
+ "ps ax | awk '{ print $1; }'", shell=True)
text_process_ids = output.split('\n')[1:]
# Convert text pids to ints
- process_ids = [int(text_pid) for text_pid in text_process_ids if text_pid != '']
+ process_ids = [int(text_pid)
+ for text_pid in text_process_ids if text_pid != '']
# elif {your_platform_here}:
# fill in process_ids as a list of int type process IDs running on
# the local system.