blob: a639b0130d5e874fe1966818a369d3ac1d0250cf [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 platform
Todd Fiala9e2d3292014-07-09 23:10:43 +00009import random
Todd Fialae2202002014-06-27 22:11:56 +000010import re
Todd Fiala31bde322014-07-26 20:39:17 +000011import select
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
Todd Fiala7306cf32014-07-29 22:30:01 +000035 # Start the inferior separately, attach to the inferior on the stub command line.
Todd Fialae50b2e42014-06-13 19:11:33 +000036 _STARTUP_ATTACH = "attach"
Todd Fiala7306cf32014-07-29 22:30:01 +000037 # Start the inferior separately, start the stub without attaching, allow the test to attach to the inferior however it wants (e.g. $vAttach;pid).
38 _STARTUP_ATTACH_MANUALLY = "attach_manually"
39 # Start the stub, and launch the inferior with an $A packet via the initial packet stream.
Todd Fialae50b2e42014-06-13 19:11:33 +000040 _STARTUP_LAUNCH = "launch"
41
42 # GDB Signal numbers that are not target-specific used for common exceptions
43 TARGET_EXC_BAD_ACCESS = 0x91
44 TARGET_EXC_BAD_INSTRUCTION = 0x92
45 TARGET_EXC_ARITHMETIC = 0x93
46 TARGET_EXC_EMULATION = 0x94
47 TARGET_EXC_SOFTWARE = 0x95
48 TARGET_EXC_BREAKPOINT = 0x96
49
50 def setUp(self):
51 TestBase.setUp(self)
52 FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s'
53 logging.basicConfig(format=FORMAT)
54 self.logger = logging.getLogger(__name__)
55 self.logger.setLevel(self._LOGGING_LEVEL)
56 self.test_sequence = GdbRemoteTestSequence(self.logger)
57 self.set_inferior_startup_launch()
Todd Fiala9e2d3292014-07-09 23:10:43 +000058 self.port = self.get_next_port()
Todd Fiala67041192014-07-11 22:50:13 +000059 self.named_pipe_path = None
Todd Fiala24189d42014-07-14 06:24:44 +000060 self.named_pipe = None
61 self.named_pipe_fd = None
Todd Fialaf9ad21d2014-07-16 16:15:42 +000062 self.stub_sends_two_stop_notifications_on_kill = False
Tamas Berghammerde786792015-03-30 10:52:32 +000063 if lldb.platfrom_url:
64 self.stub_hostname = re.match(".*://(.*):[0-9]+", lldb.platfrom_url).group(1)
65 else:
66 self.stub_hostname = "localhost"
Todd Fialae50b2e42014-06-13 19:11:33 +000067
Todd Fiala9e2d3292014-07-09 23:10:43 +000068 def get_next_port(self):
69 return 12000 + random.randint(0,3999)
Todd Fialae50b2e42014-06-13 19:11:33 +000070
71 def reset_test_sequence(self):
72 self.test_sequence = GdbRemoteTestSequence(self.logger)
73
Todd Fiala24189d42014-07-14 06:24:44 +000074 def create_named_pipe(self):
75 # Create a temp dir and name for a pipe.
76 temp_dir = tempfile.mkdtemp()
77 named_pipe_path = os.path.join(temp_dir, "stub_port_number")
78
79 # Create the named pipe.
80 os.mkfifo(named_pipe_path)
81
82 # Open the read side of the pipe in non-blocking mode. This will return right away, ready or not.
83 named_pipe_fd = os.open(named_pipe_path, os.O_RDONLY | os.O_NONBLOCK)
84
85 # Create the file for the named pipe. Note this will follow semantics of
86 # a non-blocking read side of a named pipe, which has different semantics
87 # than a named pipe opened for read in non-blocking mode.
88 named_pipe = os.fdopen(named_pipe_fd, "r")
89 self.assertIsNotNone(named_pipe)
90
91 def shutdown_named_pipe():
92 # Close the pipe.
93 try:
94 named_pipe.close()
95 except:
96 print "failed to close named pipe"
97 None
98
99 # Delete the pipe.
100 try:
101 os.remove(named_pipe_path)
102 except:
103 print "failed to delete named pipe: {}".format(named_pipe_path)
104 None
105
106 # Delete the temp directory.
107 try:
108 os.rmdir(temp_dir)
109 except:
110 print "failed to delete temp dir: {}, directory contents: '{}'".format(temp_dir, os.listdir(temp_dir))
111 None
112
113 # Add the shutdown hook to clean up the named pipe.
114 self.addTearDownHook(shutdown_named_pipe)
115
116 # Clear the port so the stub selects a port number.
117 self.port = 0
118
119 return (named_pipe_path, named_pipe, named_pipe_fd)
120
121 def get_stub_port_from_named_socket(self, read_timeout_seconds=5):
122 # Wait for something to read with a max timeout.
123 (ready_readers, _, _) = select.select([self.named_pipe_fd], [], [], read_timeout_seconds)
124 self.assertIsNotNone(ready_readers, "write side of pipe has not written anything - stub isn't writing to pipe.")
125 self.assertNotEqual(len(ready_readers), 0, "write side of pipe has not written anything - stub isn't writing to pipe.")
126
127 # Read the port from the named pipe.
128 stub_port_raw = self.named_pipe.read()
129 self.assertIsNotNone(stub_port_raw)
130 self.assertNotEqual(len(stub_port_raw), 0, "no content to read on pipe")
131
132 # Trim null byte, convert to int.
133 stub_port_raw = stub_port_raw[:-1]
134 stub_port = int(stub_port_raw)
135 self.assertTrue(stub_port > 0)
136
137 return stub_port
138
139 def init_llgs_test(self, use_named_pipe=True):
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000140 if lldb.remote_platform:
141 # Remote platforms don't support named pipe based port negotiation
142 use_named_pipe = False
143
144 platform = self.dbg.GetSelectedPlatform()
145
146 shell_command = lldb.SBPlatformShellCommand("echo $PPID")
147 err = platform.Run(shell_command)
148 if err.Fail():
149 raise Exception("remote_platform.RunShellCommand('echo $PPID') failed: %s" % err)
150 pid = shell_command.GetOutput().strip()
151
152 shell_command = lldb.SBPlatformShellCommand("readlink /proc/%s/exe" % pid)
153 err = platform.Run(shell_command)
154 if err.Fail():
155 raise Exception("remote_platform.RunShellCommand('readlink /proc/%d/exe') failed: %s" % (pid, err))
156 self.debug_monitor_exe = shell_command.GetOutput().strip()
157 dname = self.dbg.GetSelectedPlatform().GetWorkingDirectory()
158 else:
159 self.debug_monitor_exe = get_lldb_server_exe()
160 if not self.debug_monitor_exe:
161 self.skipTest("lldb-server exe not found")
162 dname = os.path.join(os.environ["LLDB_TEST"], os.environ["LLDB_SESSION_DIRNAME"])
163
164 self.debug_monitor_extra_args = ["gdbserver", "-c", "log enable -T -f {}/process-{}.log lldb break process thread".format(dname, self.id()), "-c", "log enable -T -f {}/packets-{}.log gdb-remote packets".format(dname, self.id())]
Todd Fiala24189d42014-07-14 06:24:44 +0000165 if use_named_pipe:
166 (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
Todd Fialae50b2e42014-06-13 19:11:33 +0000167
Todd Fiala24189d42014-07-14 06:24:44 +0000168 def init_debugserver_test(self, use_named_pipe=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000169 self.debug_monitor_exe = get_debugserver_exe()
170 if not self.debug_monitor_exe:
171 self.skipTest("debugserver exe not found")
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000172 self.debug_monitor_extra_args = ["--log-file=/tmp/packets-{}.log".format(self._testMethodName), "--log-flags=0x800000"]
Todd Fiala24189d42014-07-14 06:24:44 +0000173 if use_named_pipe:
174 (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
Todd Fialaf9ad21d2014-07-16 16:15:42 +0000175 # The debugserver stub has a race on handling the 'k' command, so it sends an X09 right away, then sends the real X notification
176 # when the process truly dies.
177 self.stub_sends_two_stop_notifications_on_kill = True
Todd Fialae50b2e42014-06-13 19:11:33 +0000178
Tamas Berghammer27c8d362015-03-13 14:32:25 +0000179 def forward_adb_port(self, source, target, direction):
180 def remove_port_forward():
181 subprocess.call(["adb", direction, "--remove", "tcp:%d" % source])
182
183 subprocess.call(["adb", direction, "tcp:%d" % source, "tcp:%d" % target])
184 self.addTearDownHook(remove_port_forward)
185
Todd Fialae50b2e42014-06-13 19:11:33 +0000186 def create_socket(self):
187 sock = socket.socket()
188 logger = self.logger
189
Tamas Berghammerde786792015-03-30 10:52:32 +0000190 triple = self.dbg.GetSelectedPlatform().GetTriple()
191 if re.match(".*-.*-.*-android", triple):
192 self.forward_adb_port(self.port, self.port, "forward")
193
194 connect_info = (self.stub_hostname, self.port)
195 sock.connect(connect_info)
196
Todd Fialae50b2e42014-06-13 19:11:33 +0000197 def shutdown_socket():
198 if sock:
199 try:
Robert Flack8cc4cf12015-03-06 14:36:33 +0000200 # send the kill packet so lldb-server shuts down gracefully
Todd Fialae50b2e42014-06-13 19:11:33 +0000201 sock.sendall(GdbRemoteTestCaseBase._GDBREMOTE_KILL_PACKET)
202 except:
203 logger.warning("failed to send kill packet to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
204
205 try:
206 sock.close()
207 except:
208 logger.warning("failed to close socket to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
209
210 self.addTearDownHook(shutdown_socket)
211
Todd Fialae50b2e42014-06-13 19:11:33 +0000212 return sock
213
214 def set_inferior_startup_launch(self):
215 self._inferior_startup = self._STARTUP_LAUNCH
216
217 def set_inferior_startup_attach(self):
218 self._inferior_startup = self._STARTUP_ATTACH
219
Todd Fiala7306cf32014-07-29 22:30:01 +0000220 def set_inferior_startup_attach_manually(self):
221 self._inferior_startup = self._STARTUP_ATTACH_MANUALLY
222
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000223 def get_debug_monitor_command_line_args(self, attach_pid=None):
Tamas Berghammerde786792015-03-30 10:52:32 +0000224 if lldb.remote_platform:
225 commandline_args = self.debug_monitor_extra_args + ["*:{}".format(self.port)]
226 else:
227 commandline_args = self.debug_monitor_extra_args + ["localhost:{}".format(self.port)]
228
Todd Fialae50b2e42014-06-13 19:11:33 +0000229 if attach_pid:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000230 commandline_args += ["--attach=%d" % attach_pid]
Todd Fiala67041192014-07-11 22:50:13 +0000231 if self.named_pipe_path:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000232 commandline_args += ["--named-pipe", self.named_pipe_path]
233 return commandline_args
234
235 def run_platform_command(self, cmd):
236 platform = self.dbg.GetSelectedPlatform()
237 shell_command = lldb.SBPlatformShellCommand(cmd)
238 err = platform.Run(shell_command)
239 return (err, shell_command.GetOutput())
Todd Fiala31bde322014-07-26 20:39:17 +0000240
241 def launch_debug_monitor(self, attach_pid=None, logfile=None):
242 # Create the command line.
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000243 commandline_args = self.get_debug_monitor_command_line_args(attach_pid=attach_pid)
Todd Fialae50b2e42014-06-13 19:11:33 +0000244
Todd Fiala8aae4f42014-06-13 23:34:17 +0000245 # Start the server.
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000246 server = self.spawnSubprocess(self.debug_monitor_exe, commandline_args, install_remote=False)
247 self.addTearDownHook(self.cleanupSubprocesses)
Todd Fiala24189d42014-07-14 06:24:44 +0000248 self.assertIsNotNone(server)
Todd Fiala24189d42014-07-14 06:24:44 +0000249
250 # If we're receiving the stub's listening port from the named pipe, do that here.
251 if self.named_pipe:
252 self.port = self.get_stub_port_from_named_socket()
Todd Fialae50b2e42014-06-13 19:11:33 +0000253
Todd Fiala8aae4f42014-06-13 23:34:17 +0000254 return server
255
256 def connect_to_debug_monitor(self, attach_pid=None):
Todd Fiala24189d42014-07-14 06:24:44 +0000257 if self.named_pipe:
258 # Create the stub.
259 server = self.launch_debug_monitor(attach_pid=attach_pid)
260 self.assertIsNotNone(server)
261
262 def shutdown_debug_monitor():
263 try:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000264 server.terminate()
Todd Fiala24189d42014-07-14 06:24:44 +0000265 except:
266 logger.warning("failed to close pexpect server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
267 self.addTearDownHook(shutdown_debug_monitor)
268
269 # Schedule debug monitor to be shut down during teardown.
270 logger = self.logger
271
272 # Attach to the stub and return a socket opened to it.
273 self.sock = self.create_socket()
274 return server
275
276 # We're using a random port algorithm to try not to collide with other ports,
277 # and retry a max # times.
Todd Fiala8aae4f42014-06-13 23:34:17 +0000278 attempts = 0
279 MAX_ATTEMPTS = 20
Todd Fialae50b2e42014-06-13 19:11:33 +0000280
Todd Fiala8aae4f42014-06-13 23:34:17 +0000281 while attempts < MAX_ATTEMPTS:
Todd Fiala9e2d3292014-07-09 23:10:43 +0000282 server = self.launch_debug_monitor(attach_pid=attach_pid)
283
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000284 # Schedule debug monitor to be shut down during teardown.
285 logger = self.logger
286 def shutdown_debug_monitor():
Todd Fiala9e2d3292014-07-09 23:10:43 +0000287 try:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000288 server.terminate()
289 except:
290 logger.warning("failed to terminate server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
291 self.addTearDownHook(shutdown_debug_monitor)
292
Tamas Berghammerde786792015-03-30 10:52:32 +0000293 connect_attemps = 0
294 MAX_CONNECT_ATTEMPTS = 10
295
296 while connect_attemps < MAX_CONNECT_ATTEMPTS:
297 # Create a socket to talk to the server
298 try:
299 self.sock = self.create_socket()
300 return server
301 except socket.error as serr:
302 # We're only trying to handle connection refused.
303 if serr.errno != errno.ECONNREFUSED:
304 raise serr
305 time.sleep(0.5)
306 connect_attemps += 1
307
308 # We should close the server here to be safe.
309 server.terminate()
Todd Fiala9e2d3292014-07-09 23:10:43 +0000310
311 # Increment attempts.
312 print("connect to debug monitor on port %d failed, attempt #%d of %d" % (self.port, attempts + 1, MAX_ATTEMPTS))
313 attempts += 1
314
315 # And wait a random length of time before next attempt, to avoid collisions.
316 time.sleep(random.randint(1,5))
317
318 # Now grab a new port number.
319 self.port = self.get_next_port()
Todd Fiala8aae4f42014-06-13 23:34:17 +0000320
321 raise Exception("failed to create a socket to the launched debug monitor after %d tries" % attempts)
Todd Fialae50b2e42014-06-13 19:11:33 +0000322
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000323 def launch_process_for_attach(self, inferior_args=None, sleep_seconds=3, exe_path=None):
Todd Fialae50b2e42014-06-13 19:11:33 +0000324 # We're going to start a child process that the debug monitor stub can later attach to.
325 # This process needs to be started so that it just hangs around for a while. We'll
326 # have it sleep.
Todd Fiala58a2f662014-08-12 17:02:07 +0000327 if not exe_path:
328 exe_path = os.path.abspath("a.out")
Todd Fialae50b2e42014-06-13 19:11:33 +0000329
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000330 args = []
Todd Fialae50b2e42014-06-13 19:11:33 +0000331 if inferior_args:
332 args.extend(inferior_args)
333 if sleep_seconds:
334 args.append("sleep:%d" % sleep_seconds)
335
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000336 return self.spawnSubprocess(exe_path, args)
Todd Fialae50b2e42014-06-13 19:11:33 +0000337
Todd Fiala58a2f662014-08-12 17:02:07 +0000338 def prep_debug_monitor_and_inferior(self, inferior_args=None, inferior_sleep_seconds=3, inferior_exe_path=None):
Todd Fialae50b2e42014-06-13 19:11:33 +0000339 """Prep the debug monitor, the inferior, and the expected packet stream.
340
341 Handle the separate cases of using the debug monitor in attach-to-inferior mode
342 and in launch-inferior mode.
343
344 For attach-to-inferior mode, the inferior process is first started, then
345 the debug monitor is started in attach to pid mode (using --attach on the
346 stub command line), and the no-ack-mode setup is appended to the packet
347 stream. The packet stream is not yet executed, ready to have more expected
348 packet entries added to it.
349
350 For launch-inferior mode, the stub is first started, then no ack mode is
351 setup on the expected packet stream, then the verified launch packets are added
352 to the expected socket stream. The packet stream is not yet executed, ready
353 to have more expected packet entries added to it.
354
355 The return value is:
356 {inferior:<inferior>, server:<server>}
357 """
358 inferior = None
359 attach_pid = None
360
Todd Fiala7306cf32014-07-29 22:30:01 +0000361 if self._inferior_startup == self._STARTUP_ATTACH or self._inferior_startup == self._STARTUP_ATTACH_MANUALLY:
Todd Fialae50b2e42014-06-13 19:11:33 +0000362 # Launch the process that we'll use as the inferior.
Todd Fiala58a2f662014-08-12 17:02:07 +0000363 inferior = self.launch_process_for_attach(inferior_args=inferior_args, sleep_seconds=inferior_sleep_seconds, exe_path=inferior_exe_path)
Todd Fialae50b2e42014-06-13 19:11:33 +0000364 self.assertIsNotNone(inferior)
365 self.assertTrue(inferior.pid > 0)
Todd Fiala7306cf32014-07-29 22:30:01 +0000366 if self._inferior_startup == self._STARTUP_ATTACH:
367 # In this case, we want the stub to attach via the command line, so set the command line attach pid here.
368 attach_pid = inferior.pid
Todd Fialae50b2e42014-06-13 19:11:33 +0000369
Todd Fialae50b2e42014-06-13 19:11:33 +0000370 if self._inferior_startup == self._STARTUP_LAUNCH:
371 # Build launch args
Todd Fiala58a2f662014-08-12 17:02:07 +0000372 if not inferior_exe_path:
373 inferior_exe_path = os.path.abspath("a.out")
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000374
375 if lldb.remote_platform:
376 remote_work_dir = lldb.remote_platform.GetWorkingDirectory()
377 remote_path = os.path.join(remote_work_dir, os.path.basename(inferior_exe_path))
378 remote_file_spec = lldb.SBFileSpec(remote_path, False)
379 err = lldb.remote_platform.Install(lldb.SBFileSpec(inferior_exe_path, True), remote_file_spec)
380 if err.Fail():
381 raise Exception("remote_platform.Install('%s', '%s') failed: %s" % (inferior_exe_path, remote_path, err))
382 inferior_exe_path = remote_path
383
Todd Fiala58a2f662014-08-12 17:02:07 +0000384 launch_args = [inferior_exe_path]
Todd Fialae50b2e42014-06-13 19:11:33 +0000385 if inferior_args:
386 launch_args.extend(inferior_args)
387
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000388 # Launch the debug monitor stub, attaching to the inferior.
389 server = self.connect_to_debug_monitor(attach_pid=attach_pid)
390 self.assertIsNotNone(server)
391
Todd Fialae50b2e42014-06-13 19:11:33 +0000392 # Build the expected protocol stream
393 self.add_no_ack_remote_stream()
394 if self._inferior_startup == self._STARTUP_LAUNCH:
395 self.add_verified_launch_packets(launch_args)
396
397 return {"inferior":inferior, "server":server}
398
Todd Fiala31bde322014-07-26 20:39:17 +0000399 def expect_socket_recv(self, sock, expected_content_regex, timeout_seconds):
400 response = ""
401 timeout_time = time.time() + timeout_seconds
402
403 while not expected_content_regex.match(response) and time.time() < timeout_time:
404 can_read, _, _ = select.select([sock], [], [], timeout_seconds)
405 if can_read and sock in can_read:
406 recv_bytes = sock.recv(4096)
407 if recv_bytes:
408 response += recv_bytes
409
410 self.assertTrue(expected_content_regex.match(response))
411
412 def expect_socket_send(self, sock, content, timeout_seconds):
413 request_bytes_remaining = content
414 timeout_time = time.time() + timeout_seconds
415
416 while len(request_bytes_remaining) > 0 and time.time() < timeout_time:
417 _, can_write, _ = select.select([], [sock], [], timeout_seconds)
418 if can_write and sock in can_write:
419 written_byte_count = sock.send(request_bytes_remaining)
420 request_bytes_remaining = request_bytes_remaining[written_byte_count:]
421 self.assertEquals(len(request_bytes_remaining), 0)
422
423 def do_handshake(self, stub_socket, timeout_seconds=5):
424 # Write the ack.
425 self.expect_socket_send(stub_socket, "+", timeout_seconds)
426
427 # Send the start no ack mode packet.
428 NO_ACK_MODE_REQUEST = "$QStartNoAckMode#b0"
429 bytes_sent = stub_socket.send(NO_ACK_MODE_REQUEST)
430 self.assertEquals(bytes_sent, len(NO_ACK_MODE_REQUEST))
431
432 # Receive the ack and "OK"
433 self.expect_socket_recv(stub_socket, re.compile(r"^\+\$OK#[0-9a-fA-F]{2}$"), timeout_seconds)
434
435 # Send the final ack.
436 self.expect_socket_send(stub_socket, "+", timeout_seconds)
437
Todd Fialae50b2e42014-06-13 19:11:33 +0000438 def add_no_ack_remote_stream(self):
439 self.test_sequence.add_log_lines(
440 ["read packet: +",
441 "read packet: $QStartNoAckMode#b0",
442 "send packet: +",
443 "send packet: $OK#9a",
444 "read packet: +"],
445 True)
446
447 def add_verified_launch_packets(self, launch_args):
448 self.test_sequence.add_log_lines(
449 ["read packet: %s" % build_gdbremote_A_packet(launch_args),
450 "send packet: $OK#00",
451 "read packet: $qLaunchSuccess#a5",
452 "send packet: $OK#00"],
453 True)
454
455 def add_thread_suffix_request_packets(self):
456 self.test_sequence.add_log_lines(
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000457 ["read packet: $QThreadSuffixSupported#e4",
Todd Fialae50b2e42014-06-13 19:11:33 +0000458 "send packet: $OK#00",
459 ], True)
460
461 def add_process_info_collection_packets(self):
462 self.test_sequence.add_log_lines(
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000463 ["read packet: $qProcessInfo#dc",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000464 { "direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"process_info_raw"} }],
Todd Fialae50b2e42014-06-13 19:11:33 +0000465 True)
466
467 _KNOWN_PROCESS_INFO_KEYS = [
468 "pid",
469 "parent-pid",
470 "real-uid",
471 "real-gid",
472 "effective-uid",
473 "effective-gid",
474 "cputype",
475 "cpusubtype",
476 "ostype",
Todd Fialac540dd02014-08-26 18:21:02 +0000477 "triple",
Todd Fialae50b2e42014-06-13 19:11:33 +0000478 "vendor",
479 "endian",
480 "ptrsize"
481 ]
482
483 def parse_process_info_response(self, context):
484 # Ensure we have a process info response.
485 self.assertIsNotNone(context)
486 process_info_raw = context.get("process_info_raw")
487 self.assertIsNotNone(process_info_raw)
488
489 # Pull out key:value; pairs.
490 process_info_dict = { match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", process_info_raw) }
491
492 # Validate keys are known.
493 for (key, val) in process_info_dict.items():
494 self.assertTrue(key in self._KNOWN_PROCESS_INFO_KEYS)
495 self.assertIsNotNone(val)
496
497 return process_info_dict
498
499 def add_register_info_collection_packets(self):
500 self.test_sequence.add_log_lines(
501 [ { "type":"multi_response", "query":"qRegisterInfo", "append_iteration_suffix":True,
502 "end_regex":re.compile(r"^\$(E\d+)?#[0-9a-fA-F]{2}$"),
503 "save_key":"reg_info_responses" } ],
504 True)
505
506 def parse_register_info_packets(self, context):
507 """Return an array of register info dictionaries, one per register info."""
508 reg_info_responses = context.get("reg_info_responses")
509 self.assertIsNotNone(reg_info_responses)
510
511 # Parse register infos.
512 return [parse_reg_info_response(reg_info_response) for reg_info_response in reg_info_responses]
513
Todd Fiala50a211b2014-06-14 22:00:36 +0000514 def expect_gdbremote_sequence(self, timeout_seconds=None):
Todd Fiala8aae4f42014-06-13 23:34:17 +0000515 if not timeout_seconds:
516 timeout_seconds = self._TIMEOUT_SECONDS
517 return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, timeout_seconds, self.logger)
Todd Fialae50b2e42014-06-13 19:11:33 +0000518
519 _KNOWN_REGINFO_KEYS = [
520 "name",
521 "alt-name",
522 "bitsize",
523 "offset",
524 "encoding",
525 "format",
526 "set",
527 "gcc",
528 "dwarf",
529 "generic",
530 "container-regs",
531 "invalidate-regs"
532 ]
533
534 def assert_valid_reg_info(self, reg_info):
535 # Assert we know about all the reginfo keys parsed.
536 for key in reg_info:
537 self.assertTrue(key in self._KNOWN_REGINFO_KEYS)
538
539 # Check the bare-minimum expected set of register info keys.
540 self.assertTrue("name" in reg_info)
541 self.assertTrue("bitsize" in reg_info)
542 self.assertTrue("offset" in reg_info)
543 self.assertTrue("encoding" in reg_info)
544 self.assertTrue("format" in reg_info)
545
546 def find_pc_reg_info(self, reg_infos):
547 lldb_reg_index = 0
548 for reg_info in reg_infos:
549 if ("generic" in reg_info) and (reg_info["generic"] == "pc"):
550 return (lldb_reg_index, reg_info)
551 lldb_reg_index += 1
552
553 return (None, None)
554
555 def add_lldb_register_index(self, reg_infos):
556 """Add a "lldb_register_index" key containing the 0-baed index of each reg_infos entry.
557
558 We'll use this when we want to call packets like P/p with a register index but do so
559 on only a subset of the full register info set.
560 """
561 self.assertIsNotNone(reg_infos)
562
563 reg_index = 0
564 for reg_info in reg_infos:
565 reg_info["lldb_register_index"] = reg_index
566 reg_index += 1
567
568 def add_query_memory_region_packets(self, address):
569 self.test_sequence.add_log_lines(
570 ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address),
571 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }],
572 True)
573
Todd Fialac30281a2014-06-14 03:03:23 +0000574 def parse_key_val_dict(self, key_val_text, allow_dupes=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000575 self.assertIsNotNone(key_val_text)
576 kv_dict = {}
577 for match in re.finditer(r";?([^:]+):([^;]+)", key_val_text):
Todd Fialac30281a2014-06-14 03:03:23 +0000578 key = match.group(1)
579 val = match.group(2)
580 if key in kv_dict:
581 if allow_dupes:
582 if type(kv_dict[key]) == list:
583 kv_dict[key].append(val)
584 else:
585 # Promote to list
586 kv_dict[key] = [kv_dict[key], val]
587 else:
588 self.fail("key '{}' already present when attempting to add value '{}' (text='{}', dict={})".format(key, val, key_val_text, kv_dict))
589 else:
590 kv_dict[key] = val
Todd Fialae50b2e42014-06-13 19:11:33 +0000591 return kv_dict
592
593 def parse_memory_region_packet(self, context):
594 # Ensure we have a context.
595 self.assertIsNotNone(context.get("memory_region_response"))
596
597 # Pull out key:value; pairs.
598 mem_region_dict = self.parse_key_val_dict(context.get("memory_region_response"))
599
600 # Validate keys are known.
601 for (key, val) in mem_region_dict.items():
602 self.assertTrue(key in ["start", "size", "permissions", "error"])
603 self.assertIsNotNone(val)
604
605 # Return the dictionary of key-value pairs for the memory region.
606 return mem_region_dict
607
608 def assert_address_within_memory_region(self, test_address, mem_region_dict):
609 self.assertIsNotNone(mem_region_dict)
610 self.assertTrue("start" in mem_region_dict)
611 self.assertTrue("size" in mem_region_dict)
612
613 range_start = int(mem_region_dict["start"], 16)
614 range_size = int(mem_region_dict["size"], 16)
615 range_end = range_start + range_size
616
617 if test_address < range_start:
618 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))
619 elif test_address >= range_end:
620 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))
621
622 def add_threadinfo_collection_packets(self):
623 self.test_sequence.add_log_lines(
624 [ { "type":"multi_response", "first_query":"qfThreadInfo", "next_query":"qsThreadInfo",
625 "append_iteration_suffix":False, "end_regex":re.compile(r"^\$(l)?#[0-9a-fA-F]{2}$"),
626 "save_key":"threadinfo_responses" } ],
627 True)
628
629 def parse_threadinfo_packets(self, context):
630 """Return an array of thread ids (decimal ints), one per thread."""
631 threadinfo_responses = context.get("threadinfo_responses")
632 self.assertIsNotNone(threadinfo_responses)
633
634 thread_ids = []
635 for threadinfo_response in threadinfo_responses:
636 new_thread_infos = parse_threadinfo_response(threadinfo_response)
637 thread_ids.extend(new_thread_infos)
638 return thread_ids
639
640 def wait_for_thread_count(self, thread_count, timeout_seconds=3):
641 start_time = time.time()
642 timeout_time = start_time + timeout_seconds
643
644 actual_thread_count = 0
645 while actual_thread_count < thread_count:
646 self.reset_test_sequence()
647 self.add_threadinfo_collection_packets()
648
649 context = self.expect_gdbremote_sequence()
650 self.assertIsNotNone(context)
651
652 threads = self.parse_threadinfo_packets(context)
653 self.assertIsNotNone(threads)
654
655 actual_thread_count = len(threads)
656
657 if time.time() > timeout_time:
658 raise Exception(
659 'timed out after {} seconds while waiting for theads: waiting for at least {} threads, found {}'.format(
660 timeout_seconds, thread_count, actual_thread_count))
661
662 return threads
663
664 def add_set_breakpoint_packets(self, address, do_continue=True, breakpoint_kind=1):
665 self.test_sequence.add_log_lines(
666 [# Set the breakpoint.
667 "read packet: $Z0,{0:x},{1}#00".format(address, breakpoint_kind),
668 # Verify the stub could set it.
669 "send packet: $OK#00",
670 ], True)
671
672 if (do_continue):
673 self.test_sequence.add_log_lines(
674 [# Continue the inferior.
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000675 "read packet: $c#63",
Todd Fialae50b2e42014-06-13 19:11:33 +0000676 # Expect a breakpoint stop report.
677 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
678 ], True)
679
680 def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
681 self.test_sequence.add_log_lines(
682 [# Remove the breakpoint.
683 "read packet: $z0,{0:x},{1}#00".format(address, breakpoint_kind),
684 # Verify the stub could unset it.
685 "send packet: $OK#00",
686 ], True)
687
688 def add_qSupported_packets(self):
689 self.test_sequence.add_log_lines(
690 ["read packet: $qSupported#00",
691 {"direction":"send", "regex":r"^\$(.*)#[0-9a-fA-F]{2}", "capture":{1: "qSupported_response"}},
692 ], True)
693
694 _KNOWN_QSUPPORTED_STUB_FEATURES = [
695 "augmented-libraries-svr4-read",
696 "PacketSize",
697 "QStartNoAckMode",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000698 "QThreadSuffixSupported",
Todd Fiala43ab82c2014-06-15 23:33:09 +0000699 "QListThreadsInStopReply",
Todd Fialae50b2e42014-06-13 19:11:33 +0000700 "qXfer:auxv:read",
701 "qXfer:libraries:read",
702 "qXfer:libraries-svr4:read",
703 ]
704
705 def parse_qSupported_response(self, context):
706 self.assertIsNotNone(context)
707
708 raw_response = context.get("qSupported_response")
709 self.assertIsNotNone(raw_response)
710
711 # For values with key=val, the dict key and vals are set as expected. For feature+, feature- and feature?, the
712 # +,-,? is stripped from the key and set as the value.
713 supported_dict = {}
714 for match in re.finditer(r";?([^=;]+)(=([^;]+))?", raw_response):
715 key = match.group(1)
716 val = match.group(3)
717
718 # key=val: store as is
719 if val and len(val) > 0:
720 supported_dict[key] = val
721 else:
722 if len(key) < 2:
723 raise Exception("singular stub feature is too short: must be stub_feature{+,-,?}")
724 supported_type = key[-1]
725 key = key[:-1]
726 if not supported_type in ["+", "-", "?"]:
727 raise Exception("malformed stub feature: final character {} not in expected set (+,-,?)".format(supported_type))
728 supported_dict[key] = supported_type
729 # Ensure we know the supported element
730 if not key in self._KNOWN_QSUPPORTED_STUB_FEATURES:
731 raise Exception("unknown qSupported stub feature reported: %s" % key)
732
733 return supported_dict
734
735 def run_process_then_stop(self, run_seconds=1):
736 # Tell the stub to continue.
737 self.test_sequence.add_log_lines(
Stephane Sezerb6e81922014-11-20 18:50:46 +0000738 ["read packet: $vCont;c#a8"],
Todd Fialae50b2e42014-06-13 19:11:33 +0000739 True)
740 context = self.expect_gdbremote_sequence()
741
742 # Wait for run_seconds.
743 time.sleep(run_seconds)
744
745 # Send an interrupt, capture a T response.
746 self.reset_test_sequence()
747 self.test_sequence.add_log_lines(
748 ["read packet: {}".format(chr(03)),
749 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result"} }],
750 True)
751 context = self.expect_gdbremote_sequence()
752 self.assertIsNotNone(context)
753 self.assertIsNotNone(context.get("stop_result"))
754
755 return context
756
757 def select_modifiable_register(self, reg_infos):
758 """Find a register that can be read/written freely."""
759 PREFERRED_REGISTER_NAMES = sets.Set(["rax",])
760
761 # First check for the first register from the preferred register name set.
762 alternative_register_index = None
763
764 self.assertIsNotNone(reg_infos)
765 for reg_info in reg_infos:
766 if ("name" in reg_info) and (reg_info["name"] in PREFERRED_REGISTER_NAMES):
767 # We found a preferred register. Use it.
768 return reg_info["lldb_register_index"]
769 if ("generic" in reg_info) and (reg_info["generic"] == "fp"):
770 # A frame pointer register will do as a register to modify temporarily.
771 alternative_register_index = reg_info["lldb_register_index"]
772
773 # We didn't find a preferred register. Return whatever alternative register
774 # we found, if any.
775 return alternative_register_index
776
777 def extract_registers_from_stop_notification(self, stop_key_vals_text):
778 self.assertIsNotNone(stop_key_vals_text)
779 kv_dict = self.parse_key_val_dict(stop_key_vals_text)
780
781 registers = {}
782 for (key, val) in kv_dict.items():
Stephane Sezer5109a792014-11-14 09:46:21 +0000783 if re.match(r"^[0-9a-fA-F]+$", key):
Todd Fialae50b2e42014-06-13 19:11:33 +0000784 registers[int(key, 16)] = val
785 return registers
786
787 def gather_register_infos(self):
788 self.reset_test_sequence()
789 self.add_register_info_collection_packets()
790
791 context = self.expect_gdbremote_sequence()
792 self.assertIsNotNone(context)
793
794 reg_infos = self.parse_register_info_packets(context)
795 self.assertIsNotNone(reg_infos)
796 self.add_lldb_register_index(reg_infos)
797
798 return reg_infos
799
800 def find_generic_register_with_name(self, reg_infos, generic_name):
801 self.assertIsNotNone(reg_infos)
802 for reg_info in reg_infos:
803 if ("generic" in reg_info) and (reg_info["generic"] == generic_name):
804 return reg_info
805 return None
806
Todd Fiala8d7ab8c2014-06-17 16:04:45 +0000807 def decode_gdbremote_binary(self, encoded_bytes):
808 decoded_bytes = ""
809 i = 0
810 while i < len(encoded_bytes):
811 if encoded_bytes[i] == "}":
812 # Handle escaped char.
813 self.assertTrue(i + 1 < len(encoded_bytes))
814 decoded_bytes += chr(ord(encoded_bytes[i+1]) ^ 0x20)
815 i +=2
816 elif encoded_bytes[i] == "*":
817 # Handle run length encoding.
818 self.assertTrue(len(decoded_bytes) > 0)
819 self.assertTrue(i + 1 < len(encoded_bytes))
820 repeat_count = ord(encoded_bytes[i+1]) - 29
821 decoded_bytes += decoded_bytes[-1] * repeat_count
822 i += 2
823 else:
824 decoded_bytes += encoded_bytes[i]
825 i += 1
826 return decoded_bytes
827
828 def build_auxv_dict(self, endian, word_size, auxv_data):
829 self.assertIsNotNone(endian)
830 self.assertIsNotNone(word_size)
831 self.assertIsNotNone(auxv_data)
832
833 auxv_dict = {}
834
835 while len(auxv_data) > 0:
836 # Chop off key.
837 raw_key = auxv_data[:word_size]
838 auxv_data = auxv_data[word_size:]
839
840 # Chop of value.
841 raw_value = auxv_data[:word_size]
842 auxv_data = auxv_data[word_size:]
843
844 # Convert raw text from target endian.
845 key = unpack_endian_binary_string(endian, raw_key)
846 value = unpack_endian_binary_string(endian, raw_value)
847
848 # Handle ending entry.
849 if key == 0:
850 self.assertEquals(value, 0)
851 return auxv_dict
852
853 # The key should not already be present.
854 self.assertFalse(key in auxv_dict)
855 auxv_dict[key] = value
856
857 self.fail("should not reach here - implies required double zero entry not found")
858 return auxv_dict
Todd Fiala51886732014-06-17 22:01:27 +0000859
860 def read_binary_data_in_chunks(self, command_prefix, chunk_length):
861 """Collect command_prefix{offset:x},{chunk_length:x} until a single 'l' or 'l' with data is returned."""
862 offset = 0
863 done = False
864 decoded_data = ""
865
866 while not done:
867 # Grab the next iteration of data.
868 self.reset_test_sequence()
869 self.test_sequence.add_log_lines([
870 "read packet: ${}{:x},{:x}:#00".format(command_prefix, offset, chunk_length),
Todd Fiala4c24eba2014-06-19 17:35:40 +0000871 {"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 +0000872 ], True)
873
874 context = self.expect_gdbremote_sequence()
875 self.assertIsNotNone(context)
876
877 response_type = context.get("response_type")
878 self.assertIsNotNone(response_type)
879 self.assertTrue(response_type in ["l", "m"])
880
881 # Move offset along.
882 offset += chunk_length
883
884 # Figure out if we're done. We're done if the response type is l.
885 done = response_type == "l"
886
887 # Decode binary data.
888 content_raw = context.get("content_raw")
889 if content_raw and len(content_raw) > 0:
890 self.assertIsNotNone(content_raw)
891 decoded_data += self.decode_gdbremote_binary(content_raw)
892 return decoded_data
Todd Fiala4c24eba2014-06-19 17:35:40 +0000893
894 def add_interrupt_packets(self):
895 self.test_sequence.add_log_lines([
896 # Send the intterupt.
897 "read packet: {}".format(chr(03)),
898 # And wait for the stop notification.
899 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", "capture":{1:"stop_signo", 2:"stop_key_val_text" } },
900 ], True)
901
902 def parse_interrupt_packets(self, context):
903 self.assertIsNotNone(context.get("stop_signo"))
904 self.assertIsNotNone(context.get("stop_key_val_text"))
Todd Fiala9846d452014-06-20 17:39:24 +0000905 return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"]))
906
907 def add_QSaveRegisterState_packets(self, thread_id):
908 if thread_id:
909 # Use the thread suffix form.
910 request = "read packet: $QSaveRegisterState;thread:{:x}#00".format(thread_id)
911 else:
912 request = "read packet: $QSaveRegisterState#00"
913
914 self.test_sequence.add_log_lines([
915 request,
916 {"direction":"send", "regex":r"^\$(E?.*)#[0-9a-fA-F]{2}$", "capture":{1:"save_response" } },
917 ], True)
918
919 def parse_QSaveRegisterState_response(self, context):
920 self.assertIsNotNone(context)
921
922 save_response = context.get("save_response")
923 self.assertIsNotNone(save_response)
924
925 if len(save_response) < 1 or save_response[0] == "E":
926 # error received
927 return (False, None)
928 else:
929 return (True, int(save_response))
930
931 def add_QRestoreRegisterState_packets(self, save_id, thread_id=None):
932 if thread_id:
933 # Use the thread suffix form.
934 request = "read packet: $QRestoreRegisterState:{};thread:{:x}#00".format(save_id, thread_id)
935 else:
936 request = "read packet: $QRestoreRegisterState:{}#00".format(save_id)
937
938 self.test_sequence.add_log_lines([
939 request,
940 "send packet: $OK#00"
941 ], True)
942
943 def flip_all_bits_in_each_register_value(self, reg_infos, endian, thread_id=None):
944 self.assertIsNotNone(reg_infos)
945
946 successful_writes = 0
947 failed_writes = 0
948
949 for reg_info in reg_infos:
950 # Use the lldb register index added to the reg info. We're not necessarily
951 # working off a full set of register infos, so an inferred register index could be wrong.
952 reg_index = reg_info["lldb_register_index"]
953 self.assertIsNotNone(reg_index)
954
955 reg_byte_size = int(reg_info["bitsize"])/8
956 self.assertTrue(reg_byte_size > 0)
957
958 # Handle thread suffix.
959 if thread_id:
960 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
961 else:
962 p_request = "read packet: $p{:x}#00".format(reg_index)
963
964 # Read the existing value.
965 self.reset_test_sequence()
966 self.test_sequence.add_log_lines([
967 p_request,
968 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
969 ], True)
970 context = self.expect_gdbremote_sequence()
971 self.assertIsNotNone(context)
972
973 # Verify the response length.
974 p_response = context.get("p_response")
975 self.assertIsNotNone(p_response)
976 initial_reg_value = unpack_register_hex_unsigned(endian, p_response)
977
978 # Flip the value by xoring with all 1s
979 all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) / 8)
980 flipped_bits_int = initial_reg_value ^ int(all_one_bits_raw, 16)
981 # 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)
982
983 # Handle thread suffix for P.
984 if thread_id:
985 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)
986 else:
987 P_request = "read packet: $P{:x}={}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size))
988
989 # Write the flipped value to the register.
990 self.reset_test_sequence()
991 self.test_sequence.add_log_lines([
992 P_request,
993 { "direction":"send", "regex":r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", "capture":{1:"P_response"} },
994 ], True)
995 context = self.expect_gdbremote_sequence()
996 self.assertIsNotNone(context)
997
998 # Determine if the write succeeded. There are a handful of registers that can fail, or partially fail
999 # (e.g. flags, segment selectors, etc.) due to register value restrictions. Don't worry about them
1000 # all flipping perfectly.
1001 P_response = context.get("P_response")
1002 self.assertIsNotNone(P_response)
1003 if P_response == "OK":
1004 successful_writes += 1
1005 else:
1006 failed_writes += 1
1007 # print "reg (index={}, name={}) write FAILED (error: {})".format(reg_index, reg_info["name"], P_response)
1008
1009 # Read back the register value, ensure it matches the flipped value.
1010 if P_response == "OK":
1011 self.reset_test_sequence()
1012 self.test_sequence.add_log_lines([
1013 p_request,
1014 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
1015 ], True)
1016 context = self.expect_gdbremote_sequence()
1017 self.assertIsNotNone(context)
1018
1019 verify_p_response_raw = context.get("p_response")
1020 self.assertIsNotNone(verify_p_response_raw)
1021 verify_bits = unpack_register_hex_unsigned(endian, verify_p_response_raw)
1022
1023 if verify_bits != flipped_bits_int:
1024 # Some registers, like mxcsrmask and others, will permute what's written. Adjust succeed/fail counts.
1025 # print "reg (index={}, name={}): read verify FAILED: wrote {:x}, verify read back {:x}".format(reg_index, reg_info["name"], flipped_bits_int, verify_bits)
1026 successful_writes -= 1
1027 failed_writes +=1
1028
1029 return (successful_writes, failed_writes)
1030
1031 def is_bit_flippable_register(self, reg_info):
1032 if not reg_info:
1033 return False
1034 if not "set" in reg_info:
1035 return False
1036 if reg_info["set"] != "General Purpose Registers":
1037 return False
1038 if ("container-regs" in reg_info) and (len(reg_info["container-regs"]) > 0):
1039 # Don't try to bit flip registers contained in another register.
1040 return False
1041 if re.match("^.s$", reg_info["name"]):
1042 # This is a 2-letter register name that ends in "s", like a segment register.
1043 # Don't try to bit flip these.
1044 return False
1045 # Okay, this looks fine-enough.
1046 return True
1047
1048 def read_register_values(self, reg_infos, endian, thread_id=None):
1049 self.assertIsNotNone(reg_infos)
1050 values = {}
1051
1052 for reg_info in reg_infos:
1053 # We append a register index when load reg infos so we can work with subsets.
1054 reg_index = reg_info.get("lldb_register_index")
1055 self.assertIsNotNone(reg_index)
1056
1057 # Handle thread suffix.
1058 if thread_id:
1059 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
1060 else:
1061 p_request = "read packet: $p{:x}#00".format(reg_index)
1062
1063 # Read it with p.
1064 self.reset_test_sequence()
1065 self.test_sequence.add_log_lines([
1066 p_request,
1067 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
1068 ], True)
1069 context = self.expect_gdbremote_sequence()
1070 self.assertIsNotNone(context)
1071
1072 # Convert value from target endian to integral.
1073 p_response = context.get("p_response")
1074 self.assertIsNotNone(p_response)
1075 self.assertTrue(len(p_response) > 0)
1076 self.assertFalse(p_response[0] == "E")
1077
1078 values[reg_index] = unpack_register_hex_unsigned(endian, p_response)
1079
Todd Fialae2202002014-06-27 22:11:56 +00001080 return values
1081
1082 def add_vCont_query_packets(self):
1083 self.test_sequence.add_log_lines([
Stephane Sezer22ed42e2014-11-13 21:39:24 +00001084 "read packet: $vCont?#49",
Todd Fialae2202002014-06-27 22:11:56 +00001085 {"direction":"send", "regex":r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", "capture":{2:"vCont_query_response" } },
1086 ], True)
1087
1088 def parse_vCont_query_response(self, context):
1089 self.assertIsNotNone(context)
1090 vCont_query_response = context.get("vCont_query_response")
1091
1092 # Handle case of no vCont support at all - in which case the capture group will be none or zero length.
1093 if not vCont_query_response or len(vCont_query_response) == 0:
1094 return {}
1095
1096 return {key:1 for key in vCont_query_response.split(";") if key and len(key) > 0}
1097
1098 def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100, use_Hc_packet=True, step_instruction="s"):
1099 """Used by single step test that appears in a few different contexts."""
1100 single_step_count = 0
1101
1102 while single_step_count < max_step_count:
1103 self.assertIsNotNone(thread_id)
1104
1105 # Build the packet for the single step instruction. We replace {thread}, if present, with the thread_id.
1106 step_packet = "read packet: ${}#00".format(re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction))
1107 # print "\nstep_packet created: {}\n".format(step_packet)
1108
1109 # Single step.
1110 self.reset_test_sequence()
1111 if use_Hc_packet:
1112 self.test_sequence.add_log_lines(
1113 [# Set the continue thread.
1114 "read packet: $Hc{0:x}#00".format(thread_id),
1115 "send packet: $OK#00",
1116 ], True)
1117 self.test_sequence.add_log_lines([
1118 # Single step.
1119 step_packet,
1120 # "read packet: $vCont;s:{0:x}#00".format(thread_id),
1121 # Expect a breakpoint stop report.
1122 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
1123 ], True)
1124 context = self.expect_gdbremote_sequence()
1125 self.assertIsNotNone(context)
1126 self.assertIsNotNone(context.get("stop_signo"))
1127 self.assertEquals(int(context.get("stop_signo"), 16), signal.SIGTRAP)
1128
1129 single_step_count += 1
1130
1131 # See if the predicate is true. If so, we're done.
1132 if predicate(args):
1133 return (True, single_step_count)
1134
1135 # The predicate didn't return true within the runaway step count.
1136 return (False, single_step_count)
1137
1138 def g_c1_c2_contents_are(self, args):
1139 """Used by single step test that appears in a few different contexts."""
1140 g_c1_address = args["g_c1_address"]
1141 g_c2_address = args["g_c2_address"]
1142 expected_g_c1 = args["expected_g_c1"]
1143 expected_g_c2 = args["expected_g_c2"]
1144
1145 # Read g_c1 and g_c2 contents.
1146 self.reset_test_sequence()
1147 self.test_sequence.add_log_lines(
1148 ["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1),
1149 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c1_contents"} },
1150 "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1),
1151 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c2_contents"} }],
1152 True)
1153
1154 # Run the packet stream.
1155 context = self.expect_gdbremote_sequence()
1156 self.assertIsNotNone(context)
1157
1158 # Check if what we read from inferior memory is what we are expecting.
1159 self.assertIsNotNone(context.get("g_c1_contents"))
1160 self.assertIsNotNone(context.get("g_c2_contents"))
1161
1162 return (context.get("g_c1_contents").decode("hex") == expected_g_c1) and (context.get("g_c2_contents").decode("hex") == expected_g_c2)
1163
1164 def single_step_only_steps_one_instruction(self, use_Hc_packet=True, step_instruction="s"):
1165 """Used by single step test that appears in a few different contexts."""
1166 # Start up the inferior.
1167 procs = self.prep_debug_monitor_and_inferior(
1168 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"])
1169
1170 # Run the process
1171 self.test_sequence.add_log_lines(
1172 [# Start running after initial stop.
Stephane Sezer22ed42e2014-11-13 21:39:24 +00001173 "read packet: $c#63",
Todd Fialae2202002014-06-27 22:11:56 +00001174 # Match output line that prints the memory address of the function call entry point.
1175 # Note we require launch-only testing so we can get inferior otuput.
1176 { "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$",
1177 "capture":{ 1:"function_address", 2:"g_c1_address", 3:"g_c2_address"} },
1178 # Now stop the inferior.
1179 "read packet: {}".format(chr(03)),
1180 # And wait for the stop notification.
1181 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
1182 True)
1183
1184 # Run the packet stream.
1185 context = self.expect_gdbremote_sequence()
1186 self.assertIsNotNone(context)
1187
1188 # Grab the main thread id.
1189 self.assertIsNotNone(context.get("stop_thread_id"))
1190 main_thread_id = int(context.get("stop_thread_id"), 16)
1191
1192 # Grab the function address.
1193 self.assertIsNotNone(context.get("function_address"))
1194 function_address = int(context.get("function_address"), 16)
1195
1196 # Grab the data addresses.
1197 self.assertIsNotNone(context.get("g_c1_address"))
1198 g_c1_address = int(context.get("g_c1_address"), 16)
1199
1200 self.assertIsNotNone(context.get("g_c2_address"))
1201 g_c2_address = int(context.get("g_c2_address"), 16)
1202
1203 # Set a breakpoint at the given address.
1204 # Note this might need to be switched per platform (ARM, mips, etc.).
1205 BREAKPOINT_KIND = 1
1206 self.reset_test_sequence()
1207 self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
1208 context = self.expect_gdbremote_sequence()
1209 self.assertIsNotNone(context)
1210
1211 # Remove the breakpoint.
1212 self.reset_test_sequence()
1213 self.add_remove_breakpoint_packets(function_address, breakpoint_kind=BREAKPOINT_KIND)
1214 context = self.expect_gdbremote_sequence()
1215 self.assertIsNotNone(context)
1216
1217 # Verify g_c1 and g_c2 match expected initial state.
1218 args = {}
1219 args["g_c1_address"] = g_c1_address
1220 args["g_c2_address"] = g_c2_address
1221 args["expected_g_c1"] = "0"
1222 args["expected_g_c2"] = "1"
1223
1224 self.assertTrue(self.g_c1_c2_contents_are(args))
1225
1226 # Verify we take only a small number of steps to hit the first state. Might need to work through function entry prologue code.
1227 args["expected_g_c1"] = "1"
1228 args["expected_g_c2"] = "1"
1229 (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)
1230 self.assertTrue(state_reached)
1231
1232 # Verify we hit the next state.
1233 args["expected_g_c1"] = "1"
1234 args["expected_g_c2"] = "0"
1235 (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)
1236 self.assertTrue(state_reached)
1237 self.assertEquals(step_count, 1)
1238
1239 # Verify we hit the next state.
1240 args["expected_g_c1"] = "0"
1241 args["expected_g_c2"] = "0"
1242 (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)
1243 self.assertTrue(state_reached)
1244 self.assertEquals(step_count, 1)
1245
1246 # Verify we hit the next state.
1247 args["expected_g_c1"] = "0"
1248 args["expected_g_c2"] = "1"
1249 (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)
1250 self.assertTrue(state_reached)
1251 self.assertEquals(step_count, 1)
Todd Fialaaf245d12014-06-30 21:05:18 +00001252