blob: 658487ad4a0caf6bc1cdb3082f185e0c68d583e0 [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 else:
166 self.debug_monitor_exe = get_lldb_server_exe()
167 if not self.debug_monitor_exe:
168 self.skipTest("lldb-server exe not found")
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000169
Vince Harronf1ff3c12015-05-10 18:02:53 +0000170 self.debug_monitor_extra_args = ["gdbserver"]
Todd Fiala24189d42014-07-14 06:24:44 +0000171 if use_named_pipe:
172 (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
Todd Fialae50b2e42014-06-13 19:11:33 +0000173
Todd Fiala24189d42014-07-14 06:24:44 +0000174 def init_debugserver_test(self, use_named_pipe=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000175 self.debug_monitor_exe = get_debugserver_exe()
176 if not self.debug_monitor_exe:
177 self.skipTest("debugserver exe not found")
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000178 self.debug_monitor_extra_args = ["--log-file=/tmp/packets-{}.log".format(self._testMethodName), "--log-flags=0x800000"]
Todd Fiala24189d42014-07-14 06:24:44 +0000179 if use_named_pipe:
180 (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
Todd Fialaf9ad21d2014-07-16 16:15:42 +0000181 # The debugserver stub has a race on handling the 'k' command, so it sends an X09 right away, then sends the real X notification
182 # when the process truly dies.
183 self.stub_sends_two_stop_notifications_on_kill = True
Todd Fialae50b2e42014-06-13 19:11:33 +0000184
Chaoren Lin28b8ea12015-05-07 01:42:53 +0000185 def forward_adb_port(self, source, target, direction, device):
186 adb = [ 'adb' ] + ([ '-s', device ] if device else []) + [ direction ]
Tamas Berghammer27c8d362015-03-13 14:32:25 +0000187 def remove_port_forward():
Chaoren Lin28b8ea12015-05-07 01:42:53 +0000188 subprocess.call(adb + [ "--remove", "tcp:%d" % source])
189
190 subprocess.call(adb + [ "tcp:%d" % source, "tcp:%d" % target])
Tamas Berghammer27c8d362015-03-13 14:32:25 +0000191 self.addTearDownHook(remove_port_forward)
192
Todd Fialae50b2e42014-06-13 19:11:33 +0000193 def create_socket(self):
194 sock = socket.socket()
195 logger = self.logger
196
Tamas Berghammerde786792015-03-30 10:52:32 +0000197 triple = self.dbg.GetSelectedPlatform().GetTriple()
198 if re.match(".*-.*-.*-android", triple):
Chaoren Lin28b8ea12015-05-07 01:42:53 +0000199 self.forward_adb_port(self.port, self.port, "forward", self.stub_device)
Tamas Berghammerde786792015-03-30 10:52:32 +0000200
201 connect_info = (self.stub_hostname, self.port)
202 sock.connect(connect_info)
203
Todd Fialae50b2e42014-06-13 19:11:33 +0000204 def shutdown_socket():
205 if sock:
206 try:
Robert Flack8cc4cf12015-03-06 14:36:33 +0000207 # send the kill packet so lldb-server shuts down gracefully
Todd Fialae50b2e42014-06-13 19:11:33 +0000208 sock.sendall(GdbRemoteTestCaseBase._GDBREMOTE_KILL_PACKET)
209 except:
210 logger.warning("failed to send kill packet to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
211
212 try:
213 sock.close()
214 except:
215 logger.warning("failed to close socket to debug monitor: {}; ignoring".format(sys.exc_info()[0]))
216
217 self.addTearDownHook(shutdown_socket)
218
Todd Fialae50b2e42014-06-13 19:11:33 +0000219 return sock
220
221 def set_inferior_startup_launch(self):
222 self._inferior_startup = self._STARTUP_LAUNCH
223
224 def set_inferior_startup_attach(self):
225 self._inferior_startup = self._STARTUP_ATTACH
226
Todd Fiala7306cf32014-07-29 22:30:01 +0000227 def set_inferior_startup_attach_manually(self):
228 self._inferior_startup = self._STARTUP_ATTACH_MANUALLY
229
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000230 def get_debug_monitor_command_line_args(self, attach_pid=None):
Tamas Berghammerde786792015-03-30 10:52:32 +0000231 if lldb.remote_platform:
232 commandline_args = self.debug_monitor_extra_args + ["*:{}".format(self.port)]
233 else:
234 commandline_args = self.debug_monitor_extra_args + ["localhost:{}".format(self.port)]
235
Todd Fialae50b2e42014-06-13 19:11:33 +0000236 if attach_pid:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000237 commandline_args += ["--attach=%d" % attach_pid]
Todd Fiala67041192014-07-11 22:50:13 +0000238 if self.named_pipe_path:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000239 commandline_args += ["--named-pipe", self.named_pipe_path]
240 return commandline_args
241
242 def run_platform_command(self, cmd):
243 platform = self.dbg.GetSelectedPlatform()
244 shell_command = lldb.SBPlatformShellCommand(cmd)
245 err = platform.Run(shell_command)
246 return (err, shell_command.GetOutput())
Todd Fiala31bde322014-07-26 20:39:17 +0000247
248 def launch_debug_monitor(self, attach_pid=None, logfile=None):
249 # Create the command line.
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000250 commandline_args = self.get_debug_monitor_command_line_args(attach_pid=attach_pid)
Todd Fialae50b2e42014-06-13 19:11:33 +0000251
Todd Fiala8aae4f42014-06-13 23:34:17 +0000252 # Start the server.
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000253 server = self.spawnSubprocess(self.debug_monitor_exe, commandline_args, install_remote=False)
254 self.addTearDownHook(self.cleanupSubprocesses)
Todd Fiala24189d42014-07-14 06:24:44 +0000255 self.assertIsNotNone(server)
Todd Fiala24189d42014-07-14 06:24:44 +0000256
257 # If we're receiving the stub's listening port from the named pipe, do that here.
258 if self.named_pipe:
259 self.port = self.get_stub_port_from_named_socket()
Todd Fialae50b2e42014-06-13 19:11:33 +0000260
Todd Fiala8aae4f42014-06-13 23:34:17 +0000261 return server
262
263 def connect_to_debug_monitor(self, attach_pid=None):
Todd Fiala24189d42014-07-14 06:24:44 +0000264 if self.named_pipe:
265 # Create the stub.
266 server = self.launch_debug_monitor(attach_pid=attach_pid)
267 self.assertIsNotNone(server)
268
269 def shutdown_debug_monitor():
270 try:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000271 server.terminate()
Todd Fiala24189d42014-07-14 06:24:44 +0000272 except:
Ilia K7c1d91d2015-04-15 13:08:35 +0000273 logger.warning("failed to terminate server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
Todd Fiala24189d42014-07-14 06:24:44 +0000274 self.addTearDownHook(shutdown_debug_monitor)
275
276 # Schedule debug monitor to be shut down during teardown.
277 logger = self.logger
278
279 # Attach to the stub and return a socket opened to it.
280 self.sock = self.create_socket()
281 return server
282
283 # We're using a random port algorithm to try not to collide with other ports,
284 # and retry a max # times.
Todd Fiala8aae4f42014-06-13 23:34:17 +0000285 attempts = 0
286 MAX_ATTEMPTS = 20
Todd Fialae50b2e42014-06-13 19:11:33 +0000287
Todd Fiala8aae4f42014-06-13 23:34:17 +0000288 while attempts < MAX_ATTEMPTS:
Todd Fiala9e2d3292014-07-09 23:10:43 +0000289 server = self.launch_debug_monitor(attach_pid=attach_pid)
290
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000291 # Schedule debug monitor to be shut down during teardown.
292 logger = self.logger
293 def shutdown_debug_monitor():
Todd Fiala9e2d3292014-07-09 23:10:43 +0000294 try:
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000295 server.terminate()
296 except:
297 logger.warning("failed to terminate server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
298 self.addTearDownHook(shutdown_debug_monitor)
299
Tamas Berghammerde786792015-03-30 10:52:32 +0000300 connect_attemps = 0
301 MAX_CONNECT_ATTEMPTS = 10
302
303 while connect_attemps < MAX_CONNECT_ATTEMPTS:
304 # Create a socket to talk to the server
305 try:
306 self.sock = self.create_socket()
307 return server
308 except socket.error as serr:
309 # We're only trying to handle connection refused.
310 if serr.errno != errno.ECONNREFUSED:
311 raise serr
312 time.sleep(0.5)
313 connect_attemps += 1
314
315 # We should close the server here to be safe.
316 server.terminate()
Todd Fiala9e2d3292014-07-09 23:10:43 +0000317
318 # Increment attempts.
319 print("connect to debug monitor on port %d failed, attempt #%d of %d" % (self.port, attempts + 1, MAX_ATTEMPTS))
320 attempts += 1
321
322 # And wait a random length of time before next attempt, to avoid collisions.
323 time.sleep(random.randint(1,5))
324
325 # Now grab a new port number.
326 self.port = self.get_next_port()
Todd Fiala8aae4f42014-06-13 23:34:17 +0000327
328 raise Exception("failed to create a socket to the launched debug monitor after %d tries" % attempts)
Todd Fialae50b2e42014-06-13 19:11:33 +0000329
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000330 def launch_process_for_attach(self, inferior_args=None, sleep_seconds=3, exe_path=None):
Todd Fialae50b2e42014-06-13 19:11:33 +0000331 # We're going to start a child process that the debug monitor stub can later attach to.
332 # This process needs to be started so that it just hangs around for a while. We'll
333 # have it sleep.
Todd Fiala58a2f662014-08-12 17:02:07 +0000334 if not exe_path:
335 exe_path = os.path.abspath("a.out")
Todd Fialae50b2e42014-06-13 19:11:33 +0000336
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000337 args = []
Todd Fialae50b2e42014-06-13 19:11:33 +0000338 if inferior_args:
339 args.extend(inferior_args)
340 if sleep_seconds:
341 args.append("sleep:%d" % sleep_seconds)
342
Ilia K7c1d91d2015-04-15 13:08:35 +0000343 inferior = self.spawnSubprocess(exe_path, args)
344 def shutdown_process_for_attach():
345 try:
346 inferior.terminate()
347 except:
348 logger.warning("failed to terminate inferior process for attach: {}; ignoring".format(sys.exc_info()[0]))
349 self.addTearDownHook(shutdown_process_for_attach)
350 return inferior
Todd Fialae50b2e42014-06-13 19:11:33 +0000351
Todd Fiala58a2f662014-08-12 17:02:07 +0000352 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 +0000353 """Prep the debug monitor, the inferior, and the expected packet stream.
354
355 Handle the separate cases of using the debug monitor in attach-to-inferior mode
356 and in launch-inferior mode.
357
358 For attach-to-inferior mode, the inferior process is first started, then
359 the debug monitor is started in attach to pid mode (using --attach on the
360 stub command line), and the no-ack-mode setup is appended to the packet
361 stream. The packet stream is not yet executed, ready to have more expected
362 packet entries added to it.
363
364 For launch-inferior mode, the stub is first started, then no ack mode is
365 setup on the expected packet stream, then the verified launch packets are added
366 to the expected socket stream. The packet stream is not yet executed, ready
367 to have more expected packet entries added to it.
368
369 The return value is:
370 {inferior:<inferior>, server:<server>}
371 """
372 inferior = None
373 attach_pid = None
374
Todd Fiala7306cf32014-07-29 22:30:01 +0000375 if self._inferior_startup == self._STARTUP_ATTACH or self._inferior_startup == self._STARTUP_ATTACH_MANUALLY:
Todd Fialae50b2e42014-06-13 19:11:33 +0000376 # Launch the process that we'll use as the inferior.
Todd Fiala58a2f662014-08-12 17:02:07 +0000377 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 +0000378 self.assertIsNotNone(inferior)
379 self.assertTrue(inferior.pid > 0)
Todd Fiala7306cf32014-07-29 22:30:01 +0000380 if self._inferior_startup == self._STARTUP_ATTACH:
381 # In this case, we want the stub to attach via the command line, so set the command line attach pid here.
382 attach_pid = inferior.pid
Todd Fialae50b2e42014-06-13 19:11:33 +0000383
Todd Fialae50b2e42014-06-13 19:11:33 +0000384 if self._inferior_startup == self._STARTUP_LAUNCH:
385 # Build launch args
Todd Fiala58a2f662014-08-12 17:02:07 +0000386 if not inferior_exe_path:
387 inferior_exe_path = os.path.abspath("a.out")
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000388
389 if lldb.remote_platform:
Chaoren Lin3e2bdb42015-05-11 17:53:39 +0000390 remote_path = lldbutil.append_to_remote_wd(os.path.basename(inferior_exe_path))
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000391 remote_file_spec = lldb.SBFileSpec(remote_path, False)
392 err = lldb.remote_platform.Install(lldb.SBFileSpec(inferior_exe_path, True), remote_file_spec)
393 if err.Fail():
394 raise Exception("remote_platform.Install('%s', '%s') failed: %s" % (inferior_exe_path, remote_path, err))
395 inferior_exe_path = remote_path
396
Todd Fiala58a2f662014-08-12 17:02:07 +0000397 launch_args = [inferior_exe_path]
Todd Fialae50b2e42014-06-13 19:11:33 +0000398 if inferior_args:
399 launch_args.extend(inferior_args)
400
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000401 # Launch the debug monitor stub, attaching to the inferior.
402 server = self.connect_to_debug_monitor(attach_pid=attach_pid)
403 self.assertIsNotNone(server)
404
Todd Fialae50b2e42014-06-13 19:11:33 +0000405 # Build the expected protocol stream
406 self.add_no_ack_remote_stream()
407 if self._inferior_startup == self._STARTUP_LAUNCH:
408 self.add_verified_launch_packets(launch_args)
409
410 return {"inferior":inferior, "server":server}
411
Todd Fiala31bde322014-07-26 20:39:17 +0000412 def expect_socket_recv(self, sock, expected_content_regex, timeout_seconds):
413 response = ""
414 timeout_time = time.time() + timeout_seconds
415
416 while not expected_content_regex.match(response) and time.time() < timeout_time:
417 can_read, _, _ = select.select([sock], [], [], timeout_seconds)
418 if can_read and sock in can_read:
419 recv_bytes = sock.recv(4096)
420 if recv_bytes:
421 response += recv_bytes
422
423 self.assertTrue(expected_content_regex.match(response))
424
425 def expect_socket_send(self, sock, content, timeout_seconds):
426 request_bytes_remaining = content
427 timeout_time = time.time() + timeout_seconds
428
429 while len(request_bytes_remaining) > 0 and time.time() < timeout_time:
430 _, can_write, _ = select.select([], [sock], [], timeout_seconds)
431 if can_write and sock in can_write:
432 written_byte_count = sock.send(request_bytes_remaining)
433 request_bytes_remaining = request_bytes_remaining[written_byte_count:]
434 self.assertEquals(len(request_bytes_remaining), 0)
435
436 def do_handshake(self, stub_socket, timeout_seconds=5):
437 # Write the ack.
438 self.expect_socket_send(stub_socket, "+", timeout_seconds)
439
440 # Send the start no ack mode packet.
441 NO_ACK_MODE_REQUEST = "$QStartNoAckMode#b0"
442 bytes_sent = stub_socket.send(NO_ACK_MODE_REQUEST)
443 self.assertEquals(bytes_sent, len(NO_ACK_MODE_REQUEST))
444
445 # Receive the ack and "OK"
446 self.expect_socket_recv(stub_socket, re.compile(r"^\+\$OK#[0-9a-fA-F]{2}$"), timeout_seconds)
447
448 # Send the final ack.
449 self.expect_socket_send(stub_socket, "+", timeout_seconds)
450
Todd Fialae50b2e42014-06-13 19:11:33 +0000451 def add_no_ack_remote_stream(self):
452 self.test_sequence.add_log_lines(
453 ["read packet: +",
454 "read packet: $QStartNoAckMode#b0",
455 "send packet: +",
456 "send packet: $OK#9a",
457 "read packet: +"],
458 True)
459
460 def add_verified_launch_packets(self, launch_args):
461 self.test_sequence.add_log_lines(
462 ["read packet: %s" % build_gdbremote_A_packet(launch_args),
463 "send packet: $OK#00",
464 "read packet: $qLaunchSuccess#a5",
465 "send packet: $OK#00"],
466 True)
467
468 def add_thread_suffix_request_packets(self):
469 self.test_sequence.add_log_lines(
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000470 ["read packet: $QThreadSuffixSupported#e4",
Todd Fialae50b2e42014-06-13 19:11:33 +0000471 "send packet: $OK#00",
472 ], True)
473
474 def add_process_info_collection_packets(self):
475 self.test_sequence.add_log_lines(
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000476 ["read packet: $qProcessInfo#dc",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000477 { "direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"process_info_raw"} }],
Todd Fialae50b2e42014-06-13 19:11:33 +0000478 True)
479
480 _KNOWN_PROCESS_INFO_KEYS = [
481 "pid",
482 "parent-pid",
483 "real-uid",
484 "real-gid",
485 "effective-uid",
486 "effective-gid",
487 "cputype",
488 "cpusubtype",
489 "ostype",
Todd Fialac540dd02014-08-26 18:21:02 +0000490 "triple",
Todd Fialae50b2e42014-06-13 19:11:33 +0000491 "vendor",
492 "endian",
493 "ptrsize"
494 ]
495
496 def parse_process_info_response(self, context):
497 # Ensure we have a process info response.
498 self.assertIsNotNone(context)
499 process_info_raw = context.get("process_info_raw")
500 self.assertIsNotNone(process_info_raw)
501
502 # Pull out key:value; pairs.
503 process_info_dict = { match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", process_info_raw) }
504
505 # Validate keys are known.
506 for (key, val) in process_info_dict.items():
507 self.assertTrue(key in self._KNOWN_PROCESS_INFO_KEYS)
508 self.assertIsNotNone(val)
509
510 return process_info_dict
511
512 def add_register_info_collection_packets(self):
513 self.test_sequence.add_log_lines(
514 [ { "type":"multi_response", "query":"qRegisterInfo", "append_iteration_suffix":True,
515 "end_regex":re.compile(r"^\$(E\d+)?#[0-9a-fA-F]{2}$"),
516 "save_key":"reg_info_responses" } ],
517 True)
518
519 def parse_register_info_packets(self, context):
520 """Return an array of register info dictionaries, one per register info."""
521 reg_info_responses = context.get("reg_info_responses")
522 self.assertIsNotNone(reg_info_responses)
523
524 # Parse register infos.
525 return [parse_reg_info_response(reg_info_response) for reg_info_response in reg_info_responses]
526
Todd Fiala50a211b2014-06-14 22:00:36 +0000527 def expect_gdbremote_sequence(self, timeout_seconds=None):
Todd Fiala8aae4f42014-06-13 23:34:17 +0000528 if not timeout_seconds:
529 timeout_seconds = self._TIMEOUT_SECONDS
530 return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, timeout_seconds, self.logger)
Todd Fialae50b2e42014-06-13 19:11:33 +0000531
532 _KNOWN_REGINFO_KEYS = [
533 "name",
534 "alt-name",
535 "bitsize",
536 "offset",
537 "encoding",
538 "format",
539 "set",
540 "gcc",
541 "dwarf",
542 "generic",
543 "container-regs",
544 "invalidate-regs"
545 ]
546
547 def assert_valid_reg_info(self, reg_info):
548 # Assert we know about all the reginfo keys parsed.
549 for key in reg_info:
550 self.assertTrue(key in self._KNOWN_REGINFO_KEYS)
551
552 # Check the bare-minimum expected set of register info keys.
553 self.assertTrue("name" in reg_info)
554 self.assertTrue("bitsize" in reg_info)
555 self.assertTrue("offset" in reg_info)
556 self.assertTrue("encoding" in reg_info)
557 self.assertTrue("format" in reg_info)
558
559 def find_pc_reg_info(self, reg_infos):
560 lldb_reg_index = 0
561 for reg_info in reg_infos:
562 if ("generic" in reg_info) and (reg_info["generic"] == "pc"):
563 return (lldb_reg_index, reg_info)
564 lldb_reg_index += 1
565
566 return (None, None)
567
568 def add_lldb_register_index(self, reg_infos):
569 """Add a "lldb_register_index" key containing the 0-baed index of each reg_infos entry.
570
571 We'll use this when we want to call packets like P/p with a register index but do so
572 on only a subset of the full register info set.
573 """
574 self.assertIsNotNone(reg_infos)
575
576 reg_index = 0
577 for reg_info in reg_infos:
578 reg_info["lldb_register_index"] = reg_index
579 reg_index += 1
580
581 def add_query_memory_region_packets(self, address):
582 self.test_sequence.add_log_lines(
583 ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address),
584 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }],
585 True)
586
Todd Fialac30281a2014-06-14 03:03:23 +0000587 def parse_key_val_dict(self, key_val_text, allow_dupes=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000588 self.assertIsNotNone(key_val_text)
589 kv_dict = {}
590 for match in re.finditer(r";?([^:]+):([^;]+)", key_val_text):
Todd Fialac30281a2014-06-14 03:03:23 +0000591 key = match.group(1)
592 val = match.group(2)
593 if key in kv_dict:
594 if allow_dupes:
595 if type(kv_dict[key]) == list:
596 kv_dict[key].append(val)
597 else:
598 # Promote to list
599 kv_dict[key] = [kv_dict[key], val]
600 else:
601 self.fail("key '{}' already present when attempting to add value '{}' (text='{}', dict={})".format(key, val, key_val_text, kv_dict))
602 else:
603 kv_dict[key] = val
Todd Fialae50b2e42014-06-13 19:11:33 +0000604 return kv_dict
605
606 def parse_memory_region_packet(self, context):
607 # Ensure we have a context.
608 self.assertIsNotNone(context.get("memory_region_response"))
609
610 # Pull out key:value; pairs.
611 mem_region_dict = self.parse_key_val_dict(context.get("memory_region_response"))
612
613 # Validate keys are known.
614 for (key, val) in mem_region_dict.items():
615 self.assertTrue(key in ["start", "size", "permissions", "error"])
616 self.assertIsNotNone(val)
617
618 # Return the dictionary of key-value pairs for the memory region.
619 return mem_region_dict
620
621 def assert_address_within_memory_region(self, test_address, mem_region_dict):
622 self.assertIsNotNone(mem_region_dict)
623 self.assertTrue("start" in mem_region_dict)
624 self.assertTrue("size" in mem_region_dict)
625
626 range_start = int(mem_region_dict["start"], 16)
627 range_size = int(mem_region_dict["size"], 16)
628 range_end = range_start + range_size
629
630 if test_address < range_start:
631 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))
632 elif test_address >= range_end:
633 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))
634
635 def add_threadinfo_collection_packets(self):
636 self.test_sequence.add_log_lines(
637 [ { "type":"multi_response", "first_query":"qfThreadInfo", "next_query":"qsThreadInfo",
638 "append_iteration_suffix":False, "end_regex":re.compile(r"^\$(l)?#[0-9a-fA-F]{2}$"),
639 "save_key":"threadinfo_responses" } ],
640 True)
641
642 def parse_threadinfo_packets(self, context):
643 """Return an array of thread ids (decimal ints), one per thread."""
644 threadinfo_responses = context.get("threadinfo_responses")
645 self.assertIsNotNone(threadinfo_responses)
646
647 thread_ids = []
648 for threadinfo_response in threadinfo_responses:
649 new_thread_infos = parse_threadinfo_response(threadinfo_response)
650 thread_ids.extend(new_thread_infos)
651 return thread_ids
652
653 def wait_for_thread_count(self, thread_count, timeout_seconds=3):
654 start_time = time.time()
655 timeout_time = start_time + timeout_seconds
656
657 actual_thread_count = 0
658 while actual_thread_count < thread_count:
659 self.reset_test_sequence()
660 self.add_threadinfo_collection_packets()
661
662 context = self.expect_gdbremote_sequence()
663 self.assertIsNotNone(context)
664
665 threads = self.parse_threadinfo_packets(context)
666 self.assertIsNotNone(threads)
667
668 actual_thread_count = len(threads)
669
670 if time.time() > timeout_time:
671 raise Exception(
672 'timed out after {} seconds while waiting for theads: waiting for at least {} threads, found {}'.format(
673 timeout_seconds, thread_count, actual_thread_count))
674
675 return threads
676
677 def add_set_breakpoint_packets(self, address, do_continue=True, breakpoint_kind=1):
678 self.test_sequence.add_log_lines(
679 [# Set the breakpoint.
680 "read packet: $Z0,{0:x},{1}#00".format(address, breakpoint_kind),
681 # Verify the stub could set it.
682 "send packet: $OK#00",
683 ], True)
684
685 if (do_continue):
686 self.test_sequence.add_log_lines(
687 [# Continue the inferior.
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000688 "read packet: $c#63",
Todd Fialae50b2e42014-06-13 19:11:33 +0000689 # Expect a breakpoint stop report.
690 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
691 ], True)
692
693 def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
694 self.test_sequence.add_log_lines(
695 [# Remove the breakpoint.
696 "read packet: $z0,{0:x},{1}#00".format(address, breakpoint_kind),
697 # Verify the stub could unset it.
698 "send packet: $OK#00",
699 ], True)
700
701 def add_qSupported_packets(self):
702 self.test_sequence.add_log_lines(
703 ["read packet: $qSupported#00",
704 {"direction":"send", "regex":r"^\$(.*)#[0-9a-fA-F]{2}", "capture":{1: "qSupported_response"}},
705 ], True)
706
707 _KNOWN_QSUPPORTED_STUB_FEATURES = [
708 "augmented-libraries-svr4-read",
709 "PacketSize",
710 "QStartNoAckMode",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000711 "QThreadSuffixSupported",
Todd Fiala43ab82c2014-06-15 23:33:09 +0000712 "QListThreadsInStopReply",
Todd Fialae50b2e42014-06-13 19:11:33 +0000713 "qXfer:auxv:read",
714 "qXfer:libraries:read",
715 "qXfer:libraries-svr4:read",
716 ]
717
718 def parse_qSupported_response(self, context):
719 self.assertIsNotNone(context)
720
721 raw_response = context.get("qSupported_response")
722 self.assertIsNotNone(raw_response)
723
724 # For values with key=val, the dict key and vals are set as expected. For feature+, feature- and feature?, the
725 # +,-,? is stripped from the key and set as the value.
726 supported_dict = {}
727 for match in re.finditer(r";?([^=;]+)(=([^;]+))?", raw_response):
728 key = match.group(1)
729 val = match.group(3)
730
731 # key=val: store as is
732 if val and len(val) > 0:
733 supported_dict[key] = val
734 else:
735 if len(key) < 2:
736 raise Exception("singular stub feature is too short: must be stub_feature{+,-,?}")
737 supported_type = key[-1]
738 key = key[:-1]
739 if not supported_type in ["+", "-", "?"]:
740 raise Exception("malformed stub feature: final character {} not in expected set (+,-,?)".format(supported_type))
741 supported_dict[key] = supported_type
742 # Ensure we know the supported element
743 if not key in self._KNOWN_QSUPPORTED_STUB_FEATURES:
744 raise Exception("unknown qSupported stub feature reported: %s" % key)
745
746 return supported_dict
747
748 def run_process_then_stop(self, run_seconds=1):
749 # Tell the stub to continue.
750 self.test_sequence.add_log_lines(
Stephane Sezerb6e81922014-11-20 18:50:46 +0000751 ["read packet: $vCont;c#a8"],
Todd Fialae50b2e42014-06-13 19:11:33 +0000752 True)
753 context = self.expect_gdbremote_sequence()
754
755 # Wait for run_seconds.
756 time.sleep(run_seconds)
757
758 # Send an interrupt, capture a T response.
759 self.reset_test_sequence()
760 self.test_sequence.add_log_lines(
761 ["read packet: {}".format(chr(03)),
762 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result"} }],
763 True)
764 context = self.expect_gdbremote_sequence()
765 self.assertIsNotNone(context)
766 self.assertIsNotNone(context.get("stop_result"))
767
768 return context
769
770 def select_modifiable_register(self, reg_infos):
771 """Find a register that can be read/written freely."""
772 PREFERRED_REGISTER_NAMES = sets.Set(["rax",])
773
774 # First check for the first register from the preferred register name set.
775 alternative_register_index = None
776
777 self.assertIsNotNone(reg_infos)
778 for reg_info in reg_infos:
779 if ("name" in reg_info) and (reg_info["name"] in PREFERRED_REGISTER_NAMES):
780 # We found a preferred register. Use it.
781 return reg_info["lldb_register_index"]
782 if ("generic" in reg_info) and (reg_info["generic"] == "fp"):
783 # A frame pointer register will do as a register to modify temporarily.
784 alternative_register_index = reg_info["lldb_register_index"]
785
786 # We didn't find a preferred register. Return whatever alternative register
787 # we found, if any.
788 return alternative_register_index
789
790 def extract_registers_from_stop_notification(self, stop_key_vals_text):
791 self.assertIsNotNone(stop_key_vals_text)
792 kv_dict = self.parse_key_val_dict(stop_key_vals_text)
793
794 registers = {}
795 for (key, val) in kv_dict.items():
Stephane Sezer5109a792014-11-14 09:46:21 +0000796 if re.match(r"^[0-9a-fA-F]+$", key):
Todd Fialae50b2e42014-06-13 19:11:33 +0000797 registers[int(key, 16)] = val
798 return registers
799
800 def gather_register_infos(self):
801 self.reset_test_sequence()
802 self.add_register_info_collection_packets()
803
804 context = self.expect_gdbremote_sequence()
805 self.assertIsNotNone(context)
806
807 reg_infos = self.parse_register_info_packets(context)
808 self.assertIsNotNone(reg_infos)
809 self.add_lldb_register_index(reg_infos)
810
811 return reg_infos
812
813 def find_generic_register_with_name(self, reg_infos, generic_name):
814 self.assertIsNotNone(reg_infos)
815 for reg_info in reg_infos:
816 if ("generic" in reg_info) and (reg_info["generic"] == generic_name):
817 return reg_info
818 return None
819
Todd Fiala8d7ab8c2014-06-17 16:04:45 +0000820 def decode_gdbremote_binary(self, encoded_bytes):
821 decoded_bytes = ""
822 i = 0
823 while i < len(encoded_bytes):
824 if encoded_bytes[i] == "}":
825 # Handle escaped char.
826 self.assertTrue(i + 1 < len(encoded_bytes))
827 decoded_bytes += chr(ord(encoded_bytes[i+1]) ^ 0x20)
828 i +=2
829 elif encoded_bytes[i] == "*":
830 # Handle run length encoding.
831 self.assertTrue(len(decoded_bytes) > 0)
832 self.assertTrue(i + 1 < len(encoded_bytes))
833 repeat_count = ord(encoded_bytes[i+1]) - 29
834 decoded_bytes += decoded_bytes[-1] * repeat_count
835 i += 2
836 else:
837 decoded_bytes += encoded_bytes[i]
838 i += 1
839 return decoded_bytes
840
841 def build_auxv_dict(self, endian, word_size, auxv_data):
842 self.assertIsNotNone(endian)
843 self.assertIsNotNone(word_size)
844 self.assertIsNotNone(auxv_data)
845
846 auxv_dict = {}
847
848 while len(auxv_data) > 0:
849 # Chop off key.
850 raw_key = auxv_data[:word_size]
851 auxv_data = auxv_data[word_size:]
852
853 # Chop of value.
854 raw_value = auxv_data[:word_size]
855 auxv_data = auxv_data[word_size:]
856
857 # Convert raw text from target endian.
858 key = unpack_endian_binary_string(endian, raw_key)
859 value = unpack_endian_binary_string(endian, raw_value)
860
861 # Handle ending entry.
862 if key == 0:
863 self.assertEquals(value, 0)
864 return auxv_dict
865
866 # The key should not already be present.
867 self.assertFalse(key in auxv_dict)
868 auxv_dict[key] = value
869
870 self.fail("should not reach here - implies required double zero entry not found")
871 return auxv_dict
Todd Fiala51886732014-06-17 22:01:27 +0000872
873 def read_binary_data_in_chunks(self, command_prefix, chunk_length):
874 """Collect command_prefix{offset:x},{chunk_length:x} until a single 'l' or 'l' with data is returned."""
875 offset = 0
876 done = False
877 decoded_data = ""
878
879 while not done:
880 # Grab the next iteration of data.
881 self.reset_test_sequence()
882 self.test_sequence.add_log_lines([
883 "read packet: ${}{:x},{:x}:#00".format(command_prefix, offset, chunk_length),
Todd Fiala4c24eba2014-06-19 17:35:40 +0000884 {"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 +0000885 ], True)
886
887 context = self.expect_gdbremote_sequence()
888 self.assertIsNotNone(context)
889
890 response_type = context.get("response_type")
891 self.assertIsNotNone(response_type)
892 self.assertTrue(response_type in ["l", "m"])
893
894 # Move offset along.
895 offset += chunk_length
896
897 # Figure out if we're done. We're done if the response type is l.
898 done = response_type == "l"
899
900 # Decode binary data.
901 content_raw = context.get("content_raw")
902 if content_raw and len(content_raw) > 0:
903 self.assertIsNotNone(content_raw)
904 decoded_data += self.decode_gdbremote_binary(content_raw)
905 return decoded_data
Todd Fiala4c24eba2014-06-19 17:35:40 +0000906
907 def add_interrupt_packets(self):
908 self.test_sequence.add_log_lines([
909 # Send the intterupt.
910 "read packet: {}".format(chr(03)),
911 # And wait for the stop notification.
912 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", "capture":{1:"stop_signo", 2:"stop_key_val_text" } },
913 ], True)
914
915 def parse_interrupt_packets(self, context):
916 self.assertIsNotNone(context.get("stop_signo"))
917 self.assertIsNotNone(context.get("stop_key_val_text"))
Todd Fiala9846d452014-06-20 17:39:24 +0000918 return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"]))
919
920 def add_QSaveRegisterState_packets(self, thread_id):
921 if thread_id:
922 # Use the thread suffix form.
923 request = "read packet: $QSaveRegisterState;thread:{:x}#00".format(thread_id)
924 else:
925 request = "read packet: $QSaveRegisterState#00"
926
927 self.test_sequence.add_log_lines([
928 request,
929 {"direction":"send", "regex":r"^\$(E?.*)#[0-9a-fA-F]{2}$", "capture":{1:"save_response" } },
930 ], True)
931
932 def parse_QSaveRegisterState_response(self, context):
933 self.assertIsNotNone(context)
934
935 save_response = context.get("save_response")
936 self.assertIsNotNone(save_response)
937
938 if len(save_response) < 1 or save_response[0] == "E":
939 # error received
940 return (False, None)
941 else:
942 return (True, int(save_response))
943
944 def add_QRestoreRegisterState_packets(self, save_id, thread_id=None):
945 if thread_id:
946 # Use the thread suffix form.
947 request = "read packet: $QRestoreRegisterState:{};thread:{:x}#00".format(save_id, thread_id)
948 else:
949 request = "read packet: $QRestoreRegisterState:{}#00".format(save_id)
950
951 self.test_sequence.add_log_lines([
952 request,
953 "send packet: $OK#00"
954 ], True)
955
956 def flip_all_bits_in_each_register_value(self, reg_infos, endian, thread_id=None):
957 self.assertIsNotNone(reg_infos)
958
959 successful_writes = 0
960 failed_writes = 0
961
962 for reg_info in reg_infos:
963 # Use the lldb register index added to the reg info. We're not necessarily
964 # working off a full set of register infos, so an inferred register index could be wrong.
965 reg_index = reg_info["lldb_register_index"]
966 self.assertIsNotNone(reg_index)
967
968 reg_byte_size = int(reg_info["bitsize"])/8
969 self.assertTrue(reg_byte_size > 0)
970
971 # Handle thread suffix.
972 if thread_id:
973 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
974 else:
975 p_request = "read packet: $p{:x}#00".format(reg_index)
976
977 # Read the existing value.
978 self.reset_test_sequence()
979 self.test_sequence.add_log_lines([
980 p_request,
981 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
982 ], True)
983 context = self.expect_gdbremote_sequence()
984 self.assertIsNotNone(context)
985
986 # Verify the response length.
987 p_response = context.get("p_response")
988 self.assertIsNotNone(p_response)
989 initial_reg_value = unpack_register_hex_unsigned(endian, p_response)
990
991 # Flip the value by xoring with all 1s
992 all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) / 8)
993 flipped_bits_int = initial_reg_value ^ int(all_one_bits_raw, 16)
994 # 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)
995
996 # Handle thread suffix for P.
997 if thread_id:
998 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)
999 else:
1000 P_request = "read packet: $P{:x}={}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size))
1001
1002 # Write the flipped value to the register.
1003 self.reset_test_sequence()
1004 self.test_sequence.add_log_lines([
1005 P_request,
1006 { "direction":"send", "regex":r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", "capture":{1:"P_response"} },
1007 ], True)
1008 context = self.expect_gdbremote_sequence()
1009 self.assertIsNotNone(context)
1010
1011 # Determine if the write succeeded. There are a handful of registers that can fail, or partially fail
1012 # (e.g. flags, segment selectors, etc.) due to register value restrictions. Don't worry about them
1013 # all flipping perfectly.
1014 P_response = context.get("P_response")
1015 self.assertIsNotNone(P_response)
1016 if P_response == "OK":
1017 successful_writes += 1
1018 else:
1019 failed_writes += 1
1020 # print "reg (index={}, name={}) write FAILED (error: {})".format(reg_index, reg_info["name"], P_response)
1021
1022 # Read back the register value, ensure it matches the flipped value.
1023 if P_response == "OK":
1024 self.reset_test_sequence()
1025 self.test_sequence.add_log_lines([
1026 p_request,
1027 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
1028 ], True)
1029 context = self.expect_gdbremote_sequence()
1030 self.assertIsNotNone(context)
1031
1032 verify_p_response_raw = context.get("p_response")
1033 self.assertIsNotNone(verify_p_response_raw)
1034 verify_bits = unpack_register_hex_unsigned(endian, verify_p_response_raw)
1035
1036 if verify_bits != flipped_bits_int:
1037 # Some registers, like mxcsrmask and others, will permute what's written. Adjust succeed/fail counts.
1038 # print "reg (index={}, name={}): read verify FAILED: wrote {:x}, verify read back {:x}".format(reg_index, reg_info["name"], flipped_bits_int, verify_bits)
1039 successful_writes -= 1
1040 failed_writes +=1
1041
1042 return (successful_writes, failed_writes)
1043
1044 def is_bit_flippable_register(self, reg_info):
1045 if not reg_info:
1046 return False
1047 if not "set" in reg_info:
1048 return False
1049 if reg_info["set"] != "General Purpose Registers":
1050 return False
1051 if ("container-regs" in reg_info) and (len(reg_info["container-regs"]) > 0):
1052 # Don't try to bit flip registers contained in another register.
1053 return False
1054 if re.match("^.s$", reg_info["name"]):
1055 # This is a 2-letter register name that ends in "s", like a segment register.
1056 # Don't try to bit flip these.
1057 return False
1058 # Okay, this looks fine-enough.
1059 return True
1060
1061 def read_register_values(self, reg_infos, endian, thread_id=None):
1062 self.assertIsNotNone(reg_infos)
1063 values = {}
1064
1065 for reg_info in reg_infos:
1066 # We append a register index when load reg infos so we can work with subsets.
1067 reg_index = reg_info.get("lldb_register_index")
1068 self.assertIsNotNone(reg_index)
1069
1070 # Handle thread suffix.
1071 if thread_id:
1072 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
1073 else:
1074 p_request = "read packet: $p{:x}#00".format(reg_index)
1075
1076 # Read it with p.
1077 self.reset_test_sequence()
1078 self.test_sequence.add_log_lines([
1079 p_request,
1080 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
1081 ], True)
1082 context = self.expect_gdbremote_sequence()
1083 self.assertIsNotNone(context)
1084
1085 # Convert value from target endian to integral.
1086 p_response = context.get("p_response")
1087 self.assertIsNotNone(p_response)
1088 self.assertTrue(len(p_response) > 0)
1089 self.assertFalse(p_response[0] == "E")
1090
1091 values[reg_index] = unpack_register_hex_unsigned(endian, p_response)
1092
Todd Fialae2202002014-06-27 22:11:56 +00001093 return values
1094
1095 def add_vCont_query_packets(self):
1096 self.test_sequence.add_log_lines([
Stephane Sezer22ed42e2014-11-13 21:39:24 +00001097 "read packet: $vCont?#49",
Todd Fialae2202002014-06-27 22:11:56 +00001098 {"direction":"send", "regex":r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", "capture":{2:"vCont_query_response" } },
1099 ], True)
1100
1101 def parse_vCont_query_response(self, context):
1102 self.assertIsNotNone(context)
1103 vCont_query_response = context.get("vCont_query_response")
1104
1105 # Handle case of no vCont support at all - in which case the capture group will be none or zero length.
1106 if not vCont_query_response or len(vCont_query_response) == 0:
1107 return {}
1108
1109 return {key:1 for key in vCont_query_response.split(";") if key and len(key) > 0}
1110
1111 def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100, use_Hc_packet=True, step_instruction="s"):
1112 """Used by single step test that appears in a few different contexts."""
1113 single_step_count = 0
1114
1115 while single_step_count < max_step_count:
1116 self.assertIsNotNone(thread_id)
1117
1118 # Build the packet for the single step instruction. We replace {thread}, if present, with the thread_id.
1119 step_packet = "read packet: ${}#00".format(re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction))
1120 # print "\nstep_packet created: {}\n".format(step_packet)
1121
1122 # Single step.
1123 self.reset_test_sequence()
1124 if use_Hc_packet:
1125 self.test_sequence.add_log_lines(
1126 [# Set the continue thread.
1127 "read packet: $Hc{0:x}#00".format(thread_id),
1128 "send packet: $OK#00",
1129 ], True)
1130 self.test_sequence.add_log_lines([
1131 # Single step.
1132 step_packet,
1133 # "read packet: $vCont;s:{0:x}#00".format(thread_id),
1134 # Expect a breakpoint stop report.
1135 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
1136 ], True)
1137 context = self.expect_gdbremote_sequence()
1138 self.assertIsNotNone(context)
1139 self.assertIsNotNone(context.get("stop_signo"))
1140 self.assertEquals(int(context.get("stop_signo"), 16), signal.SIGTRAP)
1141
1142 single_step_count += 1
1143
1144 # See if the predicate is true. If so, we're done.
1145 if predicate(args):
1146 return (True, single_step_count)
1147
1148 # The predicate didn't return true within the runaway step count.
1149 return (False, single_step_count)
1150
1151 def g_c1_c2_contents_are(self, args):
1152 """Used by single step test that appears in a few different contexts."""
1153 g_c1_address = args["g_c1_address"]
1154 g_c2_address = args["g_c2_address"]
1155 expected_g_c1 = args["expected_g_c1"]
1156 expected_g_c2 = args["expected_g_c2"]
1157
1158 # Read g_c1 and g_c2 contents.
1159 self.reset_test_sequence()
1160 self.test_sequence.add_log_lines(
1161 ["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1),
1162 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c1_contents"} },
1163 "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1),
1164 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c2_contents"} }],
1165 True)
1166
1167 # Run the packet stream.
1168 context = self.expect_gdbremote_sequence()
1169 self.assertIsNotNone(context)
1170
1171 # Check if what we read from inferior memory is what we are expecting.
1172 self.assertIsNotNone(context.get("g_c1_contents"))
1173 self.assertIsNotNone(context.get("g_c2_contents"))
1174
1175 return (context.get("g_c1_contents").decode("hex") == expected_g_c1) and (context.get("g_c2_contents").decode("hex") == expected_g_c2)
1176
1177 def single_step_only_steps_one_instruction(self, use_Hc_packet=True, step_instruction="s"):
1178 """Used by single step test that appears in a few different contexts."""
1179 # Start up the inferior.
1180 procs = self.prep_debug_monitor_and_inferior(
1181 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"])
1182
1183 # Run the process
1184 self.test_sequence.add_log_lines(
1185 [# Start running after initial stop.
Stephane Sezer22ed42e2014-11-13 21:39:24 +00001186 "read packet: $c#63",
Todd Fialae2202002014-06-27 22:11:56 +00001187 # Match output line that prints the memory address of the function call entry point.
1188 # Note we require launch-only testing so we can get inferior otuput.
1189 { "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$",
1190 "capture":{ 1:"function_address", 2:"g_c1_address", 3:"g_c2_address"} },
1191 # Now stop the inferior.
1192 "read packet: {}".format(chr(03)),
1193 # And wait for the stop notification.
1194 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
1195 True)
1196
1197 # Run the packet stream.
1198 context = self.expect_gdbremote_sequence()
1199 self.assertIsNotNone(context)
1200
1201 # Grab the main thread id.
1202 self.assertIsNotNone(context.get("stop_thread_id"))
1203 main_thread_id = int(context.get("stop_thread_id"), 16)
1204
1205 # Grab the function address.
1206 self.assertIsNotNone(context.get("function_address"))
1207 function_address = int(context.get("function_address"), 16)
1208
1209 # Grab the data addresses.
1210 self.assertIsNotNone(context.get("g_c1_address"))
1211 g_c1_address = int(context.get("g_c1_address"), 16)
1212
1213 self.assertIsNotNone(context.get("g_c2_address"))
1214 g_c2_address = int(context.get("g_c2_address"), 16)
1215
1216 # Set a breakpoint at the given address.
1217 # Note this might need to be switched per platform (ARM, mips, etc.).
1218 BREAKPOINT_KIND = 1
1219 self.reset_test_sequence()
1220 self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
1221 context = self.expect_gdbremote_sequence()
1222 self.assertIsNotNone(context)
1223
1224 # Remove the breakpoint.
1225 self.reset_test_sequence()
1226 self.add_remove_breakpoint_packets(function_address, breakpoint_kind=BREAKPOINT_KIND)
1227 context = self.expect_gdbremote_sequence()
1228 self.assertIsNotNone(context)
1229
1230 # Verify g_c1 and g_c2 match expected initial state.
1231 args = {}
1232 args["g_c1_address"] = g_c1_address
1233 args["g_c2_address"] = g_c2_address
1234 args["expected_g_c1"] = "0"
1235 args["expected_g_c2"] = "1"
1236
1237 self.assertTrue(self.g_c1_c2_contents_are(args))
1238
1239 # Verify we take only a small number of steps to hit the first state. Might need to work through function entry prologue code.
1240 args["expected_g_c1"] = "1"
1241 args["expected_g_c2"] = "1"
1242 (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)
1243 self.assertTrue(state_reached)
1244
1245 # Verify we hit the next state.
1246 args["expected_g_c1"] = "1"
1247 args["expected_g_c2"] = "0"
1248 (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)
1249 self.assertTrue(state_reached)
1250 self.assertEquals(step_count, 1)
1251
1252 # Verify we hit the next state.
1253 args["expected_g_c1"] = "0"
1254 args["expected_g_c2"] = "0"
1255 (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)
1256 self.assertTrue(state_reached)
1257 self.assertEquals(step_count, 1)
1258
1259 # Verify we hit the next state.
1260 args["expected_g_c1"] = "0"
1261 args["expected_g_c2"] = "1"
1262 (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)
1263 self.assertTrue(state_reached)
1264 self.assertEquals(step_count, 1)
Todd Fialaaf245d12014-06-30 21:05:18 +00001265