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 = value.encode("hex")
391        if byte_size:
392            # Add zero-fill to the left/front (MSB side) of the value.
393            retval = ("00" * (byte_size - len(retval)/2)) + retval
394        return retval
395
396    else:
397        # pdp is valid but need to add parse code once needed.
398        raise Exception("unsupported endian:{}".format(endian))
399
400class GdbRemoteEntryBase(object):
401    def is_output_matcher(self):
402        return False
403
404class GdbRemoteEntry(GdbRemoteEntryBase):
405
406    def __init__(self, is_send_to_remote=True, exact_payload=None, regex=None, capture=None, expect_captures=None):
407        """Create an entry representing one piece of the I/O to/from a gdb remote debug monitor.
408
409        Args:
410
411            is_send_to_remote: True if this entry is a message to be
412                sent to the gdbremote debug monitor; False if this
413                entry represents text to be matched against the reply
414                from the gdbremote debug monitor.
415
416            exact_payload: if not None, then this packet is an exact
417                send (when sending to the remote) or an exact match of
418                the response from the gdbremote. The checksums are
419                ignored on exact match requests since negotiation of
420                no-ack makes the checksum content essentially
421                undefined.
422
423            regex: currently only valid for receives from gdbremote.
424                When specified (and only if exact_payload is None),
425                indicates the gdbremote response must match the given
426                regex. Match groups in the regex can be used for two
427                different purposes: saving the match (see capture
428                arg), or validating that a match group matches a
429                previously established value (see expect_captures). It
430                is perfectly valid to have just a regex arg and to
431                specify neither capture or expect_captures args. This
432                arg only makes sense if exact_payload is not
433                specified.
434
435            capture: if specified, is a dictionary of regex match
436                group indices (should start with 1) to variable names
437                that will store the capture group indicated by the
438                index. For example, {1:"thread_id"} will store capture
439                group 1's content in the context dictionary where
440                "thread_id" is the key and the match group value is
441                the value. The value stored off can be used later in a
442                expect_captures expression. This arg only makes sense
443                when regex is specified.
444
445            expect_captures: if specified, is a dictionary of regex
446                match group indices (should start with 1) to variable
447                names, where the match group should match the value
448                existing in the context at the given variable name.
449                For example, {2:"thread_id"} indicates that the second
450                match group must match the value stored under the
451                context's previously stored "thread_id" key. This arg
452                only makes sense when regex is specified.
453        """
454        self._is_send_to_remote = is_send_to_remote
455        self.exact_payload = exact_payload
456        self.regex = regex
457        self.capture = capture
458        self.expect_captures = expect_captures
459
460    def is_send_to_remote(self):
461        return self._is_send_to_remote
462
463    def is_consumed(self):
464        # For now, all packets are consumed after first use.
465        return True
466
467    def get_send_packet(self):
468        if not self.is_send_to_remote():
469            raise Exception("get_send_packet() called on GdbRemoteEntry that is not a send-to-remote packet")
470        if not self.exact_payload:
471            raise Exception("get_send_packet() called on GdbRemoteEntry but it doesn't have an exact payload")
472        return self.exact_payload
473
474    def _assert_exact_payload_match(self, asserter, actual_packet):
475        assert_packets_equal(asserter, actual_packet, self.exact_payload)
476        return None
477
478    def _assert_regex_match(self, asserter, actual_packet, context):
479        # Ensure the actual packet matches from the start of the actual packet.
480        match = self.regex.match(actual_packet)
481        if not match:
482            asserter.fail("regex '{}' failed to match against content '{}'".format(self.regex.pattern, actual_packet))
483
484        if self.capture:
485            # Handle captures.
486            for group_index, var_name in list(self.capture.items()):
487                capture_text = match.group(group_index)
488                # It is okay for capture text to be None - which it will be if it is a group that can match nothing.
489                # The user must be okay with it since the regex itself matched above.
490                context[var_name] = capture_text
491
492        if self.expect_captures:
493            # Handle comparing matched groups to context dictionary entries.
494            for group_index, var_name in list(self.expect_captures.items()):
495                capture_text = match.group(group_index)
496                if not capture_text:
497                    raise Exception("No content to expect for group index {}".format(group_index))
498                asserter.assertEqual(capture_text, context[var_name])
499
500        return context
501
502    def assert_match(self, asserter, actual_packet, context=None):
503        # This only makes sense for matching lines coming from the
504        # remote debug monitor.
505        if self.is_send_to_remote():
506            raise Exception("Attempted to match a packet being sent to the remote debug monitor, doesn't make sense.")
507
508        # Create a new context if needed.
509        if not context:
510            context = {}
511
512        # If this is an exact payload, ensure they match exactly,
513        # ignoring the packet checksum which is optional for no-ack
514        # mode.
515        if self.exact_payload:
516            self._assert_exact_payload_match(asserter, actual_packet)
517            return context
518        elif self.regex:
519            return self._assert_regex_match(asserter, actual_packet, context)
520        else:
521            raise Exception("Don't know how to match a remote-sent packet when exact_payload isn't specified.")
522
523class MultiResponseGdbRemoteEntry(GdbRemoteEntryBase):
524    """Represents a query/response style packet.
525
526    Assumes the first item is sent to the gdb remote.
527    An end sequence regex indicates the end of the query/response
528    packet sequence.  All responses up through (but not including) the
529    end response are stored in a context variable.
530
531    Settings accepted from params:
532
533        next_query or query: required.  The typical query packet without the $ prefix or #xx suffix.
534            If there is a special first packet to start the iteration query, see the
535            first_query key.
536
537        first_query: optional. If the first query requires a special query command, specify
538            it with this key.  Do not specify the $ prefix or #xx suffix.
539
540        append_iteration_suffix: defaults to False.  Specify True if the 0-based iteration
541            index should be appended as a suffix to the command.  e.g. qRegisterInfo with
542            this key set true will generate query packets of qRegisterInfo0, qRegisterInfo1,
543            etc.
544
545        end_regex: required. Specifies a compiled regex object that will match the full text
546            of any response that signals an end to the iteration.  It must include the
547            initial $ and ending #xx and must match the whole packet.
548
549        save_key: required.  Specifies the key within the context where an array will be stored.
550            Each packet received from the gdb remote that does not match the end_regex will get
551            appended to the array stored within the context at that key.
552
553        runaway_response_count: optional. Defaults to 10000. If this many responses are retrieved,
554            assume there is something wrong with either the response collection or the ending
555            detection regex and throw an exception.
556    """
557    def __init__(self, params):
558        self._next_query = params.get("next_query", params.get("query"))
559        if not self._next_query:
560            raise "either next_query or query key must be specified for MultiResponseGdbRemoteEntry"
561
562        self._first_query = params.get("first_query", self._next_query)
563        self._append_iteration_suffix = params.get("append_iteration_suffix", False)
564        self._iteration = 0
565        self._end_regex = params["end_regex"]
566        self._save_key = params["save_key"]
567        self._runaway_response_count = params.get("runaway_response_count", 10000)
568        self._is_send_to_remote = True
569        self._end_matched = False
570
571    def is_send_to_remote(self):
572        return self._is_send_to_remote
573
574    def get_send_packet(self):
575        if not self.is_send_to_remote():
576            raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry that is not in the send state")
577        if self._end_matched:
578            raise Exception("get_send_packet() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
579
580        # Choose the first or next query for the base payload.
581        if self._iteration == 0 and self._first_query:
582            payload = self._first_query
583        else:
584            payload = self._next_query
585
586        # Append the suffix as needed.
587        if self._append_iteration_suffix:
588            payload += "%x" % self._iteration
589
590        # Keep track of the iteration.
591        self._iteration += 1
592
593        # Now that we've given the query packet, flip the mode to receive/match.
594        self._is_send_to_remote = False
595
596        # Return the result, converted to packet form.
597        return gdbremote_packet_encode_string(payload)
598
599    def is_consumed(self):
600        return self._end_matched
601
602    def assert_match(self, asserter, actual_packet, context=None):
603        # This only makes sense for matching lines coming from the remote debug monitor.
604        if self.is_send_to_remote():
605            raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but state is set to send a query packet.")
606
607        if self._end_matched:
608            raise Exception("assert_match() called on MultiResponseGdbRemoteEntry but end of query/response sequence has already been seen.")
609
610        # Set up a context as needed.
611        if not context:
612            context = {}
613
614        # Check if the packet matches the end condition.
615        match = self._end_regex.match(actual_packet)
616        if match:
617            # We're done iterating.
618            self._end_matched = True
619            return context
620
621        # Not done iterating - save the packet.
622        context[self._save_key] = context.get(self._save_key, [])
623        context[self._save_key].append(actual_packet)
624
625        # Check for a runaway response cycle.
626        if len(context[self._save_key]) >= self._runaway_response_count:
627            raise Exception("runaway query/response cycle detected: %d responses captured so far. Last response: %s" %
628                (len(context[self._save_key]), context[self._save_key][-1]))
629
630        # Flip the mode to send for generating the query.
631        self._is_send_to_remote = True
632        return context
633
634class MatchRemoteOutputEntry(GdbRemoteEntryBase):
635    """Waits for output from the debug monitor to match a regex or time out.
636
637    This entry type tries to match each time new gdb remote output is accumulated
638    using a provided regex.  If the output does not match the regex within the
639    given timeframe, the command fails the playback session.  If the regex does
640    match, any capture fields are recorded in the context.
641
642    Settings accepted from params:
643
644        regex: required. Specifies a compiled regex object that must either succeed
645            with re.match or re.search (see regex_mode below) within the given timeout
646            (see timeout_seconds below) or cause the playback to fail.
647
648        regex_mode: optional. Available values: "match" or "search". If "match", the entire
649            stub output as collected so far must match the regex.  If search, then the regex
650            must match starting somewhere within the output text accumulated thus far.
651            Default: "match" (i.e. the regex must match the entirety of the accumulated output
652            buffer, so unexpected text will generally fail the match).
653
654        capture: optional.  If specified, is a dictionary of regex match group indices (should start
655            with 1) to variable names that will store the capture group indicated by the
656            index. For example, {1:"thread_id"} will store capture group 1's content in the
657            context dictionary where "thread_id" is the key and the match group value is
658            the value. The value stored off can be used later in a expect_captures expression.
659            This arg only makes sense when regex is specified.
660    """
661    def __init__(self, regex=None, regex_mode="match", capture=None):
662        self._regex = regex
663        self._regex_mode = regex_mode
664        self._capture = capture
665        self._matched = False
666
667        if not self._regex:
668            raise Exception("regex cannot be None")
669
670        if not self._regex_mode in ["match", "search"]:
671            raise Exception("unsupported regex mode \"{}\": must be \"match\" or \"search\"".format(self._regex_mode))
672
673    def is_output_matcher(self):
674        return True
675
676    def is_send_to_remote(self):
677        # This is always a "wait for remote" command.
678        return False
679
680    def is_consumed(self):
681        return self._matched
682
683    def assert_match(self, asserter, accumulated_output, context):
684        # Validate args.
685        if not accumulated_output:
686            raise Exception("accumulated_output cannot be none")
687        if not context:
688            raise Exception("context cannot be none")
689
690        # Validate that we haven't already matched.
691        if self._matched:
692            raise Exception("invalid state - already matched, attempting to match again")
693
694        # If we don't have any content yet, we don't match.
695        if len(accumulated_output) < 1:
696            return context
697
698        # Check if we match
699        if self._regex_mode == "match":
700            match = self._regex.match(accumulated_output)
701        elif self._regex_mode == "search":
702            match = self._regex.search(accumulated_output)
703        else:
704            raise Exception("Unexpected regex mode: {}".format(self._regex_mode))
705
706        # If we don't match, wait to try again after next $O content, or time out.
707        if not match:
708            # print("re pattern \"{}\" did not match against \"{}\"".format(self._regex.pattern, accumulated_output))
709            return context
710
711        # We do match.
712        self._matched = True
713        # print("re pattern \"{}\" matched against \"{}\"".format(self._regex.pattern, accumulated_output))
714
715        # Collect up any captures into the context.
716        if self._capture:
717            # Handle captures.
718            for group_index, var_name in list(self._capture.items()):
719                capture_text = match.group(group_index)
720                if not capture_text:
721                    raise Exception("No content for group index {}".format(group_index))
722                context[var_name] = capture_text
723
724        return context
725
726
727class GdbRemoteTestSequence(object):
728
729    _LOG_LINE_REGEX = re.compile(r'^.*(read|send)\s+packet:\s+(.+)$')
730
731    def __init__(self, logger):
732        self.entries = []
733        self.logger = logger
734
735    def add_log_lines(self, log_lines, remote_input_is_read):
736        for line in log_lines:
737            if type(line) == str:
738                # Handle log line import
739                # if self.logger:
740                #     self.logger.debug("processing log line: {}".format(line))
741                match = self._LOG_LINE_REGEX.match(line)
742                if match:
743                    playback_packet = match.group(2)
744                    direction = match.group(1)
745                    if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read):
746                        # Handle as something to send to the remote debug monitor.
747                        # if self.logger:
748                        #     self.logger.info("processed packet to send to remote: {}".format(playback_packet))
749                        self.entries.append(GdbRemoteEntry(is_send_to_remote=True, exact_payload=playback_packet))
750                    else:
751                        # Log line represents content to be expected from the remote debug monitor.
752                        # if self.logger:
753                        #     self.logger.info("receiving packet from llgs, should match: {}".format(playback_packet))
754                        self.entries.append(GdbRemoteEntry(is_send_to_remote=False,exact_payload=playback_packet))
755                else:
756                    raise Exception("failed to interpret log line: {}".format(line))
757            elif type(line) == dict:
758                entry_type = line.get("type", "regex_capture")
759                if entry_type == "regex_capture":
760                    # Handle more explicit control over details via dictionary.
761                    direction = line.get("direction", None)
762                    regex = line.get("regex", None)
763                    capture = line.get("capture", None)
764                    expect_captures = line.get("expect_captures", None)
765
766                    # Compile the regex.
767                    if regex and (type(regex) == str):
768                        regex = re.compile(regex)
769
770                    if _is_packet_lldb_gdbserver_input(direction, remote_input_is_read):
771                        # Handle as something to send to the remote debug monitor.
772                        # if self.logger:
773                        #     self.logger.info("processed dict sequence to send to remote")
774                        self.entries.append(GdbRemoteEntry(is_send_to_remote=True, regex=regex, capture=capture, expect_captures=expect_captures))
775                    else:
776                        # Log line represents content to be expected from the remote debug monitor.
777                        # if self.logger:
778                        #     self.logger.info("processed dict sequence to match receiving from remote")
779                        self.entries.append(GdbRemoteEntry(is_send_to_remote=False, regex=regex, capture=capture, expect_captures=expect_captures))
780                elif entry_type == "multi_response":
781                    self.entries.append(MultiResponseGdbRemoteEntry(line))
782                elif entry_type == "output_match":
783
784                    regex = line.get("regex", None)
785                    # Compile the regex.
786                    if regex and (type(regex) == str):
787                        regex = re.compile(regex)
788
789                    regex_mode = line.get("regex_mode", "match")
790                    capture = line.get("capture", None)
791                    self.entries.append(MatchRemoteOutputEntry(regex=regex, regex_mode=regex_mode, capture=capture))
792                else:
793                    raise Exception("unknown entry type \"%s\"" % entry_type)
794
795def process_is_running(pid, unknown_value=True):
796    """If possible, validate that the given pid represents a running process on the local system.
797
798    Args:
799
800        pid: an OS-specific representation of a process id.  Should be an integral value.
801
802        unknown_value: value used when we cannot determine how to check running local
803        processes on the OS.
804
805    Returns:
806
807        If we can figure out how to check running process ids on the given OS:
808        return True if the process is running, or False otherwise.
809
810        If we don't know how to check running process ids on the given OS:
811        return the value provided by the unknown_value arg.
812    """
813    if not isinstance(pid, six.integer_types):
814        raise Exception("pid must be an integral type (actual type: %s)" % str(type(pid)))
815
816    process_ids = []
817
818    if lldb.remote_platform:
819        # Don't know how to get list of running process IDs on a remote
820        # platform
821        return unknown_value
822    elif platform.system() in ['Darwin', 'Linux', 'FreeBSD', 'NetBSD']:
823        # Build the list of running process ids
824        output = subprocess.check_output("ps ax | awk '{ print $1; }'", shell=True)
825        text_process_ids = output.split('\n')[1:]
826        # Convert text pids to ints
827        process_ids = [int(text_pid) for text_pid in text_process_ids if text_pid != '']
828    # elif {your_platform_here}:
829    #   fill in process_ids as a list of int type process IDs running on
830    #   the local system.
831    else:
832        # Don't know how to get list of running process IDs on this
833        # OS, so return the "don't know" value.
834        return unknown_value
835
836    # Check if the pid is in the process_ids
837    return pid in process_ids
838
839if __name__ == '__main__':
840    EXE_PATH = get_lldb_server_exe()
841    if EXE_PATH:
842        print("lldb-server path detected: {}".format(EXE_PATH))
843    else:
844        print("lldb-server could not be found")
845