13 class DeleteServer(unittest
.TestCase
):
17 class MemoryTest(DeleteServer
):
19 self
.server
= target
.server()
20 self
.gdb
= testlib
.Gdb()
21 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
23 def access_test(self
, size
, data_type
):
24 a
= 0x86753095555aaaa & ((1<<(size
*8))-1)
25 b
= 0xdeadbeef12345678 & ((1<<(size
*8))-1)
26 self
.gdb
.p("*((%s*)0x%x) = 0x%x" % (data_type
, target
.ram
, a
))
27 self
.gdb
.p("*((%s*)0x%x) = 0x%x" % (data_type
, target
.ram
+ size
, b
))
28 self
.assertEqual(self
.gdb
.p("*((%s*)0x%x)" % (data_type
, target
.ram
)), a
)
29 self
.assertEqual(self
.gdb
.p("*((%s*)0x%x)" % (data_type
, target
.ram
+ size
)), b
)
32 self
.access_test(1, 'char')
35 self
.access_test(2, 'short')
38 self
.access_test(4, 'long')
41 self
.access_test(8, 'long long')
43 class InstantHaltTest(DeleteServer
):
45 self
.server
= target
.server()
46 self
.gdb
= testlib
.Gdb()
47 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
49 def test_instant_halt(self
):
50 self
.assertEqual(0x1000, self
.gdb
.p("$pc"))
51 # For some reason instret resets to 0.
52 self
.assertLess(self
.gdb
.p("$instret"), 8)
53 self
.gdb
.command("stepi")
54 self
.assertNotEqual(0x1000, self
.gdb
.p("$pc"))
56 def test_change_pc(self
):
57 """Change the PC right as we come out of reset."""
59 self
.gdb
.command("p *((int*) 0x%x)=0x13" % target
.ram
)
60 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (target
.ram
+ 4))
61 self
.gdb
.command("p *((int*) 0x%x)=0x13" % (target
.ram
+ 8))
62 self
.gdb
.p("$pc=0x%x" % target
.ram
)
63 self
.gdb
.command("stepi")
64 self
.assertEqual((target
.ram
+ 4), self
.gdb
.p("$pc"))
65 self
.gdb
.command("stepi")
66 self
.assertEqual((target
.ram
+ 4), self
.gdb
.p("$pc"))
68 class DebugTest(DeleteServer
):
70 self
.binary
= target
.compile("programs/debug.c", "programs/checksum.c")
71 self
.server
= target
.server()
72 self
.gdb
= testlib
.Gdb()
73 self
.gdb
.command("file %s" % self
.binary
)
74 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
80 self
.assertIn("Breakpoint", output
)
81 self
.assertIn("_exit", output
)
82 self
.assertEqual(self
.gdb
.p("status"), 0xc86455d4)
84 def test_turbostep(self
):
85 """Single step a bunch of times."""
86 self
.gdb
.command("p i=0");
89 self
.gdb
.command("stepi")
90 pc
= self
.gdb
.command("p $pc")
91 self
.assertNotEqual(last_pc
, pc
)
97 def test_breakpoint(self
):
99 # The breakpoint should be hit exactly 2 times.
101 output
= self
.gdb
.c()
102 self
.assertIn("Breakpoint ", output
)
105 def test_registers(self
):
106 # Get to a point in the code where some registers have actually been
111 # Try both forms to test gdb.
112 for cmd
in ("info all-registers", "info registers all"):
113 output
= self
.gdb
.command(cmd
)
114 self
.assertNotIn("Could not", output
)
115 for reg
in ('zero', 'ra', 'sp', 'gp', 'tp'):
116 self
.assertIn(reg
, output
)
119 # mcpuid is one of the few registers that should have the high bit set
121 # Leave this commented out until gdb and spike agree on the encoding of
122 # mcpuid (which is going to be renamed to misa in any case).
123 #self.assertRegexpMatches(output, ".*mcpuid *0x80")
126 # The instret register should always be changing.
129 # instret = self.gdb.p("$instret")
130 # self.assertNotEqual(instret, last_instret)
131 # last_instret = instret
132 # self.gdb.command("stepi")
136 def test_interrupt(self
):
137 """Sending gdb ^C while the program is running should cause it to halt."""
138 self
.gdb
.b("main:start")
140 self
.gdb
.command("p i=123");
141 self
.gdb
.c(wait
=False)
143 output
= self
.gdb
.interrupt()
144 assert "main" in output
145 self
.assertGreater(self
.gdb
.p("j"), 10)
149 class RegsTest(DeleteServer
):
151 self
.binary
= target
.compile("programs/regs.S")
152 self
.server
= target
.server()
153 self
.gdb
= testlib
.Gdb()
154 self
.gdb
.command("file %s" % self
.binary
)
155 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
156 self
.gdb
.command("load")
158 self
.gdb
.b("handle_trap")
161 def test_write_gprs(self
):
162 # Note a0 is missing from this list since it's used to hold the
164 regs
= ("ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
165 "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
166 "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5",
169 self
.gdb
.p("$pc=write_regs")
170 for i
, r
in enumerate(regs
):
171 self
.gdb
.command("p $%s=%d" % (r
, (0xdeadbeef<<i
)+17))
172 self
.gdb
.command("p $a0=data")
173 self
.gdb
.command("b all_done")
174 output
= self
.gdb
.c()
175 self
.assertIn("Breakpoint ", output
)
177 # Just to get this data in the log.
178 self
.gdb
.command("x/30gx data")
179 self
.gdb
.command("info registers")
180 for n
in range(len(regs
)):
181 self
.assertEqual(self
.gdb
.x("data+%d" % (8*n
), 'g'),
184 def test_write_csrs(self
):
185 # As much a test of gdb as of the simulator.
186 self
.gdb
.p("$mscratch=0")
188 self
.assertEqual(self
.gdb
.p("$mscratch"), 0)
189 self
.gdb
.p("$mscratch=123")
191 self
.assertEqual(self
.gdb
.p("$mscratch"), 123)
193 self
.gdb
.command("p $pc=write_regs")
194 self
.gdb
.command("p $a0=data")
195 self
.gdb
.command("b all_done")
196 self
.gdb
.command("c")
198 self
.assertEqual(123, self
.gdb
.p("$mscratch"))
199 self
.assertEqual(123, self
.gdb
.p("$x1"))
200 self
.assertEqual(123, self
.gdb
.p("$csr832"))
202 class DownloadTest(DeleteServer
):
205 fd
= file("download.c", "w")
206 fd
.write("#include <stdint.h>\n")
207 fd
.write("unsigned int crc32a(uint8_t *message, unsigned int size);\n")
208 fd
.write("uint32_t length = %d;\n" % length
)
209 fd
.write("uint8_t d[%d] = {\n" % length
)
211 for i
in range(length
/ 16):
212 fd
.write(" /* 0x%04x */ " % (i
* 16));
214 value
= random
.randrange(1<<8)
215 fd
.write("%d, " % value
)
216 self
.crc
= binascii
.crc32("%c" % value
, self
.crc
)
219 fd
.write("uint8_t *data = &d[0];\n");
220 fd
.write("uint32_t main() { return crc32a(data, length); }\n")
226 self
.binary
= target
.compile("download.c", "programs/checksum.c")
227 self
.server
= target
.server()
228 self
.gdb
= testlib
.Gdb()
229 self
.gdb
.command("file %s" % self
.binary
)
230 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
232 def test_download(self
):
233 output
= self
.gdb
.load()
234 self
.gdb
.command("b _exit")
236 self
.assertEqual(self
.gdb
.p("status"), self
.crc
)
238 class MprvTest(DeleteServer
):
240 self
.binary
= target
.compile("programs/mprv.S")
241 self
.server
= target
.server()
242 self
.gdb
= testlib
.Gdb()
243 self
.gdb
.command("file %s" % self
.binary
)
244 self
.gdb
.command("target extended-remote localhost:%d" % self
.server
.port
)
248 """Test that the debugger can access memory when MPRV is set."""
249 self
.gdb
.c(wait
=False)
251 output
= self
.gdb
.command("p/x *(int*)(((char*)&data)-0x80000000)")
252 self
.assertIn("0xbead", output
)
254 class Target(object):
256 raise NotImplementedError
258 def compile(self
, *sources
):
259 return testlib
.compile(sources
+
260 ("programs/entry.S", "programs/init.c",
262 "-T", "targets/%s/link.lds" % self
.name
,
264 "-mcmodel=medany"), xlen
=self
.xlen
)
266 class SpikeTarget(Target
):
272 return testlib
.Spike(parsed
.cmd
, halted
=True)
274 class MicroSemiTarget(Target
):
280 return testlib
.Openocd(cmd
=parsed
.cmd
,
281 config
="targets/%s/openocd.cfg" % self
.name
)
289 parser
= argparse
.ArgumentParser()
290 group
= parser
.add_mutually_exclusive_group(required
=True)
292 group
.add_argument("--%s" % t
.name
, action
="store_const", const
=t
,
294 parser
.add_argument("--cmd",
295 help="The command to use to start the debug server.")
296 parser
.add_argument("unittest", nargs
="*")
298 parsed
= parser
.parse_args()
301 target
= parsed
.target()
302 unittest
.main(argv
=[sys
.argv
[0]] + parsed
.unittest
)
304 # TROUBLESHOOTING TIPS
305 # If a particular test fails, run just that one test, eg.:
306 # ./tests/gdbserver.py MprvTest.test_mprv
307 # Then inspect gdb.log and spike.log to see what happened in more detail.
309 if __name__
== '__main__':