]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
Vendor import of lldb trunk r256945:
[FreeBSD/FreeBSD.git] / packages / Python / lldbsuite / test / tools / lldb-server / lldbgdbserverutils.py
1 """Module for supporting unit testing of the lldb-server debug monitor exe.
2 """
3
4 from __future__ import print_function
5
6
7
8 import os
9 import os.path
10 import platform
11 import re
12 import six
13 import socket_packet_pump
14 import subprocess
15 import time
16 from lldbsuite.test.lldbtest import *
17
18 from six.moves import queue
19
20 def _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
66 def 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
78 def 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
94 def _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
122 def 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
145 def 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
153 def 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
256 def gdbremote_hex_encode_string(str):
257     output = ''
258     for c in str:
259         output += '{0:02x}'.format(ord(c))
260     return output
261
262 def gdbremote_hex_decode_string(str):
263     return str.decode("hex")
264
265 def 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
271 def 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
296 def 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
315 def 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
326 def 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
351 def 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
372 def 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
399 class GdbRemoteEntryBase(object):
400     def is_output_matcher(self):
401         return False
402
403 class 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
522 class 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
633 class 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
726 class 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
794 def 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
838 if __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")