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