Add --gdb argument so I can run valgrind on gdb.
[riscv-tests.git] / debug / testlib.py
1 import os.path
2 import pexpect
3 import shlex
4 import subprocess
5 import tempfile
6 import testlib
7 import unittest
8
9 # Note that gdb comes with its own testsuite. I was unable to figure out how to
10 # run that testsuite against the spike simulator.
11
12 def find_file(path):
13 for directory in (os.getcwd(), os.path.dirname(testlib.__file__)):
14 fullpath = os.path.join(directory, path)
15 if os.path.exists(fullpath):
16 return fullpath
17 return None
18
19 def compile(args, xlen=32):
20 cc = os.path.expandvars("$RISCV/bin/riscv%d-unknown-elf-gcc" % xlen)
21 cmd = [cc, "-g"]
22 for arg in args:
23 found = find_file(arg)
24 if found:
25 cmd.append(found)
26 else:
27 cmd.append(arg)
28 cmd = " ".join(cmd)
29 result = os.system(cmd)
30 assert result == 0, "%r failed" % cmd
31
32 def unused_port():
33 # http://stackoverflow.com/questions/2838244/get-open-tcp-port-in-python/2838309#2838309
34 import socket
35 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
36 s.bind(("",0))
37 port = s.getsockname()[1]
38 s.close()
39 return port
40
41 class Spike(object):
42 def __init__(self, cmd, binary=None, halted=False, with_gdb=True, timeout=None,
43 xlen=64):
44 """Launch spike. Return tuple of its process and the port it's running on."""
45 if cmd:
46 cmd = shlex.split(cmd)
47 else:
48 cmd = ["spike"]
49 if (xlen == 32):
50 cmd += ["--isa", "RV32"]
51
52 if timeout:
53 cmd = ["timeout", str(timeout)] + cmd
54
55 if halted:
56 cmd.append('-H')
57 if with_gdb:
58 self.port = unused_port()
59 cmd += ['--gdb-port', str(self.port)]
60 cmd.append('pk')
61 if binary:
62 cmd.append(binary)
63 logfile = open("spike.log", "w")
64 logfile.write("+ %s\n" % " ".join(cmd))
65 logfile.flush()
66 self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile,
67 stderr=logfile)
68
69 def __del__(self):
70 try:
71 self.process.kill()
72 self.process.wait()
73 except OSError:
74 pass
75
76 def wait(self, *args, **kwargs):
77 return self.process.wait(*args, **kwargs)
78
79 class Openocd(object):
80 def __init__(self, cmd=None, config=None, debug=False):
81 if cmd:
82 cmd = shlex.split(cmd)
83 else:
84 cmd = ["openocd"]
85 if config:
86 cmd += ["-f", find_file(config)]
87 if debug:
88 cmd.append("-d")
89 logfile = open("openocd.log", "w")
90 logfile.write("+ %s\n" % " ".join(cmd))
91 self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile,
92 stderr=logfile)
93 # TODO: Pick a random port
94 self.port = 3333
95
96 def __del__(self):
97 try:
98 self.process.kill()
99 self.process.wait()
100 except OSError:
101 pass
102
103 class Gdb(object):
104 def __init__(self,
105 cmd=os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gdb")):
106 self.child = pexpect.spawn(cmd)
107 self.child.logfile = file("gdb.log", "w")
108 self.child.logfile.write("+ %s\n" % cmd)
109 self.wait()
110 self.command("set confirm off")
111 self.command("set width 0")
112 self.command("set height 0")
113 # Force consistency.
114 self.command("set print entry-values no")
115
116 def wait(self):
117 """Wait for prompt."""
118 self.child.expect("\(gdb\)")
119
120 def command(self, command, timeout=-1):
121 self.child.sendline(command)
122 self.child.expect("\n", timeout=timeout)
123 self.child.expect("\(gdb\)", timeout=timeout)
124 return self.child.before.strip()
125
126 def c(self, wait=True):
127 if wait:
128 output = self.command("c")
129 assert "Continuing" in output
130 return output
131 else:
132 self.child.sendline("c")
133 self.child.expect("Continuing")
134
135 def interrupt(self):
136 self.child.send("\003");
137 self.child.expect("\(gdb\)")
138 return self.child.before.strip()
139
140 def x(self, address, size='w'):
141 output = self.command("x/%s %s" % (size, address))
142 value = int(output.split(':')[1].strip(), 0)
143 return value
144
145 def p(self, obj):
146 output = self.command("p/x %s" % obj)
147 value = int(output.split('=')[-1].strip(), 0)
148 return value
149
150 def stepi(self):
151 output = self.command("stepi")
152 assert "Cannot" not in output
153 return output
154
155 def load(self):
156 output = self.command("load", timeout=60)
157 assert "failed" not in output
158 assert "Transfer rate" in output
159
160 def b(self, location):
161 output = self.command("b %s" % location)
162 assert "not defined" not in output
163 assert "Breakpoint" in output
164 return output
165
166 def hbreak(self, location):
167 output = self.command("hbreak %s" % location)
168 assert "not defined" not in output
169 assert "Hardware assisted breakpoint" in output
170 return output