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