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