Write test for downloading a mostly random program
[riscv-isa-sim.git] / tests / gdbserver.py
1 #!/usr/bin/python
2
3 import os
4 import testlib
5 import unittest
6 import tempfile
7 import time
8 import random
9 import binascii
10
11 class InstantHaltTest(unittest.TestCase):
12 def setUp(self):
13 self.binary = testlib.compile("debug.c")
14 self.spike = testlib.Spike(self.binary, halted=True)
15 self.gdb = testlib.Gdb()
16 self.gdb.command("file %s" % self.binary)
17 self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
18
19 def test_instant_halt(self):
20 self.assertEqual(0x1000, self.gdb.p("$pc"))
21 # For some reason instret resets to 0.
22 self.assertLess(self.gdb.p("$instret"), 8)
23 self.gdb.command("stepi")
24 self.assertNotEqual(0x1000, self.gdb.p("$pc"))
25
26 def test_change_pc(self):
27 """Change the PC right as we come out of reset."""
28 # 0x13 is nop
29 self.gdb.command("p *((int*) 0x80000000)=0x13")
30 self.gdb.command("p *((int*) 0x80000004)=0x13")
31 self.gdb.command("p *((int*) 0x80000008)=0x13")
32 self.gdb.command("p $pc=0x80000000")
33 self.gdb.command("stepi")
34 self.assertEqual(0x80000004, self.gdb.p("$pc"))
35 self.gdb.command("stepi")
36 self.assertEqual(0x80000008, self.gdb.p("$pc"))
37
38 class DebugTest(unittest.TestCase):
39 def setUp(self):
40 self.binary = testlib.compile("debug.c")
41 self.spike = testlib.Spike(self.binary, halted=False)
42 self.gdb = testlib.Gdb()
43 self.gdb.command("file %s" % self.binary)
44 self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
45
46 def test_turbostep(self):
47 """Single step a bunch of times."""
48 self.gdb.command("p i=0");
49 last_pc = None
50 for _ in range(100):
51 self.gdb.command("stepi")
52 pc = self.gdb.command("p $pc")
53 self.assertNotEqual(last_pc, pc)
54 last_pc = pc
55
56 def test_exit(self):
57 self.gdb.command("p i=0");
58 output = self.gdb.command("c")
59 self.assertIn("Continuing", output)
60 self.assertIn("Remote connection closed", output)
61
62 def test_breakpoint(self):
63 self.gdb.command("p i=0");
64 self.gdb.command("b print_row")
65 # The breakpoint should be hit exactly 10 times.
66 for i in range(10):
67 output = self.gdb.command("c")
68 self.assertIn("Continuing", output)
69 self.assertIn("length=%d" % i, output)
70 self.assertIn("Breakpoint 1", output)
71 output = self.gdb.command("c")
72 self.assertIn("Continuing", output)
73 self.assertIn("Remote connection closed", output)
74
75 def test_registers(self):
76 self.gdb.command("p i=0");
77 # Try both forms to test gdb.
78 for cmd in ("info all-registers", "info registers all"):
79 output = self.gdb.command(cmd)
80 self.assertNotIn("Could not", output)
81 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
82 self.assertIn(reg, output)
83 # mcpuid is one of the few registers that should have the high bit set
84 # (for rv64).
85 # Leave this commented out until gdb and spike agree on the encoding of
86 # mcpuid (which is going to be renamed to misa in any case).
87 #self.assertRegexpMatches(output, ".*mcpuid *0x80")
88
89 # The instret register should always be changing.
90 last_instret = None
91 for _ in range(5):
92 instret = self.gdb.p("$instret")
93 self.assertNotEqual(instret, last_instret)
94 last_instret = instret
95 self.gdb.command("stepi")
96
97 def test_interrupt(self):
98 """Sending gdb ^C while the program is running should cause it to halt."""
99 self.gdb.c(wait=False)
100 time.sleep(0.1)
101 self.gdb.interrupt()
102 self.gdb.command("p i=123");
103 self.gdb.c(wait=False)
104 time.sleep(0.1)
105 self.gdb.interrupt()
106 self.gdb.command("p i=0");
107 output = self.gdb.c()
108 self.assertIn("Continuing", output)
109 self.assertIn("Remote connection closed", output)
110
111 class RegsTest(unittest.TestCase):
112 def setUp(self):
113 self.binary = testlib.compile("regs.s")
114 self.spike = testlib.Spike(self.binary, halted=False)
115 self.gdb = testlib.Gdb()
116 self.gdb.command("file %s" % self.binary)
117 self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
118
119 def test_write_gprs(self):
120 # Note a0 is missing from this list since it's used to hold the
121 # address.
122 regs = ("ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
123 "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
124 "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5",
125 "t6")
126
127 self.gdb.command("p $pc=write_regs")
128 for i, r in enumerate(regs):
129 self.gdb.command("p $%s=%d" % (r, (0xdeadbeef<<i)+17))
130 self.gdb.command("p $a0=data")
131 self.gdb.command("b all_done")
132 output = self.gdb.command("c")
133 self.assertIn("Breakpoint 1", output)
134
135 # Just to get this data in the log.
136 self.gdb.command("x/30gx data")
137 self.gdb.command("info registers")
138 for n in range(len(regs)):
139 self.assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
140 (0xdeadbeef<<n)+17)
141
142 def test_write_csrs(self):
143 # As much a test of gdb as of the simulator.
144 self.gdb.p("$mscratch=0")
145 self.gdb.stepi()
146 self.assertEqual(self.gdb.p("$mscratch"), 0)
147 self.gdb.p("$mscratch=123")
148 self.gdb.stepi()
149 self.assertEqual(self.gdb.p("$mscratch"), 123)
150
151 self.gdb.command("p $fflags=9")
152 self.gdb.command("p $pc=write_regs")
153 self.gdb.command("p $a0=data")
154 self.gdb.command("b all_done")
155 self.gdb.command("c")
156
157 self.assertEqual(9, self.gdb.p("$fflags"))
158 self.assertEqual(9, self.gdb.p("$x1"))
159 self.assertEqual(9, self.gdb.p("$csr1"))
160
161 class DownloadTest(unittest.TestCase):
162 def setUp(self):
163 length = 2**16
164 fd = file("data.c", "w")
165 fd.write("#include <stdint.h>\n")
166 fd.write("uint32_t length = %d;\n" % length)
167 fd.write("uint8_t d[%d] = {\n" % length)
168 self.crc = 0
169 for _ in range(length / 16):
170 fd.write(" ");
171 for _ in range(16):
172 value = random.randrange(1<<8)
173 fd.write("%d, " % value)
174 self.crc = binascii.crc32("%c" % value, self.crc)
175 fd.write("\n");
176 fd.write("};\n");
177 fd.write("uint8_t *data = &d[0];\n");
178 fd.close()
179
180 self.binary = testlib.compile("checksum.c", "data.c", "start.S",
181 "-mcmodel=medany",
182 "-T", "standalone.lds",
183 "-nostartfiles"
184 )
185 self.spike = testlib.Spike(None, halted=True)
186 self.gdb = testlib.Gdb()
187 self.gdb.command("file %s" % self.binary)
188 self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
189
190 def test_download(self):
191 output = self.gdb.command("load")
192 self.assertNotIn("failed", output)
193 self.assertIn("Transfer rate", output)
194 self.gdb.command("b done")
195 self.gdb.c()
196 result = self.gdb.p("$a0")
197 self.assertEqual(self.crc, result)
198
199 class MprvTest(unittest.TestCase):
200 def setUp(self):
201 self.binary = testlib.compile("mprv.S", "-T", "standalone.lds",
202 "-nostartfiles")
203 self.spike = testlib.Spike(None, halted=True)
204 self.gdb = testlib.Gdb()
205 self.gdb.command("file %s" % self.binary)
206 self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
207 self.gdb.command("load")
208
209 def test_mprv(self):
210 """Test that the debugger can access memory when MPRV is set."""
211 self.gdb.c(wait=False)
212 self.gdb.interrupt()
213 output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
214 self.assertIn("0xbead", output)
215
216 if __name__ == '__main__':
217 # TROUBLESHOOTING TIPS
218 # If a particular test fails, run just that one test, eg.:
219 # ./tests/gdbserver.py MprvTest.test_mprv
220 # Then inspect gdb.log and spike.log to see what happened in more detail.
221 unittest.main()