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