blob: 781ca4dadaaa47e547434907692af0aea5728717 [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:
390 remote_work_dir = lldb.remote_platform.GetWorkingDirectory()
391 remote_path = os.path.join(remote_work_dir, os.path.basename(inferior_exe_path))
392 remote_file_spec = lldb.SBFileSpec(remote_path, False)
393 err = lldb.remote_platform.Install(lldb.SBFileSpec(inferior_exe_path, True), remote_file_spec)
394 if err.Fail():
395 raise Exception("remote_platform.Install('%s', '%s') failed: %s" % (inferior_exe_path, remote_path, err))
396 inferior_exe_path = remote_path
397
Todd Fiala58a2f662014-08-12 17:02:07 +0000398 launch_args = [inferior_exe_path]
Todd Fialae50b2e42014-06-13 19:11:33 +0000399 if inferior_args:
400 launch_args.extend(inferior_args)
401
Tamas Berghammer04f51d12015-03-11 13:51:07 +0000402 # Launch the debug monitor stub, attaching to the inferior.
403 server = self.connect_to_debug_monitor(attach_pid=attach_pid)
404 self.assertIsNotNone(server)
405
Todd Fialae50b2e42014-06-13 19:11:33 +0000406 # Build the expected protocol stream
407 self.add_no_ack_remote_stream()
408 if self._inferior_startup == self._STARTUP_LAUNCH:
409 self.add_verified_launch_packets(launch_args)
410
411 return {"inferior":inferior, "server":server}
412
Todd Fiala31bde322014-07-26 20:39:17 +0000413 def expect_socket_recv(self, sock, expected_content_regex, timeout_seconds):
414 response = ""
415 timeout_time = time.time() + timeout_seconds
416
417 while not expected_content_regex.match(response) and time.time() < timeout_time:
418 can_read, _, _ = select.select([sock], [], [], timeout_seconds)
419 if can_read and sock in can_read:
420 recv_bytes = sock.recv(4096)
421 if recv_bytes:
422 response += recv_bytes
423
424 self.assertTrue(expected_content_regex.match(response))
425
426 def expect_socket_send(self, sock, content, timeout_seconds):
427 request_bytes_remaining = content
428 timeout_time = time.time() + timeout_seconds
429
430 while len(request_bytes_remaining) > 0 and time.time() < timeout_time:
431 _, can_write, _ = select.select([], [sock], [], timeout_seconds)
432 if can_write and sock in can_write:
433 written_byte_count = sock.send(request_bytes_remaining)
434 request_bytes_remaining = request_bytes_remaining[written_byte_count:]
435 self.assertEquals(len(request_bytes_remaining), 0)
436
437 def do_handshake(self, stub_socket, timeout_seconds=5):
438 # Write the ack.
439 self.expect_socket_send(stub_socket, "+", timeout_seconds)
440
441 # Send the start no ack mode packet.
442 NO_ACK_MODE_REQUEST = "$QStartNoAckMode#b0"
443 bytes_sent = stub_socket.send(NO_ACK_MODE_REQUEST)
444 self.assertEquals(bytes_sent, len(NO_ACK_MODE_REQUEST))
445
446 # Receive the ack and "OK"
447 self.expect_socket_recv(stub_socket, re.compile(r"^\+\$OK#[0-9a-fA-F]{2}$"), timeout_seconds)
448
449 # Send the final ack.
450 self.expect_socket_send(stub_socket, "+", timeout_seconds)
451
Todd Fialae50b2e42014-06-13 19:11:33 +0000452 def add_no_ack_remote_stream(self):
453 self.test_sequence.add_log_lines(
454 ["read packet: +",
455 "read packet: $QStartNoAckMode#b0",
456 "send packet: +",
457 "send packet: $OK#9a",
458 "read packet: +"],
459 True)
460
461 def add_verified_launch_packets(self, launch_args):
462 self.test_sequence.add_log_lines(
463 ["read packet: %s" % build_gdbremote_A_packet(launch_args),
464 "send packet: $OK#00",
465 "read packet: $qLaunchSuccess#a5",
466 "send packet: $OK#00"],
467 True)
468
469 def add_thread_suffix_request_packets(self):
470 self.test_sequence.add_log_lines(
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000471 ["read packet: $QThreadSuffixSupported#e4",
Todd Fialae50b2e42014-06-13 19:11:33 +0000472 "send packet: $OK#00",
473 ], True)
474
475 def add_process_info_collection_packets(self):
476 self.test_sequence.add_log_lines(
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000477 ["read packet: $qProcessInfo#dc",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000478 { "direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"process_info_raw"} }],
Todd Fialae50b2e42014-06-13 19:11:33 +0000479 True)
480
481 _KNOWN_PROCESS_INFO_KEYS = [
482 "pid",
483 "parent-pid",
484 "real-uid",
485 "real-gid",
486 "effective-uid",
487 "effective-gid",
488 "cputype",
489 "cpusubtype",
490 "ostype",
Todd Fialac540dd02014-08-26 18:21:02 +0000491 "triple",
Todd Fialae50b2e42014-06-13 19:11:33 +0000492 "vendor",
493 "endian",
494 "ptrsize"
495 ]
496
497 def parse_process_info_response(self, context):
498 # Ensure we have a process info response.
499 self.assertIsNotNone(context)
500 process_info_raw = context.get("process_info_raw")
501 self.assertIsNotNone(process_info_raw)
502
503 # Pull out key:value; pairs.
504 process_info_dict = { match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", process_info_raw) }
505
506 # Validate keys are known.
507 for (key, val) in process_info_dict.items():
508 self.assertTrue(key in self._KNOWN_PROCESS_INFO_KEYS)
509 self.assertIsNotNone(val)
510
511 return process_info_dict
512
513 def add_register_info_collection_packets(self):
514 self.test_sequence.add_log_lines(
515 [ { "type":"multi_response", "query":"qRegisterInfo", "append_iteration_suffix":True,
516 "end_regex":re.compile(r"^\$(E\d+)?#[0-9a-fA-F]{2}$"),
517 "save_key":"reg_info_responses" } ],
518 True)
519
520 def parse_register_info_packets(self, context):
521 """Return an array of register info dictionaries, one per register info."""
522 reg_info_responses = context.get("reg_info_responses")
523 self.assertIsNotNone(reg_info_responses)
524
525 # Parse register infos.
526 return [parse_reg_info_response(reg_info_response) for reg_info_response in reg_info_responses]
527
Todd Fiala50a211b2014-06-14 22:00:36 +0000528 def expect_gdbremote_sequence(self, timeout_seconds=None):
Todd Fiala8aae4f42014-06-13 23:34:17 +0000529 if not timeout_seconds:
530 timeout_seconds = self._TIMEOUT_SECONDS
531 return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, timeout_seconds, self.logger)
Todd Fialae50b2e42014-06-13 19:11:33 +0000532
533 _KNOWN_REGINFO_KEYS = [
534 "name",
535 "alt-name",
536 "bitsize",
537 "offset",
538 "encoding",
539 "format",
540 "set",
541 "gcc",
542 "dwarf",
543 "generic",
544 "container-regs",
545 "invalidate-regs"
546 ]
547
548 def assert_valid_reg_info(self, reg_info):
549 # Assert we know about all the reginfo keys parsed.
550 for key in reg_info:
551 self.assertTrue(key in self._KNOWN_REGINFO_KEYS)
552
553 # Check the bare-minimum expected set of register info keys.
554 self.assertTrue("name" in reg_info)
555 self.assertTrue("bitsize" in reg_info)
556 self.assertTrue("offset" in reg_info)
557 self.assertTrue("encoding" in reg_info)
558 self.assertTrue("format" in reg_info)
559
560 def find_pc_reg_info(self, reg_infos):
561 lldb_reg_index = 0
562 for reg_info in reg_infos:
563 if ("generic" in reg_info) and (reg_info["generic"] == "pc"):
564 return (lldb_reg_index, reg_info)
565 lldb_reg_index += 1
566
567 return (None, None)
568
569 def add_lldb_register_index(self, reg_infos):
570 """Add a "lldb_register_index" key containing the 0-baed index of each reg_infos entry.
571
572 We'll use this when we want to call packets like P/p with a register index but do so
573 on only a subset of the full register info set.
574 """
575 self.assertIsNotNone(reg_infos)
576
577 reg_index = 0
578 for reg_info in reg_infos:
579 reg_info["lldb_register_index"] = reg_index
580 reg_index += 1
581
582 def add_query_memory_region_packets(self, address):
583 self.test_sequence.add_log_lines(
584 ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address),
585 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }],
586 True)
587
Todd Fialac30281a2014-06-14 03:03:23 +0000588 def parse_key_val_dict(self, key_val_text, allow_dupes=True):
Todd Fialae50b2e42014-06-13 19:11:33 +0000589 self.assertIsNotNone(key_val_text)
590 kv_dict = {}
591 for match in re.finditer(r";?([^:]+):([^;]+)", key_val_text):
Todd Fialac30281a2014-06-14 03:03:23 +0000592 key = match.group(1)
593 val = match.group(2)
594 if key in kv_dict:
595 if allow_dupes:
596 if type(kv_dict[key]) == list:
597 kv_dict[key].append(val)
598 else:
599 # Promote to list
600 kv_dict[key] = [kv_dict[key], val]
601 else:
602 self.fail("key '{}' already present when attempting to add value '{}' (text='{}', dict={})".format(key, val, key_val_text, kv_dict))
603 else:
604 kv_dict[key] = val
Todd Fialae50b2e42014-06-13 19:11:33 +0000605 return kv_dict
606
607 def parse_memory_region_packet(self, context):
608 # Ensure we have a context.
609 self.assertIsNotNone(context.get("memory_region_response"))
610
611 # Pull out key:value; pairs.
612 mem_region_dict = self.parse_key_val_dict(context.get("memory_region_response"))
613
614 # Validate keys are known.
615 for (key, val) in mem_region_dict.items():
616 self.assertTrue(key in ["start", "size", "permissions", "error"])
617 self.assertIsNotNone(val)
618
619 # Return the dictionary of key-value pairs for the memory region.
620 return mem_region_dict
621
622 def assert_address_within_memory_region(self, test_address, mem_region_dict):
623 self.assertIsNotNone(mem_region_dict)
624 self.assertTrue("start" in mem_region_dict)
625 self.assertTrue("size" in mem_region_dict)
626
627 range_start = int(mem_region_dict["start"], 16)
628 range_size = int(mem_region_dict["size"], 16)
629 range_end = range_start + range_size
630
631 if test_address < range_start:
632 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))
633 elif test_address >= range_end:
634 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))
635
636 def add_threadinfo_collection_packets(self):
637 self.test_sequence.add_log_lines(
638 [ { "type":"multi_response", "first_query":"qfThreadInfo", "next_query":"qsThreadInfo",
639 "append_iteration_suffix":False, "end_regex":re.compile(r"^\$(l)?#[0-9a-fA-F]{2}$"),
640 "save_key":"threadinfo_responses" } ],
641 True)
642
643 def parse_threadinfo_packets(self, context):
644 """Return an array of thread ids (decimal ints), one per thread."""
645 threadinfo_responses = context.get("threadinfo_responses")
646 self.assertIsNotNone(threadinfo_responses)
647
648 thread_ids = []
649 for threadinfo_response in threadinfo_responses:
650 new_thread_infos = parse_threadinfo_response(threadinfo_response)
651 thread_ids.extend(new_thread_infos)
652 return thread_ids
653
654 def wait_for_thread_count(self, thread_count, timeout_seconds=3):
655 start_time = time.time()
656 timeout_time = start_time + timeout_seconds
657
658 actual_thread_count = 0
659 while actual_thread_count < thread_count:
660 self.reset_test_sequence()
661 self.add_threadinfo_collection_packets()
662
663 context = self.expect_gdbremote_sequence()
664 self.assertIsNotNone(context)
665
666 threads = self.parse_threadinfo_packets(context)
667 self.assertIsNotNone(threads)
668
669 actual_thread_count = len(threads)
670
671 if time.time() > timeout_time:
672 raise Exception(
673 'timed out after {} seconds while waiting for theads: waiting for at least {} threads, found {}'.format(
674 timeout_seconds, thread_count, actual_thread_count))
675
676 return threads
677
678 def add_set_breakpoint_packets(self, address, do_continue=True, breakpoint_kind=1):
679 self.test_sequence.add_log_lines(
680 [# Set the breakpoint.
681 "read packet: $Z0,{0:x},{1}#00".format(address, breakpoint_kind),
682 # Verify the stub could set it.
683 "send packet: $OK#00",
684 ], True)
685
686 if (do_continue):
687 self.test_sequence.add_log_lines(
688 [# Continue the inferior.
Stephane Sezer22ed42e2014-11-13 21:39:24 +0000689 "read packet: $c#63",
Todd Fialae50b2e42014-06-13 19:11:33 +0000690 # Expect a breakpoint stop report.
691 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
692 ], True)
693
694 def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
695 self.test_sequence.add_log_lines(
696 [# Remove the breakpoint.
697 "read packet: $z0,{0:x},{1}#00".format(address, breakpoint_kind),
698 # Verify the stub could unset it.
699 "send packet: $OK#00",
700 ], True)
701
702 def add_qSupported_packets(self):
703 self.test_sequence.add_log_lines(
704 ["read packet: $qSupported#00",
705 {"direction":"send", "regex":r"^\$(.*)#[0-9a-fA-F]{2}", "capture":{1: "qSupported_response"}},
706 ], True)
707
708 _KNOWN_QSUPPORTED_STUB_FEATURES = [
709 "augmented-libraries-svr4-read",
710 "PacketSize",
711 "QStartNoAckMode",
Todd Fiala8aae4f42014-06-13 23:34:17 +0000712 "QThreadSuffixSupported",
Todd Fiala43ab82c2014-06-15 23:33:09 +0000713 "QListThreadsInStopReply",
Todd Fialae50b2e42014-06-13 19:11:33 +0000714 "qXfer:auxv:read",
715 "qXfer:libraries:read",
716 "qXfer:libraries-svr4:read",
717 ]
718
719 def parse_qSupported_response(self, context):
720 self.assertIsNotNone(context)
721
722 raw_response = context.get("qSupported_response")
723 self.assertIsNotNone(raw_response)
724
725 # For values with key=val, the dict key and vals are set as expected. For feature+, feature- and feature?, the
726 # +,-,? is stripped from the key and set as the value.
727 supported_dict = {}
728 for match in re.finditer(r";?([^=;]+)(=([^;]+))?", raw_response):
729 key = match.group(1)
730 val = match.group(3)
731
732 # key=val: store as is
733 if val and len(val) > 0:
734 supported_dict[key] = val
735 else:
736 if len(key) < 2:
737 raise Exception("singular stub feature is too short: must be stub_feature{+,-,?}")
738 supported_type = key[-1]
739 key = key[:-1]
740 if not supported_type in ["+", "-", "?"]:
741 raise Exception("malformed stub feature: final character {} not in expected set (+,-,?)".format(supported_type))
742 supported_dict[key] = supported_type
743 # Ensure we know the supported element
744 if not key in self._KNOWN_QSUPPORTED_STUB_FEATURES:
745 raise Exception("unknown qSupported stub feature reported: %s" % key)
746
747 return supported_dict
748
749 def run_process_then_stop(self, run_seconds=1):
750 # Tell the stub to continue.
751 self.test_sequence.add_log_lines(
Stephane Sezerb6e81922014-11-20 18:50:46 +0000752 ["read packet: $vCont;c#a8"],
Todd Fialae50b2e42014-06-13 19:11:33 +0000753 True)
754 context = self.expect_gdbremote_sequence()
755
756 # Wait for run_seconds.
757 time.sleep(run_seconds)
758
759 # Send an interrupt, capture a T response.
760 self.reset_test_sequence()
761 self.test_sequence.add_log_lines(
762 ["read packet: {}".format(chr(03)),
763 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]+)([^#]+)#[0-9a-fA-F]{2}$", "capture":{1:"stop_result"} }],
764 True)
765 context = self.expect_gdbremote_sequence()
766 self.assertIsNotNone(context)
767 self.assertIsNotNone(context.get("stop_result"))
768
769 return context
770
771 def select_modifiable_register(self, reg_infos):
772 """Find a register that can be read/written freely."""
773 PREFERRED_REGISTER_NAMES = sets.Set(["rax",])
774
775 # First check for the first register from the preferred register name set.
776 alternative_register_index = None
777
778 self.assertIsNotNone(reg_infos)
779 for reg_info in reg_infos:
780 if ("name" in reg_info) and (reg_info["name"] in PREFERRED_REGISTER_NAMES):
781 # We found a preferred register. Use it.
782 return reg_info["lldb_register_index"]
783 if ("generic" in reg_info) and (reg_info["generic"] == "fp"):
784 # A frame pointer register will do as a register to modify temporarily.
785 alternative_register_index = reg_info["lldb_register_index"]
786
787 # We didn't find a preferred register. Return whatever alternative register
788 # we found, if any.
789 return alternative_register_index
790
791 def extract_registers_from_stop_notification(self, stop_key_vals_text):
792 self.assertIsNotNone(stop_key_vals_text)
793 kv_dict = self.parse_key_val_dict(stop_key_vals_text)
794
795 registers = {}
796 for (key, val) in kv_dict.items():
Stephane Sezer5109a792014-11-14 09:46:21 +0000797 if re.match(r"^[0-9a-fA-F]+$", key):
Todd Fialae50b2e42014-06-13 19:11:33 +0000798 registers[int(key, 16)] = val
799 return registers
800
801 def gather_register_infos(self):
802 self.reset_test_sequence()
803 self.add_register_info_collection_packets()
804
805 context = self.expect_gdbremote_sequence()
806 self.assertIsNotNone(context)
807
808 reg_infos = self.parse_register_info_packets(context)
809 self.assertIsNotNone(reg_infos)
810 self.add_lldb_register_index(reg_infos)
811
812 return reg_infos
813
814 def find_generic_register_with_name(self, reg_infos, generic_name):
815 self.assertIsNotNone(reg_infos)
816 for reg_info in reg_infos:
817 if ("generic" in reg_info) and (reg_info["generic"] == generic_name):
818 return reg_info
819 return None
820
Todd Fiala8d7ab8c2014-06-17 16:04:45 +0000821 def decode_gdbremote_binary(self, encoded_bytes):
822 decoded_bytes = ""
823 i = 0
824 while i < len(encoded_bytes):
825 if encoded_bytes[i] == "}":
826 # Handle escaped char.
827 self.assertTrue(i + 1 < len(encoded_bytes))
828 decoded_bytes += chr(ord(encoded_bytes[i+1]) ^ 0x20)
829 i +=2
830 elif encoded_bytes[i] == "*":
831 # Handle run length encoding.
832 self.assertTrue(len(decoded_bytes) > 0)
833 self.assertTrue(i + 1 < len(encoded_bytes))
834 repeat_count = ord(encoded_bytes[i+1]) - 29
835 decoded_bytes += decoded_bytes[-1] * repeat_count
836 i += 2
837 else:
838 decoded_bytes += encoded_bytes[i]
839 i += 1
840 return decoded_bytes
841
842 def build_auxv_dict(self, endian, word_size, auxv_data):
843 self.assertIsNotNone(endian)
844 self.assertIsNotNone(word_size)
845 self.assertIsNotNone(auxv_data)
846
847 auxv_dict = {}
848
849 while len(auxv_data) > 0:
850 # Chop off key.
851 raw_key = auxv_data[:word_size]
852 auxv_data = auxv_data[word_size:]
853
854 # Chop of value.
855 raw_value = auxv_data[:word_size]
856 auxv_data = auxv_data[word_size:]
857
858 # Convert raw text from target endian.
859 key = unpack_endian_binary_string(endian, raw_key)
860 value = unpack_endian_binary_string(endian, raw_value)
861
862 # Handle ending entry.
863 if key == 0:
864 self.assertEquals(value, 0)
865 return auxv_dict
866
867 # The key should not already be present.
868 self.assertFalse(key in auxv_dict)
869 auxv_dict[key] = value
870
871 self.fail("should not reach here - implies required double zero entry not found")
872 return auxv_dict
Todd Fiala51886732014-06-17 22:01:27 +0000873
874 def read_binary_data_in_chunks(self, command_prefix, chunk_length):
875 """Collect command_prefix{offset:x},{chunk_length:x} until a single 'l' or 'l' with data is returned."""
876 offset = 0
877 done = False
878 decoded_data = ""
879
880 while not done:
881 # Grab the next iteration of data.
882 self.reset_test_sequence()
883 self.test_sequence.add_log_lines([
884 "read packet: ${}{:x},{:x}:#00".format(command_prefix, offset, chunk_length),
Todd Fiala4c24eba2014-06-19 17:35:40 +0000885 {"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 +0000886 ], True)
887
888 context = self.expect_gdbremote_sequence()
889 self.assertIsNotNone(context)
890
891 response_type = context.get("response_type")
892 self.assertIsNotNone(response_type)
893 self.assertTrue(response_type in ["l", "m"])
894
895 # Move offset along.
896 offset += chunk_length
897
898 # Figure out if we're done. We're done if the response type is l.
899 done = response_type == "l"
900
901 # Decode binary data.
902 content_raw = context.get("content_raw")
903 if content_raw and len(content_raw) > 0:
904 self.assertIsNotNone(content_raw)
905 decoded_data += self.decode_gdbremote_binary(content_raw)
906 return decoded_data
Todd Fiala4c24eba2014-06-19 17:35:40 +0000907
908 def add_interrupt_packets(self):
909 self.test_sequence.add_log_lines([
910 # Send the intterupt.
911 "read packet: {}".format(chr(03)),
912 # And wait for the stop notification.
913 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})(.*)#[0-9a-fA-F]{2}$", "capture":{1:"stop_signo", 2:"stop_key_val_text" } },
914 ], True)
915
916 def parse_interrupt_packets(self, context):
917 self.assertIsNotNone(context.get("stop_signo"))
918 self.assertIsNotNone(context.get("stop_key_val_text"))
Todd Fiala9846d452014-06-20 17:39:24 +0000919 return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"]))
920
921 def add_QSaveRegisterState_packets(self, thread_id):
922 if thread_id:
923 # Use the thread suffix form.
924 request = "read packet: $QSaveRegisterState;thread:{:x}#00".format(thread_id)
925 else:
926 request = "read packet: $QSaveRegisterState#00"
927
928 self.test_sequence.add_log_lines([
929 request,
930 {"direction":"send", "regex":r"^\$(E?.*)#[0-9a-fA-F]{2}$", "capture":{1:"save_response" } },
931 ], True)
932
933 def parse_QSaveRegisterState_response(self, context):
934 self.assertIsNotNone(context)
935
936 save_response = context.get("save_response")
937 self.assertIsNotNone(save_response)
938
939 if len(save_response) < 1 or save_response[0] == "E":
940 # error received
941 return (False, None)
942 else:
943 return (True, int(save_response))
944
945 def add_QRestoreRegisterState_packets(self, save_id, thread_id=None):
946 if thread_id:
947 # Use the thread suffix form.
948 request = "read packet: $QRestoreRegisterState:{};thread:{:x}#00".format(save_id, thread_id)
949 else:
950 request = "read packet: $QRestoreRegisterState:{}#00".format(save_id)
951
952 self.test_sequence.add_log_lines([
953 request,
954 "send packet: $OK#00"
955 ], True)
956
957 def flip_all_bits_in_each_register_value(self, reg_infos, endian, thread_id=None):
958 self.assertIsNotNone(reg_infos)
959
960 successful_writes = 0
961 failed_writes = 0
962
963 for reg_info in reg_infos:
964 # Use the lldb register index added to the reg info. We're not necessarily
965 # working off a full set of register infos, so an inferred register index could be wrong.
966 reg_index = reg_info["lldb_register_index"]
967 self.assertIsNotNone(reg_index)
968
969 reg_byte_size = int(reg_info["bitsize"])/8
970 self.assertTrue(reg_byte_size > 0)
971
972 # Handle thread suffix.
973 if thread_id:
974 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
975 else:
976 p_request = "read packet: $p{:x}#00".format(reg_index)
977
978 # Read the existing value.
979 self.reset_test_sequence()
980 self.test_sequence.add_log_lines([
981 p_request,
982 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
983 ], True)
984 context = self.expect_gdbremote_sequence()
985 self.assertIsNotNone(context)
986
987 # Verify the response length.
988 p_response = context.get("p_response")
989 self.assertIsNotNone(p_response)
990 initial_reg_value = unpack_register_hex_unsigned(endian, p_response)
991
992 # Flip the value by xoring with all 1s
993 all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) / 8)
994 flipped_bits_int = initial_reg_value ^ int(all_one_bits_raw, 16)
995 # 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)
996
997 # Handle thread suffix for P.
998 if thread_id:
999 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)
1000 else:
1001 P_request = "read packet: $P{:x}={}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size))
1002
1003 # Write the flipped value to the register.
1004 self.reset_test_sequence()
1005 self.test_sequence.add_log_lines([
1006 P_request,
1007 { "direction":"send", "regex":r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", "capture":{1:"P_response"} },
1008 ], True)
1009 context = self.expect_gdbremote_sequence()
1010 self.assertIsNotNone(context)
1011
1012 # Determine if the write succeeded. There are a handful of registers that can fail, or partially fail
1013 # (e.g. flags, segment selectors, etc.) due to register value restrictions. Don't worry about them
1014 # all flipping perfectly.
1015 P_response = context.get("P_response")
1016 self.assertIsNotNone(P_response)
1017 if P_response == "OK":
1018 successful_writes += 1
1019 else:
1020 failed_writes += 1
1021 # print "reg (index={}, name={}) write FAILED (error: {})".format(reg_index, reg_info["name"], P_response)
1022
1023 # Read back the register value, ensure it matches the flipped value.
1024 if P_response == "OK":
1025 self.reset_test_sequence()
1026 self.test_sequence.add_log_lines([
1027 p_request,
1028 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
1029 ], True)
1030 context = self.expect_gdbremote_sequence()
1031 self.assertIsNotNone(context)
1032
1033 verify_p_response_raw = context.get("p_response")
1034 self.assertIsNotNone(verify_p_response_raw)
1035 verify_bits = unpack_register_hex_unsigned(endian, verify_p_response_raw)
1036
1037 if verify_bits != flipped_bits_int:
1038 # Some registers, like mxcsrmask and others, will permute what's written. Adjust succeed/fail counts.
1039 # print "reg (index={}, name={}): read verify FAILED: wrote {:x}, verify read back {:x}".format(reg_index, reg_info["name"], flipped_bits_int, verify_bits)
1040 successful_writes -= 1
1041 failed_writes +=1
1042
1043 return (successful_writes, failed_writes)
1044
1045 def is_bit_flippable_register(self, reg_info):
1046 if not reg_info:
1047 return False
1048 if not "set" in reg_info:
1049 return False
1050 if reg_info["set"] != "General Purpose Registers":
1051 return False
1052 if ("container-regs" in reg_info) and (len(reg_info["container-regs"]) > 0):
1053 # Don't try to bit flip registers contained in another register.
1054 return False
1055 if re.match("^.s$", reg_info["name"]):
1056 # This is a 2-letter register name that ends in "s", like a segment register.
1057 # Don't try to bit flip these.
1058 return False
1059 # Okay, this looks fine-enough.
1060 return True
1061
1062 def read_register_values(self, reg_infos, endian, thread_id=None):
1063 self.assertIsNotNone(reg_infos)
1064 values = {}
1065
1066 for reg_info in reg_infos:
1067 # We append a register index when load reg infos so we can work with subsets.
1068 reg_index = reg_info.get("lldb_register_index")
1069 self.assertIsNotNone(reg_index)
1070
1071 # Handle thread suffix.
1072 if thread_id:
1073 p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
1074 else:
1075 p_request = "read packet: $p{:x}#00".format(reg_index)
1076
1077 # Read it with p.
1078 self.reset_test_sequence()
1079 self.test_sequence.add_log_lines([
1080 p_request,
1081 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
1082 ], True)
1083 context = self.expect_gdbremote_sequence()
1084 self.assertIsNotNone(context)
1085
1086 # Convert value from target endian to integral.
1087 p_response = context.get("p_response")
1088 self.assertIsNotNone(p_response)
1089 self.assertTrue(len(p_response) > 0)
1090 self.assertFalse(p_response[0] == "E")
1091
1092 values[reg_index] = unpack_register_hex_unsigned(endian, p_response)
1093
Todd Fialae2202002014-06-27 22:11:56 +00001094 return values
1095
1096 def add_vCont_query_packets(self):
1097 self.test_sequence.add_log_lines([
Stephane Sezer22ed42e2014-11-13 21:39:24 +00001098 "read packet: $vCont?#49",
Todd Fialae2202002014-06-27 22:11:56 +00001099 {"direction":"send", "regex":r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", "capture":{2:"vCont_query_response" } },
1100 ], True)
1101
1102 def parse_vCont_query_response(self, context):
1103 self.assertIsNotNone(context)
1104 vCont_query_response = context.get("vCont_query_response")
1105
1106 # Handle case of no vCont support at all - in which case the capture group will be none or zero length.
1107 if not vCont_query_response or len(vCont_query_response) == 0:
1108 return {}
1109
1110 return {key:1 for key in vCont_query_response.split(";") if key and len(key) > 0}
1111
1112 def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100, use_Hc_packet=True, step_instruction="s"):
1113 """Used by single step test that appears in a few different contexts."""
1114 single_step_count = 0
1115
1116 while single_step_count < max_step_count:
1117 self.assertIsNotNone(thread_id)
1118
1119 # Build the packet for the single step instruction. We replace {thread}, if present, with the thread_id.
1120 step_packet = "read packet: ${}#00".format(re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction))
1121 # print "\nstep_packet created: {}\n".format(step_packet)
1122
1123 # Single step.
1124 self.reset_test_sequence()
1125 if use_Hc_packet:
1126 self.test_sequence.add_log_lines(
1127 [# Set the continue thread.
1128 "read packet: $Hc{0:x}#00".format(thread_id),
1129 "send packet: $OK#00",
1130 ], True)
1131 self.test_sequence.add_log_lines([
1132 # Single step.
1133 step_packet,
1134 # "read packet: $vCont;s:{0:x}#00".format(thread_id),
1135 # Expect a breakpoint stop report.
1136 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
1137 ], True)
1138 context = self.expect_gdbremote_sequence()
1139 self.assertIsNotNone(context)
1140 self.assertIsNotNone(context.get("stop_signo"))
1141 self.assertEquals(int(context.get("stop_signo"), 16), signal.SIGTRAP)
1142
1143 single_step_count += 1
1144
1145 # See if the predicate is true. If so, we're done.
1146 if predicate(args):
1147 return (True, single_step_count)
1148
1149 # The predicate didn't return true within the runaway step count.
1150 return (False, single_step_count)
1151
1152 def g_c1_c2_contents_are(self, args):
1153 """Used by single step test that appears in a few different contexts."""
1154 g_c1_address = args["g_c1_address"]
1155 g_c2_address = args["g_c2_address"]
1156 expected_g_c1 = args["expected_g_c1"]
1157 expected_g_c2 = args["expected_g_c2"]
1158
1159 # Read g_c1 and g_c2 contents.
1160 self.reset_test_sequence()
1161 self.test_sequence.add_log_lines(
1162 ["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1),
1163 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c1_contents"} },
1164 "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1),
1165 {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c2_contents"} }],
1166 True)
1167
1168 # Run the packet stream.
1169 context = self.expect_gdbremote_sequence()
1170 self.assertIsNotNone(context)
1171
1172 # Check if what we read from inferior memory is what we are expecting.
1173 self.assertIsNotNone(context.get("g_c1_contents"))
1174 self.assertIsNotNone(context.get("g_c2_contents"))
1175
1176 return (context.get("g_c1_contents").decode("hex") == expected_g_c1) and (context.get("g_c2_contents").decode("hex") == expected_g_c2)
1177
1178 def single_step_only_steps_one_instruction(self, use_Hc_packet=True, step_instruction="s"):
1179 """Used by single step test that appears in a few different contexts."""
1180 # Start up the inferior.
1181 procs = self.prep_debug_monitor_and_inferior(
1182 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"])
1183
1184 # Run the process
1185 self.test_sequence.add_log_lines(
1186 [# Start running after initial stop.
Stephane Sezer22ed42e2014-11-13 21:39:24 +00001187 "read packet: $c#63",
Todd Fialae2202002014-06-27 22:11:56 +00001188 # Match output line that prints the memory address of the function call entry point.
1189 # Note we require launch-only testing so we can get inferior otuput.
1190 { "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$",
1191 "capture":{ 1:"function_address", 2:"g_c1_address", 3:"g_c2_address"} },
1192 # Now stop the inferior.
1193 "read packet: {}".format(chr(03)),
1194 # And wait for the stop notification.
1195 {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
1196 True)
1197
1198 # Run the packet stream.
1199 context = self.expect_gdbremote_sequence()
1200 self.assertIsNotNone(context)
1201
1202 # Grab the main thread id.
1203 self.assertIsNotNone(context.get("stop_thread_id"))
1204 main_thread_id = int(context.get("stop_thread_id"), 16)
1205
1206 # Grab the function address.
1207 self.assertIsNotNone(context.get("function_address"))
1208 function_address = int(context.get("function_address"), 16)
1209
1210 # Grab the data addresses.
1211 self.assertIsNotNone(context.get("g_c1_address"))
1212 g_c1_address = int(context.get("g_c1_address"), 16)
1213
1214 self.assertIsNotNone(context.get("g_c2_address"))
1215 g_c2_address = int(context.get("g_c2_address"), 16)
1216
1217 # Set a breakpoint at the given address.
1218 # Note this might need to be switched per platform (ARM, mips, etc.).
1219 BREAKPOINT_KIND = 1
1220 self.reset_test_sequence()
1221 self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
1222 context = self.expect_gdbremote_sequence()
1223 self.assertIsNotNone(context)
1224
1225 # Remove the breakpoint.
1226 self.reset_test_sequence()
1227 self.add_remove_breakpoint_packets(function_address, breakpoint_kind=BREAKPOINT_KIND)
1228 context = self.expect_gdbremote_sequence()
1229 self.assertIsNotNone(context)
1230
1231 # Verify g_c1 and g_c2 match expected initial state.
1232 args = {}
1233 args["g_c1_address"] = g_c1_address
1234 args["g_c2_address"] = g_c2_address
1235 args["expected_g_c1"] = "0"
1236 args["expected_g_c2"] = "1"
1237
1238 self.assertTrue(self.g_c1_c2_contents_are(args))
1239
1240 # Verify we take only a small number of steps to hit the first state. Might need to work through function entry prologue code.
1241 args["expected_g_c1"] = "1"
1242 args["expected_g_c2"] = "1"
1243 (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)
1244 self.assertTrue(state_reached)
1245
1246 # Verify we hit the next state.
1247 args["expected_g_c1"] = "1"
1248 args["expected_g_c2"] = "0"
1249 (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
1250 self.assertTrue(state_reached)
1251 self.assertEquals(step_count, 1)
1252
1253 # Verify we hit the next state.
1254 args["expected_g_c1"] = "0"
1255 args["expected_g_c2"] = "0"
1256 (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)
1257 self.assertTrue(state_reached)
1258 self.assertEquals(step_count, 1)
1259
1260 # Verify we hit the next state.
1261 args["expected_g_c1"] = "0"
1262 args["expected_g_c2"] = "1"
1263 (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)
1264 self.assertTrue(state_reached)
1265 self.assertEquals(step_count, 1)
Todd Fialaaf245d12014-06-30 21:05:18 +00001266