blob: fe23b5a5ea53a0260ce43e309b9262684f50b655 [file] [log] [blame]
Todd Fialae50b2e42014-06-13 19:11:33 +00001"""
2Base class for gdb-remote test cases.
3"""
4
Todd Fiala8aae4f42014-06-13 23:34:17 +00005import errno
Todd Fiala24189d42014-07-14 06:24:44 +00006import os
7import os.path
Todd Fialae50b2e42014-06-13 19:11:33 +00008import pexpect
9import platform
Todd Fiala9e2d3292014-07-09 23:10:43 +000010import random
Todd Fialae2202002014-06-27 22:11:56 +000011import re
Todd Fialae50b2e42014-06-13 19:11:33 +000012import sets
13import signal
14import socket
15import subprocess
16import sys
Todd Fiala24189d42014-07-14 06:24:44 +000017import tempfile
Todd Fialae50b2e42014-06-13 19:11:33 +000018import time
Todd Fiala24189d42014-07-14 06:24:44 +000019import unittest2
Todd Fialae50b2e42014-06-13 19:11:33 +000020from lldbtest import *
21from lldbgdbserverutils import *
22import logging
Todd Fialae50b2e42014-06-13 19:11:33 +000023
24class GdbRemoteTestCaseBase(TestBase):
25
26 mydir = TestBase.compute_mydir(__file__)
27
Todd Fialae50b2e42014-06-13 19:11:33 +000028 _TIMEOUT_SECONDS = 5
29
30 _GDBREMOTE_KILL_PACKET = "$k#6b"
31
32 _LOGGING_LEVEL = logging.WARNING
33 # _LOGGING_LEVEL = logging.DEBUG
34
35 _STARTUP_ATTACH = "attach"
36 _STARTUP_LAUNCH = "launch"
37
38 # GDB Signal numbers that are not target-specific used for common exceptions
39 TARGET_EXC_BAD_ACCESS = 0x91
40 TARGET_EXC_BAD_INSTRUCTION = 0x92
41 TARGET_EXC_ARITHMETIC = 0x93
42 TARGET_EXC_EMULATION = 0x94
43 TARGET_EXC_SOFTWARE = 0x95
44 TARGET_EXC_BREAKPOINT = 0x96
45
46 def setUp(self):
47 TestBase.setUp(self)
48 FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s'
49 logging.basicConfig(format=FORMAT)
50 self.logger = logging.getLogger(__name__)
51 self.logger.setLevel(self._LOGGING_LEVEL)
52 self.test_sequence = GdbRemoteTestSequence(self.logger)
53 self.set_inferior_startup_launch()
Todd Fiala9e2d3292014-07-09 23:10:43 +000054 self.port = self.get_next_port()
Todd Fiala67041192014-07-11 22:50:13 +000055 self.named_pipe_path = None
Todd Fiala24189d42014-07-14 06:24:44 +000056 self.named_pipe = None
57 self.named_pipe_fd = None
Todd Fialae50b2e42014-06-13 19:11:33 +000058
Todd Fiala9e2d3292014-07-09 23:10:43 +000059 def get_next_port(self):
60 return 12000 + random.randint(0,3999)
Todd Fialae50b2e42014-06-13 19:11:33 +000061
62 def reset_test_sequence(self):
63 self.test_sequence = GdbRemoteTestSequence(self.logger)
64
Todd Fiala24189d42014-07-14 06:24:44 +000065 def create_named_pipe(self):
66 # Create a temp dir and name for a pipe.
67 temp_dir = tempfile.mkdtemp()
68 named_pipe_path = os.path.join(temp_dir, "stub_port_number")
69
70 # Create the named pipe.
71 os.mkfifo(named_pipe_path)
72
73 # Open the read side of the pipe in non-blocking mode. This will return right away, ready or not.
74 named_pipe_fd = os.open(named_pipe_path, os.O_RDONLY | os.O_NONBLOCK)
75
76 # Create the file for the named pipe. Note this will follow semantics of
77 # a non-blocking read side of a named pipe, which has different semantics
78 # than a named pipe opened for read in non-blocking mode.
79 named_pipe = os.fdopen(named_pipe_fd, "r")
80 self.assertIsNotNone(named_pipe)
81
82 def shutdown_named_pipe():
83 # Close the pipe.
84 try:
85 named_pipe.close()
86 except:
87 print "failed to close named pipe"
88 None
89
90 # Delete the pipe.
91 try:
92 os.remove(named_pipe_path)
93 except:
94 print "failed to delete named pipe: {}".format(named_pipe_path)
95 None
96
97 # Delete the temp directory.
98 try:
99 os.rmdir(temp_dir)
100 except:
101 print "failed to delete temp dir: {}, directory contents: '{}'".format(temp_dir, os.listdir(temp_dir))
102 None
103
104 # Add the shutdown hook to clean up the named pipe.
105 self.addTearDownHook(shutdown_named_pipe)
106
107 # Clear the port so the stub selects a port number.
108 self.port = 0
109
110 return (named_pipe_path, named_pipe, named_pipe_fd)
111
112 def get_stub_port_from_named_socket(self, read_timeout_seconds=5):
113 # Wait for something to read with a max timeout.
114 (ready_readers, _, _) = select.select([self.named_pipe_fd], [], [], read_timeout_seconds)
115 self.assertIsNotNone(ready_readers, "write side of pipe has not written anything - stub isn't writing to pipe.")
116 self.assertNotEqual(len(ready_readers), 0, "write side of pipe has not written anything - stub isn't writing to pipe.")
117
118 # Read the port from the named pipe.
119 stub_port_raw = self.named_pipe.read()
120 self.assertIsNotNone(stub_port_raw)
121 self.assertNotEqual(len(stub_port_raw), 0, "no content to read on pipe")
122
123 # Trim null byte, convert to int.
124 stub_port_raw = stub_port_raw[:-1]
125 stub_port = int(stub_port_raw)
126 self.assertTrue(stub_port > 0)
127
128 return stub_port
129
130 def init_llgs_test(self, use_named_pipe=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000131 self.debug_monitor_exe = get_lldb_gdbserver_exe()
132 if not self.debug_monitor_exe:
133 self.skipTest("lldb_gdbserver exe not found")
Todd Fiala8aae4f42014-06-13 23:34:17 +0000134 self.debug_monitor_extra_args = " -c 'log enable -T -f process-{}.log lldb break process thread' -c 'log enable -T -f packets-{}.log gdb-remote packets'".format(self.id(), self.id(), self.id())
Todd Fiala24189d42014-07-14 06:24:44 +0000135 if use_named_pipe:
136 (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
Todd Fialae50b2e42014-06-13 19:11:33 +0000137
Todd Fiala24189d42014-07-14 06:24:44 +0000138 def init_debugserver_test(self, use_named_pipe=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000139 self.debug_monitor_exe = get_debugserver_exe()
140 if not self.debug_monitor_exe:
141 self.skipTest("debugserver exe not found")
142 self.debug_monitor_extra_args = " --log-file=/tmp/packets-{}.log --log-flags=0x800000".format(self._testMethodName)
Todd Fiala24189d42014-07-14 06:24:44 +0000143 if use_named_pipe:
144 (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
Todd Fialae50b2e42014-06-13 19:11:33 +0000145
146 def create_socket(self):
147 sock = socket.socket()
148 logger = self.logger
149
150 def shutdown_socket():
151 if sock:
152 try:
153 # send the kill packet so lldb-gdbserver shuts down gracefully
154 sock.sendall(GdbRemoteTestCaseBase._GDBREMOTE_KILL_PACKET)
155 except:
156 logger.warning("failed to send kill packet to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
157
158 try:
159 sock.close()
160 except:
161 logger.warning("failed to close socket to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
162
163 self.addTearDownHook(shutdown_socket)
164
Todd Fiala24189d42014-07-14 06:24:44 +0000165 connect_info = ("localhost", self.port)
166 # print "connecting to stub on {}:{}".format(connect_info[0], connect_info[1])
167 sock.connect(connect_info)
168
Todd Fialae50b2e42014-06-13 19:11:33 +0000169 return sock
170
171 def set_inferior_startup_launch(self):
172 self._inferior_startup = self._STARTUP_LAUNCH
173
174 def set_inferior_startup_attach(self):
175 self._inferior_startup = self._STARTUP_ATTACH
176
Todd Fiala8aae4f42014-06-13 23:34:17 +0000177 def launch_debug_monitor(self, attach_pid=None):
178 # Create the command line.
Todd Fialae50b2e42014-06-13 19:11:33 +0000179 commandline = "{}{} localhost:{}".format(self.debug_monitor_exe, self.debug_monitor_extra_args, self.port)
180 if attach_pid:
181 commandline += " --attach=%d" % attach_pid
Todd Fiala67041192014-07-11 22:50:13 +0000182 if self.named_pipe_path:
183 commandline += " --named-pipe %s" % self.named_pipe_path
Todd Fialae50b2e42014-06-13 19:11:33 +0000184
Todd Fiala8aae4f42014-06-13 23:34:17 +0000185 # Start the server.
Todd Fialae50b2e42014-06-13 19:11:33 +0000186 server = pexpect.spawn(commandline)
Todd Fiala24189d42014-07-14 06:24:44 +0000187 self.assertIsNotNone(server)
188 server.expect(r"(debugserver|lldb-gdbserver)", timeout=10)
189
190 # If we're receiving the stub's listening port from the named pipe, do that here.
191 if self.named_pipe:
192 self.port = self.get_stub_port_from_named_socket()
193 # print "debug server listening on {}".format(self.port)
Todd Fialae50b2e42014-06-13 19:11:33 +0000194
195 # Turn on logging for what the child sends back.
196 if self.TraceOn():
197 server.logfile_read = sys.stdout
198
Todd Fiala8aae4f42014-06-13 23:34:17 +0000199 return server
200
201 def connect_to_debug_monitor(self, attach_pid=None):
Todd Fiala24189d42014-07-14 06:24:44 +0000202 if self.named_pipe:
203 # Create the stub.
204 server = self.launch_debug_monitor(attach_pid=attach_pid)
205 self.assertIsNotNone(server)
206
207 def shutdown_debug_monitor():
208 try:
209 server.close()
210 except:
211 logger.warning("failed to close pexpect server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
212 self.addTearDownHook(shutdown_debug_monitor)
213
214 # Schedule debug monitor to be shut down during teardown.
215 logger = self.logger
216
217 # Attach to the stub and return a socket opened to it.
218 self.sock = self.create_socket()
219 return server
220
221 # We're using a random port algorithm to try not to collide with other ports,
222 # and retry a max # times.
Todd Fiala8aae4f42014-06-13 23:34:17 +0000223 attempts = 0
224 MAX_ATTEMPTS = 20
Todd Fialae50b2e42014-06-13 19:11:33 +0000225
Todd Fiala8aae4f42014-06-13 23:34:17 +0000226 while attempts < MAX_ATTEMPTS:
Todd Fiala9e2d3292014-07-09 23:10:43 +0000227 server = self.launch_debug_monitor(attach_pid=attach_pid)
228
229 # Wait until we receive the server ready message before continuing.
230 port_good = True
Todd Fiala8aae4f42014-06-13 23:34:17 +0000231 try:
Todd Fiala9e2d3292014-07-09 23:10:43 +0000232 server.expect_exact('Listening to port {} for a connection from localhost'.format(self.port))
233 except:
234 port_good = False
235 server.close()
Todd Fialae50b2e42014-06-13 19:11:33 +0000236
Todd Fiala9e2d3292014-07-09 23:10:43 +0000237 if port_good:
238 # Schedule debug monitor to be shut down during teardown.
239 logger = self.logger
240 def shutdown_debug_monitor():
241 try:
242 server.close()
243 except:
244 logger.warning("failed to close pexpect server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
245 self.addTearDownHook(shutdown_debug_monitor)
Todd Fiala8aae4f42014-06-13 23:34:17 +0000246
Todd Fiala9e2d3292014-07-09 23:10:43 +0000247 # Create a socket to talk to the server
248 try:
249 self.sock = self.create_socket()
250 return server
251 except socket.error as serr:
252 # We're only trying to handle connection refused.
253 if serr.errno != errno.ECONNREFUSED:
254 raise serr
255 # We should close the server here to be safe.
256 server.close()
257
258 # Increment attempts.
259 print("connect to debug monitor on port %d failed, attempt #%d of %d" % (self.port, attempts + 1, MAX_ATTEMPTS))
260 attempts += 1
261
262 # And wait a random length of time before next attempt, to avoid collisions.
263 time.sleep(random.randint(1,5))
264
265 # Now grab a new port number.
266 self.port = self.get_next_port()
Todd Fiala8aae4f42014-06-13 23:34:17 +0000267
268 raise Exception("failed to create a socket to the launched debug monitor after %d tries" % attempts)
Todd Fialae50b2e42014-06-13 19:11:33 +0000269
270 def launch_process_for_attach(self,inferior_args=None, sleep_seconds=3):
271 # We're going to start a child process that the debug monitor stub can later attach to.
272 # This process needs to be started so that it just hangs around for a while. We'll
273 # have it sleep.
274 exe_path = os.path.abspath("a.out")
275
276 args = [exe_path]
277 if inferior_args:
278 args.extend(inferior_args)
279 if sleep_seconds:
280 args.append("sleep:%d" % sleep_seconds)
281
282 return subprocess.Popen(args)
283
284 def prep_debug_monitor_and_inferior(self, inferior_args=None, inferior_sleep_seconds=3):
285 """Prep the debug monitor, the inferior, and the expected packet stream.
286
287 Handle the separate cases of using the debug monitor in attach-to-inferior mode
288 and in launch-inferior mode.
289
290 For attach-to-inferior mode, the inferior process is first started, then
291 the debug monitor is started in attach to pid mode (using --attach on the
292 stub command line), and the no-ack-mode setup is appended to the packet
293 stream. The packet stream is not yet executed, ready to have more expected
294 packet entries added to it.
295
296 For launch-inferior mode, the stub is first started, then no ack mode is
297 setup on the expected packet stream, then the verified launch packets are added
298 to the expected socket stream. The packet stream is not yet executed, ready
299 to have more expected packet entries added to it.
300
301 The return value is:
302 {inferior:<inferior>, server:<server>}
303 """
304 inferior = None
305 attach_pid = None
306
307 if self._inferior_startup == self._STARTUP_ATTACH:
308 # Launch the process that we'll use as the inferior.
309 inferior = self.launch_process_for_attach(inferior_args=inferior_args, sleep_seconds=inferior_sleep_seconds)
310 self.assertIsNotNone(inferior)
311 self.assertTrue(inferior.pid > 0)
312 attach_pid = inferior.pid
313
314 # Launch the debug monitor stub, attaching to the inferior.
Todd Fiala8aae4f42014-06-13 23:34:17 +0000315 server = self.connect_to_debug_monitor(attach_pid=attach_pid)
Todd Fialae50b2e42014-06-13 19:11:33 +0000316 self.assertIsNotNone(server)
317
318 if self._inferior_startup == self._STARTUP_LAUNCH:
319 # Build launch args
320 launch_args = [os.path.abspath('a.out')]
321 if inferior_args:
322 launch_args.extend(inferior_args)
323
324 # Build the expected protocol stream
325 self.add_no_ack_remote_stream()
326 if self._inferior_startup == self._STARTUP_LAUNCH:
327 self.add_verified_launch_packets(launch_args)
328
329 return {"inferior":inferior, "server":server}
330
331 def add_no_ack_remote_stream(self):
332 self.test_sequence.add_log_lines(
333 ["read packet: +",
334 "read packet: $QStartNoAckMode#b0",
335 "send packet: +",
336 "send packet: $OK#9a",
337 "read packet: +"],
338 True)
339
340 def add_verified_launch_packets(self, launch_args):
341 self.test_sequence.add_log_lines(
342 ["read packet: %s" % build_gdbremote_A_packet(launch_args),
343 "send packet: $OK#00",
344 "read packet: $qLaunchSuccess#a5",
345 "send packet: $OK#00"],
346 True)
347
348 def add_thread_suffix_request_packets(self):
349 self.test_sequence.add_log_lines(
350 ["read packet: $QThreadSuffixSupported#00",
351 "send packet: $OK#00",
352 ], True)
353
354 def add_process_info_collection_packets(self):
355 self.test_sequence.add_log_lines(
356 ["read packet: $qProcessInfo#00",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000357 { "direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"process_info_raw"} }],
Todd Fialae50b2e42014-06-13 19:11:33 +0000358 True)
359
360 _KNOWN_PROCESS_INFO_KEYS = [
361 "pid",
362 "parent-pid",
363 "real-uid",
364 "real-gid",
365 "effective-uid",
366 "effective-gid",
367 "cputype",
368 "cpusubtype",
369 "ostype",
370 "vendor",
371 "endian",
372 "ptrsize"
373 ]
374
375 def parse_process_info_response(self, context):
376 # Ensure we have a process info response.
377 self.assertIsNotNone(context)
378 process_info_raw = context.get("process_info_raw")
379 self.assertIsNotNone(process_info_raw)
380
381 # Pull out key:value; pairs.
382 process_info_dict = { match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", process_info_raw) }
383
384 # Validate keys are known.
385 for (key, val) in process_info_dict.items():
386 self.assertTrue(key in self._KNOWN_PROCESS_INFO_KEYS)
387 self.assertIsNotNone(val)
388
389 return process_info_dict
390
391 def add_register_info_collection_packets(self):
392 self.test_sequence.add_log_lines(
393 [ { "type":"multi_response", "query":"qRegisterInfo", "append_iteration_suffix":True,
394 "end_regex":re.compile(r"^\$(E\d+)?#[0-9a-fA-F]{2}$"),
395 "save_key":"reg_info_responses" } ],
396 True)
397
398 def parse_register_info_packets(self, context):
399 """Return an array of register info dictionaries, one per register info."""
400 reg_info_responses = context.get("reg_info_responses")
401 self.assertIsNotNone(reg_info_responses)
402
403 # Parse register infos.
404 return [parse_reg_info_response(reg_info_response) for reg_info_response in reg_info_responses]
405
Todd Fiala50a211b2014-06-14 22:00:36 +0000406 def expect_gdbremote_sequence(self, timeout_seconds=None):
Todd Fiala8aae4f42014-06-13 23:34:17 +0000407 if not timeout_seconds:
408 timeout_seconds = self._TIMEOUT_SECONDS
409 return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, timeout_seconds, self.logger)
Todd Fialae50b2e42014-06-13 19:11:33 +0000410
411 _KNOWN_REGINFO_KEYS = [
412 "name",
413 "alt-name",
414 "bitsize",
415 "offset",
416 "encoding",
417 "format",
418 "set",
419 "gcc",
420 "dwarf",
421 "generic",
422 "container-regs",
423 "invalidate-regs"
424 ]
425
426 def assert_valid_reg_info(self, reg_info):
427 # Assert we know about all the reginfo keys parsed.
428 for key in reg_info:
429 self.assertTrue(key in self._KNOWN_REGINFO_KEYS)
430
431 # Check the bare-minimum expected set of register info keys.
432 self.assertTrue("name" in reg_info)
433 self.assertTrue("bitsize" in reg_info)
434 self.assertTrue("offset" in reg_info)
435 self.assertTrue("encoding" in reg_info)
436 self.assertTrue("format" in reg_info)
437
438 def find_pc_reg_info(self, reg_infos):
439 lldb_reg_index = 0
440 for reg_info in reg_infos:
441 if ("generic" in reg_info) and (reg_info["generic"] == "pc"):
442 return (lldb_reg_index, reg_info)
443 lldb_reg_index += 1
444
445 return (None, None)
446
447 def add_lldb_register_index(self, reg_infos):
448 """Add a "lldb_register_index" key containing the 0-baed index of each reg_infos entry.
449
450 We'll use this when we want to call packets like P/p with a register index but do so
451 on only a subset of the full register info set.
452 """
453 self.assertIsNotNone(reg_infos)
454
455 reg_index = 0
456 for reg_info in reg_infos:
457 reg_info["lldb_register_index"] = reg_index
458 reg_index += 1
459
460 def add_query_memory_region_packets(self, address):
461 self.test_sequence.add_log_lines(
462 ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address),
463 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }],
464 True)
465
Todd Fialac30281a2014-06-14 03:03:23 +0000466 def parse_key_val_dict(self, key_val_text, allow_dupes=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000467 self.assertIsNotNone(key_val_text)
468 kv_dict = {}
469 for match in re.finditer(r";?([^:]+):([^;]+)", key_val_text):
Todd Fialac30281a2014-06-14 03:03:23 +0000470 key = match.group(1)
471 val = match.group(2)
472 if key in kv_dict:
473 if allow_dupes:
474 if type(kv_dict[key]) == list:
475 kv_dict[key].append(val)
476 else:
477 # Promote to list
478 kv_dict[key] = [kv_dict[key], val]
479 else:
480 self.fail("key '{}' already present when attempting to add value '{}' (text='{}', dict={})".format(key, val, key_val_text, kv_dict))
481 else:
482 kv_dict[key] = val
Todd Fialae50b2e42014-06-13 19:11:33 +0000483 return kv_dict
484
485 def parse_memory_region_packet(self, context):
486 # Ensure we have a context.
487 self.assertIsNotNone(context.get("memory_region_response"))
488
489 # Pull out key:value; pairs.
490 mem_region_dict = self.parse_key_val_dict(context.get("memory_region_response"))
491
492 # Validate keys are known.
493 for (key, val) in mem_region_dict.items():
494 self.assertTrue(key in ["start", "size", "permissions", "error"])
495 self.assertIsNotNone(val)
496
497 # Return the dictionary of key-value pairs for the memory region.
498 return mem_region_dict
499
500 def assert_address_within_memory_region(self, test_address, mem_region_dict):
501 self.assertIsNotNone(mem_region_dict)
502 self.assertTrue("start" in mem_region_dict)
503 self.assertTrue("size" in mem_region_dict)
504
505 range_start = int(mem_region_dict["start"], 16)
506 range_size = int(mem_region_dict["size"], 16)
507 range_end = range_start + range_size
508
509 if test_address < range_start:
510 self.fail("address 0x{0:x} comes before range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size))
511 elif test_address >= range_end:
512 self.fail("address 0x{0:x} comes after range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size))
513
514 def add_threadinfo_collection_packets(self):
515 self.test_sequence.add_log_lines(
516 [ { "type":"multi_response", "first_query":"qfThreadInfo", "next_query":"qsThreadInfo",
517 "append_iteration_suffix":False, "end_regex":re.compile(r"^\$(l)?#[0-9a-fA-F]{2}$"),
518 "save_key":"threadinfo_responses" } ],
519 True)
520
521 def parse_threadinfo_packets(self, context):
522 """Return an array of thread ids (decimal ints), one per thread."""
523 threadinfo_responses = context.get("threadinfo_responses")
524 self.assertIsNotNone(threadinfo_responses)
525
526 thread_ids = []
527 for threadinfo_response in threadinfo_responses:
528 new_thread_infos = parse_threadinfo_response(threadinfo_response)
529 thread_ids.extend(new_thread_infos)
530 return thread_ids
531
532 def wait_for_thread_count(self, thread_count, timeout_seconds=3):
533 start_time = time.time()
534 timeout_time = start_time + timeout_seconds
535
536 actual_thread_count = 0
537 while actual_thread_count < thread_count:
538 self.reset_test_sequence()
539 self.add_threadinfo_collection_packets()
540
541 context = self.expect_gdbremote_sequence()
542 self.assertIsNotNone(context)
543
544 threads = self.parse_threadinfo_packets(context)
545 self.assertIsNotNone(threads)
546
547 actual_thread_count = len(threads)
548
549 if time.time() > timeout_time:
550 raise Exception(
551 'timed out after {} seconds while waiting for theads: waiting for at least {} threads, found {}'.format(
552 timeout_seconds, thread_count, actual_thread_count))
553
554 return threads
555
556 def add_set_breakpoint_packets(self, address, do_continue=True, breakpoint_kind=1):
557 self.test_sequence.add_log_lines(
558 [# Set the breakpoint.
559 "read packet: $Z0,{0:x},{1}#00".format(address, breakpoint_kind),
560 # Verify the stub could set it.
561 "send packet: $OK#00",
562 ], True)
563
564 if (do_continue):
565 self.test_sequence.add_log_lines(
566 [# Continue the inferior.
567 "read packet: $c#00",
568 # Expect a breakpoint stop report.
569 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
570 ], True)
571
572 def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
573 self.test_sequence.add_log_lines(
574 [# Remove the breakpoint.
575 "read packet: $z0,{0:x},{1}#00".format(address, breakpoint_kind),
576 # Verify the stub could unset it.
577 "send packet: $OK#00",
578 ], True)
579
580 def add_qSupported_packets(self):
581 self.test_sequence.add_log_lines(
582 ["read packet: $qSupported#00",
583 {"direction":"send", "regex":r"^\$(.*)#[0-9a-fA-F]{2}", "capture":{1: "qSupported_response"}},
584 ], True)
585
586 _KNOWN_QSUPPORTED_STUB_FEATURES = [
587 "augmented-libraries-svr4-read",
588 "PacketSize",
589 "QStartNoAckMode",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000590 "QThreadSuffixSupported",
Todd Fiala43ab82c2014-06-15 23:33:09 +0000591 "QListThreadsInStopReply",
Todd Fialae50b2e42014-06-13 19:11:33 +0000592 "qXfer:auxv:read",
593 "qXfer:libraries:read",
594 "qXfer:libraries-svr4:read",
595 ]
596
597 def parse_qSupported_response(self, context):
598 self.assertIsNotNone(context)
599
600 raw_response = context.get("qSupported_response")
601 self.assertIsNotNone(raw_response)
602
603 # For values with key=val, the dict key and vals are set as expected. For feature+, feature- and feature?, the
604 # +,-,? is stripped from the key and set as the value.
605 supported_dict = {}
606 for match in re.finditer(r";?([^=;]+)(=([^;]+))?", raw_response):
607 key = match.group(1)
608 val = match.group(3)
609
610 # key=val: store as is
611 if val and len(val) > 0:
612 supported_dict[key] = val
613 else:
614 if len(key) < 2:
615 raise Exception("singular stub feature is too short: must be stub_feature{+,-,?}")
616 supported_type = key[-1]
617 key = key[:-1]
618 if not supported_type in ["+", "-", "?"]:
619 raise Exception("malformed stub feature: final character {} not in expected set (+,-,?)".format(supported_type))
620 supported_dict[key] = supported_type
621 # Ensure we know the supported element
622 if not key in self._KNOWN_QSUPPORTED_STUB_FEATURES:
623 raise Exception("unknown qSupported stub feature reported: %s" % key)
624
625 return supported_dict
626
627 def run_process_then_stop(self, run_seconds=1):
628 # Tell the stub to continue.
629 self.test_sequence.add_log_lines(
630 ["read packet: $vCont;c#00"],
631 True)
632 context = self.expect_gdbremote_sequence()
633
634 # Wait for run_seconds.
635 time.sleep(run_seconds)
636
637 # Send an interrupt, capture a T response.
638 self.reset_test_sequence()
639 self.test_sequence.add_log_lines(
640 ["read packet: {}".format(chr(03)),
641 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result"} }],
642 True)
643 context = self.expect_gdbremote_sequence()
644 self.assertIsNotNone(context)
645 self.assertIsNotNone(context.get("stop_result"))
646
647 return context
648
649 def select_modifiable_register(self, reg_infos):
650 """Find a register that can be read/written freely."""
651 PREFERRED_REGISTER_NAMES = sets.Set(["rax",])
652
653 # First check for the first register from the preferred register name set.
654 alternative_register_index = None
655
656 self.assertIsNotNone(reg_infos)
657 for reg_info in reg_infos:
658 if ("name" in reg_info) and (reg_info["name"] in PREFERRED_REGISTER_NAMES):
659 # We found a preferred register. Use it.
660 return reg_info["lldb_register_index"]
661 if ("generic" in reg_info) and (reg_info["generic"] == "fp"):
662 # A frame pointer register will do as a register to modify temporarily.
663 alternative_register_index = reg_info["lldb_register_index"]
664
665 # We didn't find a preferred register. Return whatever alternative register
666 # we found, if any.
667 return alternative_register_index
668
669 def extract_registers_from_stop_notification(self, stop_key_vals_text):
670 self.assertIsNotNone(stop_key_vals_text)
671 kv_dict = self.parse_key_val_dict(stop_key_vals_text)
672
673 registers = {}
674 for (key, val) in kv_dict.items():
675 if re.match(r"^[0-9a-fA-F]+", key):
676 registers[int(key, 16)] = val
677 return registers
678
679 def gather_register_infos(self):
680 self.reset_test_sequence()
681 self.add_register_info_collection_packets()
682
683 context = self.expect_gdbremote_sequence()
684 self.assertIsNotNone(context)
685
686 reg_infos = self.parse_register_info_packets(context)
687 self.assertIsNotNone(reg_infos)
688 self.add_lldb_register_index(reg_infos)
689
690 return reg_infos
691
692 def find_generic_register_with_name(self, reg_infos, generic_name):
693 self.assertIsNotNone(reg_infos)
694 for reg_info in reg_infos:
695 if ("generic" in reg_info) and (reg_info["generic"] == generic_name):
696 return reg_info
697 return None
698
Todd Fiala8d7ab8c2014-06-17 16:04:45 +0000699 def decode_gdbremote_binary(self, encoded_bytes):
700 decoded_bytes = ""
701 i = 0
702 while i < len(encoded_bytes):
703 if encoded_bytes[i] == "}":
704 # Handle escaped char.
705 self.assertTrue(i + 1 < len(encoded_bytes))
706 decoded_bytes += chr(ord(encoded_bytes[i+1]) ^ 0x20)
707 i +=2
708 elif encoded_bytes[i] == "*":
709 # Handle run length encoding.
710 self.assertTrue(len(decoded_bytes) > 0)
711 self.assertTrue(i + 1 < len(encoded_bytes))
712 repeat_count = ord(encoded_bytes[i+1]) - 29
713 decoded_bytes += decoded_bytes[-1] * repeat_count
714 i += 2
715 else:
716 decoded_bytes += encoded_bytes[i]
717 i += 1
718 return decoded_bytes
719
720 def build_auxv_dict(self, endian, word_size, auxv_data):
721 self.assertIsNotNone(endian)
722 self.assertIsNotNone(word_size)
723 self.assertIsNotNone(auxv_data)
724
725 auxv_dict = {}
726
727 while len(auxv_data) > 0:
728 # Chop off key.
729 raw_key = auxv_data[:word_size]
730 auxv_data = auxv_data[word_size:]
731
732 # Chop of value.
733 raw_value = auxv_data[:word_size]
734 auxv_data = auxv_data[word_size:]
735
736 # Convert raw text from target endian.
737 key = unpack_endian_binary_string(endian, raw_key)
738 value = unpack_endian_binary_string(endian, raw_value)
739
740 # Handle ending entry.
741 if key == 0:
742 self.assertEquals(value, 0)
743 return auxv_dict
744
745 # The key should not already be present.
746 self.assertFalse(key in auxv_dict)
747 auxv_dict[key] = value
748
749 self.fail("should not reach here - implies required double zero entry not found")
750 return auxv_dict
Todd Fiala51886732014-06-17 22:01:27 +0000751
752 def read_binary_data_in_chunks(self, command_prefix, chunk_length):
753 """Collect command_prefix{offset:x},{chunk_length:x} until a single 'l' or 'l' with data is returned."""
754 offset = 0
755 done = False
756 decoded_data = ""
757
758 while not done:
759 # Grab the next iteration of data.
760 self.reset_test_sequence()
761 self.test_sequence.add_log_lines([
762 "read packet: ${}{:x},{:x}:#00".format(command_prefix, offset, chunk_length),
Todd Fiala4c24eba2014-06-19 17:35:40 +0000763 {"direction":"send", "regex":re.compile(r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE|re.DOTALL), "capture":{1:"response_type", 2:"content_raw"} }
Todd Fiala51886732014-06-17 22:01:27 +0000764 ], True)
765
766 context = self.expect_gdbremote_sequence()
767 self.assertIsNotNone(context)
768
769 response_type = context.get("response_type")
770 self.assertIsNotNone(response_type)
771 self.assertTrue(response_type in ["l", "m"])
772
773 # Move offset along.
774 offset += chunk_length
775
776 # Figure out if we're done. We're done if the response type is l.
777 done = response_type == "l"
778
779 # Decode binary data.
780 content_raw = context.get("content_raw")
781 if content_raw and len(content_raw) > 0:
782 self.assertIsNotNone(content_raw)
783 decoded_data += self.decode_gdbremote_binary(content_raw)
784 return decoded_data
Todd Fiala4c24eba2014-06-19 17:35:40 +0000785
786 def add_interrupt_packets(self):
787 self.test_sequence.add_log_lines([
788 # Send the intterupt.
789 "read packet: {}".format(chr(03)),
790 # And wait for the stop notification.
791 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", "capture":{1:"stop_signo", 2:"stop_key_val_text" } },
792 ], True)
793
794 def parse_interrupt_packets(self, context):
795 self.assertIsNotNone(context.get("stop_signo"))
796 self.assertIsNotNone(context.get("stop_key_val_text"))
Todd Fiala9846d452014-06-20 17:39:24 +0000797 return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"]))
798
799 def add_QSaveRegisterState_packets(self, thread_id):
800 if thread_id:
801 # Use the thread suffix form.
802 request = "read packet: $QSaveRegisterState;thread:{:x}#00".format(thread_id)
803 else:
804 request = "read packet: $QSaveRegisterState#00"
805
806 self.test_sequence.add_log_lines([
807 request,
808 {"direction":"send", "regex":r"^\$(E?.*)#[0-9a-fA-F]{2}$", "capture":{1:"save_response" } },
809 ], True)
810
811 def parse_QSaveRegisterState_response(self, context):
812 self.assertIsNotNone(context)
813
814 save_response = context.get("save_response")
815 self.assertIsNotNone(save_response)
816
817 if len(save_response) < 1 or save_response[0] == "E":
818 # error received
819 return (False, None)
820 else:
821 return (True, int(save_response))
822
823 def add_QRestoreRegisterState_packets(self, save_id, thread_id=None):
824 if thread_id:
825 # Use the thread suffix form.
826 request = "read packet: $QRestoreRegisterState:{};thread:{:x}#00".format(save_id, thread_id)
827 else:
828 request = "read packet: $QRestoreRegisterState:{}#00".format(save_id)
829
830 self.test_sequence.add_log_lines([
831 request,
832 "send packet: $OK#00"
833 ], True)
834
835 def flip_all_bits_in_each_register_value(self, reg_infos, endian, thread_id=None):
836 self.assertIsNotNone(reg_infos)
837
838 successful_writes = 0
839 failed_writes = 0
840
841 for reg_info in reg_infos:
842 # Use the lldb register index added to the reg info. We're not necessarily
843 # working off a full set of register infos, so an inferred register index could be wrong.
844 reg_index = reg_info["lldb_register_index"]
845 self.assertIsNotNone(reg_index)
846
847 reg_byte_size = int(reg_info["bitsize"])/8
848 self.assertTrue(reg_byte_size > 0)
849
850 # Handle thread suffix.
851 if thread_id:
852 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
853 else:
854 p_request = "read packet: $p{:x}#00".format(reg_index)
855
856 # Read the existing value.
857 self.reset_test_sequence()
858 self.test_sequence.add_log_lines([
859 p_request,
860 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
861 ], True)
862 context = self.expect_gdbremote_sequence()
863 self.assertIsNotNone(context)
864
865 # Verify the response length.
866 p_response = context.get("p_response")
867 self.assertIsNotNone(p_response)
868 initial_reg_value = unpack_register_hex_unsigned(endian, p_response)
869
870 # Flip the value by xoring with all 1s
871 all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) / 8)
872 flipped_bits_int = initial_reg_value ^ int(all_one_bits_raw, 16)
873 # print "reg (index={}, name={}): val={}, flipped bits (int={}, hex={:x})".format(reg_index, reg_info["name"], initial_reg_value, flipped_bits_int, flipped_bits_int)
874
875 # Handle thread suffix for P.
876 if thread_id:
877 P_request = "read packet: $P{:x}={};thread:{:x}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size), thread_id)
878 else:
879 P_request = "read packet: $P{:x}={}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size))
880
881 # Write the flipped value to the register.
882 self.reset_test_sequence()
883 self.test_sequence.add_log_lines([
884 P_request,
885 { "direction":"send", "regex":r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", "capture":{1:"P_response"} },
886 ], True)
887 context = self.expect_gdbremote_sequence()
888 self.assertIsNotNone(context)
889
890 # Determine if the write succeeded. There are a handful of registers that can fail, or partially fail
891 # (e.g. flags, segment selectors, etc.) due to register value restrictions. Don't worry about them
892 # all flipping perfectly.
893 P_response = context.get("P_response")
894 self.assertIsNotNone(P_response)
895 if P_response == "OK":
896 successful_writes += 1
897 else:
898 failed_writes += 1
899 # print "reg (index={}, name={}) write FAILED (error: {})".format(reg_index, reg_info["name"], P_response)
900
901 # Read back the register value, ensure it matches the flipped value.
902 if P_response == "OK":
903 self.reset_test_sequence()
904 self.test_sequence.add_log_lines([
905 p_request,
906 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
907 ], True)
908 context = self.expect_gdbremote_sequence()
909 self.assertIsNotNone(context)
910
911 verify_p_response_raw = context.get("p_response")
912 self.assertIsNotNone(verify_p_response_raw)
913 verify_bits = unpack_register_hex_unsigned(endian, verify_p_response_raw)
914
915 if verify_bits != flipped_bits_int:
916 # Some registers, like mxcsrmask and others, will permute what's written. Adjust succeed/fail counts.
917 # print "reg (index={}, name={}): read verify FAILED: wrote {:x}, verify read back {:x}".format(reg_index, reg_info["name"], flipped_bits_int, verify_bits)
918 successful_writes -= 1
919 failed_writes +=1
920
921 return (successful_writes, failed_writes)
922
923 def is_bit_flippable_register(self, reg_info):
924 if not reg_info:
925 return False
926 if not "set" in reg_info:
927 return False
928 if reg_info["set"] != "General Purpose Registers":
929 return False
930 if ("container-regs" in reg_info) and (len(reg_info["container-regs"]) > 0):
931 # Don't try to bit flip registers contained in another register.
932 return False
933 if re.match("^.s$", reg_info["name"]):
934 # This is a 2-letter register name that ends in "s", like a segment register.
935 # Don't try to bit flip these.
936 return False
937 # Okay, this looks fine-enough.
938 return True
939
940 def read_register_values(self, reg_infos, endian, thread_id=None):
941 self.assertIsNotNone(reg_infos)
942 values = {}
943
944 for reg_info in reg_infos:
945 # We append a register index when load reg infos so we can work with subsets.
946 reg_index = reg_info.get("lldb_register_index")
947 self.assertIsNotNone(reg_index)
948
949 # Handle thread suffix.
950 if thread_id:
951 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
952 else:
953 p_request = "read packet: $p{:x}#00".format(reg_index)
954
955 # Read it with p.
956 self.reset_test_sequence()
957 self.test_sequence.add_log_lines([
958 p_request,
959 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
960 ], True)
961 context = self.expect_gdbremote_sequence()
962 self.assertIsNotNone(context)
963
964 # Convert value from target endian to integral.
965 p_response = context.get("p_response")
966 self.assertIsNotNone(p_response)
967 self.assertTrue(len(p_response) > 0)
968 self.assertFalse(p_response[0] == "E")
969
970 values[reg_index] = unpack_register_hex_unsigned(endian, p_response)
971
Todd Fialae2202002014-06-27 22:11:56 +0000972 return values
973
974 def add_vCont_query_packets(self):
975 self.test_sequence.add_log_lines([
976 "read packet: $vCont?#00",
977 {"direction":"send", "regex":r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", "capture":{2:"vCont_query_response" } },
978 ], True)
979
980 def parse_vCont_query_response(self, context):
981 self.assertIsNotNone(context)
982 vCont_query_response = context.get("vCont_query_response")
983
984 # Handle case of no vCont support at all - in which case the capture group will be none or zero length.
985 if not vCont_query_response or len(vCont_query_response) == 0:
986 return {}
987
988 return {key:1 for key in vCont_query_response.split(";") if key and len(key) > 0}
989
990 def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100, use_Hc_packet=True, step_instruction="s"):
991 """Used by single step test that appears in a few different contexts."""
992 single_step_count = 0
993
994 while single_step_count < max_step_count:
995 self.assertIsNotNone(thread_id)
996
997 # Build the packet for the single step instruction. We replace {thread}, if present, with the thread_id.
998 step_packet = "read packet: ${}#00".format(re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction))
999 # print "\nstep_packet created: {}\n".format(step_packet)
1000
1001 # Single step.
1002 self.reset_test_sequence()
1003 if use_Hc_packet:
1004 self.test_sequence.add_log_lines(
1005 [# Set the continue thread.
1006 "read packet: $Hc{0:x}#00".format(thread_id),
1007 "send packet: $OK#00",
1008 ], True)
1009 self.test_sequence.add_log_lines([
1010 # Single step.
1011 step_packet,
1012 # "read packet: $vCont;s:{0:x}#00".format(thread_id),
1013 # Expect a breakpoint stop report.
1014 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
1015 ], True)
1016 context = self.expect_gdbremote_sequence()
1017 self.assertIsNotNone(context)
1018 self.assertIsNotNone(context.get("stop_signo"))
1019 self.assertEquals(int(context.get("stop_signo"), 16), signal.SIGTRAP)
1020
1021 single_step_count += 1
1022
1023 # See if the predicate is true. If so, we're done.
1024 if predicate(args):
1025 return (True, single_step_count)
1026
1027 # The predicate didn't return true within the runaway step count.
1028 return (False, single_step_count)
1029
1030 def g_c1_c2_contents_are(self, args):
1031 """Used by single step test that appears in a few different contexts."""
1032 g_c1_address = args["g_c1_address"]
1033 g_c2_address = args["g_c2_address"]
1034 expected_g_c1 = args["expected_g_c1"]
1035 expected_g_c2 = args["expected_g_c2"]
1036
1037 # Read g_c1 and g_c2 contents.
1038 self.reset_test_sequence()
1039 self.test_sequence.add_log_lines(
1040 ["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1),
1041 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c1_contents"} },
1042 "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1),
1043 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c2_contents"} }],
1044 True)
1045
1046 # Run the packet stream.
1047 context = self.expect_gdbremote_sequence()
1048 self.assertIsNotNone(context)
1049
1050 # Check if what we read from inferior memory is what we are expecting.
1051 self.assertIsNotNone(context.get("g_c1_contents"))
1052 self.assertIsNotNone(context.get("g_c2_contents"))
1053
1054 return (context.get("g_c1_contents").decode("hex") == expected_g_c1) and (context.get("g_c2_contents").decode("hex") == expected_g_c2)
1055
1056 def single_step_only_steps_one_instruction(self, use_Hc_packet=True, step_instruction="s"):
1057 """Used by single step test that appears in a few different contexts."""
1058 # Start up the inferior.
1059 procs = self.prep_debug_monitor_and_inferior(
1060 inferior_args=["get-code-address-hex:swap_chars", "get-data-address-hex:g_c1", "get-data-address-hex:g_c2", "sleep:1", "call-function:swap_chars", "sleep:5"])
1061
1062 # Run the process
1063 self.test_sequence.add_log_lines(
1064 [# Start running after initial stop.
1065 "read packet: $c#00",
1066 # Match output line that prints the memory address of the function call entry point.
1067 # Note we require launch-only testing so we can get inferior otuput.
1068 { "type":"output_match", "regex":r"^code address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\n$",
1069 "capture":{ 1:"function_address", 2:"g_c1_address", 3:"g_c2_address"} },
1070 # Now stop the inferior.
1071 "read packet: {}".format(chr(03)),
1072 # And wait for the stop notification.
1073 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
1074 True)
1075
1076 # Run the packet stream.
1077 context = self.expect_gdbremote_sequence()
1078 self.assertIsNotNone(context)
1079
1080 # Grab the main thread id.
1081 self.assertIsNotNone(context.get("stop_thread_id"))
1082 main_thread_id = int(context.get("stop_thread_id"), 16)
1083
1084 # Grab the function address.
1085 self.assertIsNotNone(context.get("function_address"))
1086 function_address = int(context.get("function_address"), 16)
1087
1088 # Grab the data addresses.
1089 self.assertIsNotNone(context.get("g_c1_address"))
1090 g_c1_address = int(context.get("g_c1_address"), 16)
1091
1092 self.assertIsNotNone(context.get("g_c2_address"))
1093 g_c2_address = int(context.get("g_c2_address"), 16)
1094
1095 # Set a breakpoint at the given address.
1096 # Note this might need to be switched per platform (ARM, mips, etc.).
1097 BREAKPOINT_KIND = 1
1098 self.reset_test_sequence()
1099 self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
1100 context = self.expect_gdbremote_sequence()
1101 self.assertIsNotNone(context)
1102
1103 # Remove the breakpoint.
1104 self.reset_test_sequence()
1105 self.add_remove_breakpoint_packets(function_address, breakpoint_kind=BREAKPOINT_KIND)
1106 context = self.expect_gdbremote_sequence()
1107 self.assertIsNotNone(context)
1108
1109 # Verify g_c1 and g_c2 match expected initial state.
1110 args = {}
1111 args["g_c1_address"] = g_c1_address
1112 args["g_c2_address"] = g_c2_address
1113 args["expected_g_c1"] = "0"
1114 args["expected_g_c2"] = "1"
1115
1116 self.assertTrue(self.g_c1_c2_contents_are(args))
1117
1118 # Verify we take only a small number of steps to hit the first state. Might need to work through function entry prologue code.
1119 args["expected_g_c1"] = "1"
1120 args["expected_g_c2"] = "1"
1121 (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=25, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
1122 self.assertTrue(state_reached)
1123
1124 # Verify we hit the next state.
1125 args["expected_g_c1"] = "1"
1126 args["expected_g_c2"] = "0"
1127 (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
1128 self.assertTrue(state_reached)
1129 self.assertEquals(step_count, 1)
1130
1131 # Verify we hit the next state.
1132 args["expected_g_c1"] = "0"
1133 args["expected_g_c2"] = "0"
1134 (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
1135 self.assertTrue(state_reached)
1136 self.assertEquals(step_count, 1)
1137
1138 # Verify we hit the next state.
1139 args["expected_g_c1"] = "0"
1140 args["expected_g_c2"] = "1"
1141 (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
1142 self.assertTrue(state_reached)
1143 self.assertEquals(step_count, 1)
Todd Fialaaf245d12014-06-30 21:05:18 +00001144