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