Ensure there are no unnamed registers.
[riscv-tests.git] / debug / gdbserver.py
1 #!/usr/bin/env python
2
3 import argparse
4 import binascii
5 import random
6 import sys
7 import tempfile
8 import time
9 import os
10
11 import targets
12 import testlib
13 from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn
14 from testlib import assertGreater, assertRegexpMatches, assertLess
15 from testlib import GdbTest, GdbSingleHartTest, TestFailed, assertTrue
16
17 MSTATUS_UIE = 0x00000001
18 MSTATUS_SIE = 0x00000002
19 MSTATUS_HIE = 0x00000004
20 MSTATUS_MIE = 0x00000008
21 MSTATUS_UPIE = 0x00000010
22 MSTATUS_SPIE = 0x00000020
23 MSTATUS_HPIE = 0x00000040
24 MSTATUS_MPIE = 0x00000080
25 MSTATUS_SPP = 0x00000100
26 MSTATUS_HPP = 0x00000600
27 MSTATUS_MPP = 0x00001800
28 MSTATUS_FS = 0x00006000
29 MSTATUS_XS = 0x00018000
30 MSTATUS_MPRV = 0x00020000
31 MSTATUS_PUM = 0x00040000
32 MSTATUS_MXR = 0x00080000
33 MSTATUS_VM = 0x1F000000
34 MSTATUS32_SD = 0x80000000
35 MSTATUS64_SD = 0x8000000000000000
36
37 # pylint: disable=abstract-method
38
39 def ihex_line(address, record_type, data):
40 assert len(data) < 128
41 line = ":%02X%04X%02X" % (len(data), address, record_type)
42 check = len(data)
43 check += address % 256
44 check += address >> 8
45 check += record_type
46 for char in data:
47 value = ord(char)
48 check += value
49 line += "%02X" % value
50 line += "%02X\n" % ((256-check)%256)
51 return line
52
53 def ihex_parse(line):
54 assert line.startswith(":")
55 line = line[1:]
56 data_len = int(line[:2], 16)
57 address = int(line[2:6], 16)
58 record_type = int(line[6:8], 16)
59 data = ""
60 for i in range(data_len):
61 data += "%c" % int(line[8+2*i:10+2*i], 16)
62 return record_type, address, data
63
64 def readable_binary_string(s):
65 return "".join("%02x" % ord(c) for c in s)
66
67 class SimpleRegisterTest(GdbTest):
68 def check_reg(self, name, alias):
69 a = random.randrange(1<<self.hart.xlen)
70 b = random.randrange(1<<self.hart.xlen)
71 self.gdb.p("$%s=0x%x" % (name, a))
72 assertEqual(self.gdb.p("$%s" % alias), a)
73 self.gdb.stepi()
74 assertEqual(self.gdb.p("$%s" % name), a)
75 assertEqual(self.gdb.p("$%s" % alias), a)
76 self.gdb.p("$%s=0x%x" % (alias, b))
77 assertEqual(self.gdb.p("$%s" % name), b)
78 self.gdb.stepi()
79 assertEqual(self.gdb.p("$%s" % name), b)
80 assertEqual(self.gdb.p("$%s" % alias), b)
81
82 def setup(self):
83 # 0x13 is nop
84 self.gdb.command("p *((int*) 0x%x)=0x13" % self.hart.ram)
85 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 4))
86 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 8))
87 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 12))
88 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 16))
89 self.gdb.p("$pc=0x%x" % self.hart.ram)
90
91 class SimpleS0Test(SimpleRegisterTest):
92 def test(self):
93 self.check_reg("s0", "x8")
94
95 class SimpleS1Test(SimpleRegisterTest):
96 def test(self):
97 self.check_reg("s1", "x9")
98
99 class SimpleT0Test(SimpleRegisterTest):
100 def test(self):
101 self.check_reg("t0", "x5")
102
103 class SimpleT1Test(SimpleRegisterTest):
104 def test(self):
105 self.check_reg("t1", "x6")
106
107 class SimpleF18Test(SimpleRegisterTest):
108 def check_reg(self, name, alias):
109 self.gdb.p_raw("$mstatus=$mstatus | 0x00006000")
110 self.gdb.stepi()
111 a = random.random()
112 b = random.random()
113 self.gdb.p_raw("$%s=%f" % (name, a))
114 assertLess(abs(float(self.gdb.p_raw("$%s" % alias)) - a), .001)
115 self.gdb.stepi()
116 assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - a), .001)
117 assertLess(abs(float(self.gdb.p_raw("$%s" % alias)) - a), .001)
118 self.gdb.p_raw("$%s=%f" % (alias, b))
119 assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - b), .001)
120 self.gdb.stepi()
121 assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - b), .001)
122 assertLess(abs(float(self.gdb.p_raw("$%s" % alias)) - b), .001)
123
124 def early_applicable(self):
125 return self.hart.extensionSupported('F')
126
127 def test(self):
128 self.check_reg("f18", "fs2")
129
130 class SimpleMemoryTest(GdbTest):
131 def access_test(self, size, data_type):
132 assertEqual(self.gdb.p("sizeof(%s)" % data_type), size)
133 a = 0x86753095555aaaa & ((1<<(size*8))-1)
134 b = 0xdeadbeef12345678 & ((1<<(size*8))-1)
135 addrA = self.hart.ram
136 addrB = self.hart.ram + self.hart.ram_size - size
137 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, addrA, a))
138 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, addrB, b))
139 assertEqual(self.gdb.p("*((%s*)0x%x)" % (data_type, addrA)), a)
140 assertEqual(self.gdb.p("*((%s*)0x%x)" % (data_type, addrB)), b)
141
142 class MemTest8(SimpleMemoryTest):
143 def test(self):
144 self.access_test(1, 'char')
145
146 class MemTest16(SimpleMemoryTest):
147 def test(self):
148 self.access_test(2, 'short')
149
150 class MemTest32(SimpleMemoryTest):
151 def test(self):
152 self.access_test(4, 'int')
153
154 class MemTest64(SimpleMemoryTest):
155 def test(self):
156 self.access_test(8, 'long long')
157
158 # FIXME: I'm not passing back invalid addresses correctly in read/write memory.
159 #class MemTestReadInvalid(SimpleMemoryTest):
160 # def test(self):
161 # # This test relies on 'gdb_report_data_abort enable' being executed in
162 # # the openocd.cfg file.
163 # try:
164 # self.gdb.p("*((int*)0xdeadbeef)")
165 # assert False, "Read should have failed."
166 # except testlib.CannotAccess as e:
167 # assertEqual(e.address, 0xdeadbeef)
168 # self.gdb.p("*((int*)0x%x)" % self.hart.ram)
169 #
170 #class MemTestWriteInvalid(SimpleMemoryTest):
171 # def test(self):
172 # # This test relies on 'gdb_report_data_abort enable' being executed in
173 # # the openocd.cfg file.
174 # try:
175 # self.gdb.p("*((int*)0xdeadbeef)=8675309")
176 # assert False, "Write should have failed."
177 # except testlib.CannotAccess as e:
178 # assertEqual(e.address, 0xdeadbeef)
179 # self.gdb.p("*((int*)0x%x)=6874742" % self.hart.ram)
180
181 class MemTestBlock(GdbTest):
182 length = 1024
183 line_length = 16
184
185 def test(self):
186 a = tempfile.NamedTemporaryFile(suffix=".ihex")
187 data = ""
188 for i in range(self.length / self.line_length):
189 line_data = "".join(["%c" % random.randrange(256)
190 for _ in range(self.line_length)])
191 data += line_data
192 a.write(ihex_line(i * self.line_length, 0, line_data))
193 a.flush()
194
195 self.gdb.command("shell cat %s" % a.name)
196 self.gdb.command("restore %s 0x%x" % (a.name, self.hart.ram))
197 increment = 19 * 4
198 for offset in range(0, self.length, increment) + [self.length-4]:
199 value = self.gdb.p("*((int*)0x%x)" % (self.hart.ram + offset))
200 written = ord(data[offset]) | \
201 (ord(data[offset+1]) << 8) | \
202 (ord(data[offset+2]) << 16) | \
203 (ord(data[offset+3]) << 24)
204 assertEqual(value, written)
205
206 b = tempfile.NamedTemporaryFile(suffix=".ihex")
207 self.gdb.command("dump ihex memory %s 0x%x 0x%x" % (b.name,
208 self.hart.ram, self.hart.ram + self.length))
209 self.gdb.command("shell cat %s" % b.name)
210 for line in b.xreadlines():
211 record_type, address, line_data = ihex_parse(line)
212 if record_type == 0:
213 written_data = data[address:address+len(line_data)]
214 if line_data != written_data:
215 raise TestFailed(
216 "Data mismatch at 0x%x; wrote %s but read %s" % (
217 address, readable_binary_string(written_data),
218 readable_binary_string(line_data)))
219
220 class InstantHaltTest(GdbTest):
221 def test(self):
222 """Assert that reset is really resetting what it should."""
223 self.gdb.command("monitor reset halt")
224 self.gdb.command("flushregs")
225 threads = self.gdb.threads()
226 pcs = []
227 for t in threads:
228 self.gdb.thread(t)
229 pcs.append(self.gdb.p("$pc"))
230 for pc in pcs:
231 assertIn(pc, self.hart.reset_vectors)
232 # mcycle and minstret have no defined reset value.
233 mstatus = self.gdb.p("$mstatus")
234 assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
235 MSTATUS_VM), 0)
236
237 class InstantChangePc(GdbTest):
238 def test(self):
239 """Change the PC right as we come out of reset."""
240 # 0x13 is nop
241 self.gdb.command("monitor reset halt")
242 self.gdb.command("flushregs")
243 self.gdb.command("p *((int*) 0x%x)=0x13" % self.hart.ram)
244 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 4))
245 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 8))
246 self.gdb.p("$pc=0x%x" % self.hart.ram)
247 self.gdb.stepi()
248 assertEqual((self.hart.ram + 4), self.gdb.p("$pc"))
249 self.gdb.stepi()
250 assertEqual((self.hart.ram + 8), self.gdb.p("$pc"))
251
252 class DebugTest(GdbSingleHartTest):
253 # Include malloc so that gdb can make function calls. I suspect this malloc
254 # will silently blow through the memory set aside for it, so be careful.
255 compile_args = ("programs/debug.c", "programs/checksum.c",
256 "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE")
257
258 def setup(self):
259 self.gdb.load()
260 self.gdb.b("_exit")
261
262 def exit(self, expected_result=0xc86455d4):
263 output = self.gdb.c()
264 assertIn("Breakpoint", output)
265 assertIn("_exit", output)
266 assertEqual(self.gdb.p("status"), expected_result)
267
268 class DebugCompareSections(DebugTest):
269 def test(self):
270 output = self.gdb.command("compare-sections")
271 matched = 0
272 for line in output.splitlines():
273 if line.startswith("Section"):
274 assert line.endswith("matched.")
275 matched += 1
276 assertGreater(matched, 1)
277
278 class DebugFunctionCall(DebugTest):
279 def test(self):
280 self.gdb.b("main:start")
281 self.gdb.c()
282 assertEqual(self.gdb.p('fib(6)'), 8)
283 assertEqual(self.gdb.p('fib(7)'), 13)
284 self.exit()
285
286 class DebugChangeString(DebugTest):
287 def test(self):
288 text = "This little piggy went to the market."
289 self.gdb.b("main:start")
290 self.gdb.c()
291 self.gdb.p('fox = "%s"' % text)
292 self.exit(0x43b497b8)
293
294 class DebugTurbostep(DebugTest):
295 def test(self):
296 """Single step a bunch of times."""
297 self.gdb.b("main:start")
298 self.gdb.c()
299 self.gdb.command("p i=0")
300 last_pc = None
301 advances = 0
302 jumps = 0
303 for _ in range(10):
304 self.gdb.stepi()
305 pc = self.gdb.p("$pc")
306 assertNotEqual(last_pc, pc)
307 if last_pc and pc > last_pc and pc - last_pc <= 4:
308 advances += 1
309 else:
310 jumps += 1
311 last_pc = pc
312 # Some basic sanity that we're not running between breakpoints or
313 # something.
314 assertGreater(jumps, 1)
315 assertGreater(advances, 5)
316
317 class DebugExit(DebugTest):
318 def test(self):
319 self.exit()
320
321 class DebugSymbols(DebugTest):
322 def test(self):
323 self.gdb.b("main")
324 self.gdb.b("rot13")
325 output = self.gdb.c()
326 assertIn(", main ", output)
327 output = self.gdb.c()
328 assertIn(", rot13 ", output)
329
330 class DebugBreakpoint(DebugTest):
331 def test(self):
332 self.gdb.b("rot13")
333 # The breakpoint should be hit exactly 2 times.
334 for _ in range(2):
335 output = self.gdb.c()
336 self.gdb.p("$pc")
337 assertIn("Breakpoint ", output)
338 assertIn("rot13 ", output)
339 self.exit()
340
341 class Hwbp1(DebugTest):
342 def test(self):
343 if self.hart.instruction_hardware_breakpoint_count < 1:
344 return 'not_applicable'
345
346 if not self.hart.honors_tdata1_hmode:
347 # Run to main before setting the breakpoint, because startup code
348 # will otherwise clear the trigger that we set.
349 self.gdb.b("main")
350 self.gdb.c()
351
352 self.gdb.hbreak("rot13")
353 # The breakpoint should be hit exactly 2 times.
354 for _ in range(2):
355 output = self.gdb.c()
356 self.gdb.p("$pc")
357 assertRegexpMatches(output, r"[bB]reakpoint")
358 assertIn("rot13 ", output)
359 self.exit()
360
361 class Hwbp2(DebugTest):
362 def test(self):
363 if self.hart.instruction_hardware_breakpoint_count < 2:
364 return 'not_applicable'
365
366 self.gdb.hbreak("main")
367 self.gdb.hbreak("rot13")
368 # We should hit 3 breakpoints.
369 for expected in ("main", "rot13", "rot13"):
370 output = self.gdb.c()
371 self.gdb.p("$pc")
372 assertRegexpMatches(output, r"[bB]reakpoint")
373 assertIn("%s " % expected, output)
374 self.exit()
375
376 class TooManyHwbp(DebugTest):
377 def test(self):
378 for i in range(30):
379 self.gdb.hbreak("*rot13 + %d" % (i * 4))
380
381 output = self.gdb.c()
382 assertIn("Cannot insert hardware breakpoint", output)
383 # Clean up, otherwise the hardware breakpoints stay set and future
384 # tests may fail.
385 self.gdb.command("D")
386
387 class Registers(DebugTest):
388 def test(self):
389 # Get to a point in the code where some registers have actually been
390 # used.
391 self.gdb.b("rot13")
392 self.gdb.c()
393 self.gdb.c()
394 # Try both forms to test gdb.
395 for cmd in ("info all-registers", "info registers all"):
396 output = self.gdb.command(cmd)
397 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
398 assertIn(reg, output)
399 for line in output.splitlines():
400 assertRegexpMatches(line, r"^\S")
401
402 #TODO
403 # mcpuid is one of the few registers that should have the high bit set
404 # (for rv64).
405 # Leave this commented out until gdb and spike agree on the encoding of
406 # mcpuid (which is going to be renamed to misa in any case).
407 #assertRegexpMatches(output, ".*mcpuid *0x80")
408
409 #TODO:
410 # The instret register should always be changing.
411 #last_instret = None
412 #for _ in range(5):
413 # instret = self.gdb.p("$instret")
414 # assertNotEqual(instret, last_instret)
415 # last_instret = instret
416 # self.gdb.stepi()
417
418 self.exit()
419
420 class UserInterrupt(DebugTest):
421 def test(self):
422 """Sending gdb ^C while the program is running should cause it to
423 halt."""
424 self.gdb.b("main:start")
425 self.gdb.c()
426 self.gdb.p("i=123")
427 self.gdb.c(wait=False)
428 time.sleep(2)
429 output = self.gdb.interrupt()
430 assert "main" in output
431 assertGreater(self.gdb.p("j"), 10)
432 self.gdb.p("i=0")
433 self.exit()
434
435 class InterruptTest(GdbSingleHartTest):
436 compile_args = ("programs/interrupt.c",)
437
438 def early_applicable(self):
439 return self.target.supports_clint_mtime
440
441 def setup(self):
442 self.gdb.load()
443
444 def test(self):
445 self.gdb.b("main")
446 output = self.gdb.c()
447 assertIn(" main ", output)
448 self.gdb.b("trap_entry")
449 output = self.gdb.c()
450 assertIn(" trap_entry ", output)
451 assertEqual(self.gdb.p("$mip") & 0x80, 0x80)
452 assertEqual(self.gdb.p("interrupt_count"), 0)
453 # You'd expect local to still be 0, but it looks like spike doesn't
454 # jump to the interrupt handler immediately after the write to
455 # mtimecmp.
456 assertLess(self.gdb.p("local"), 1000)
457 self.gdb.command("delete breakpoints")
458 for _ in range(10):
459 self.gdb.c(wait=False)
460 time.sleep(2)
461 self.gdb.interrupt()
462 interrupt_count = self.gdb.p("interrupt_count")
463 local = self.gdb.p("local")
464 if interrupt_count > 1000 and \
465 local > 1000:
466 return
467
468 assertGreater(interrupt_count, 1000)
469 assertGreater(local, 1000)
470
471 def postMortem(self):
472 GdbSingleHartTest.postMortem(self)
473 self.gdb.p("*((long long*) 0x200bff8)")
474 self.gdb.p("*((long long*) 0x2004000)")
475 self.gdb.p("interrupt_count")
476 self.gdb.p("local")
477
478 class MulticoreRegTest(GdbTest):
479 compile_args = ("programs/infinite_loop.S", "-DMULTICORE")
480
481 def early_applicable(self):
482 return len(self.target.harts) > 1
483
484 def setup(self):
485 self.gdb.load()
486 for hart in self.target.harts:
487 self.gdb.select_hart(hart)
488 self.gdb.p("$pc=_start")
489
490 def test(self):
491 # Run to main
492 for hart in self.target.harts:
493 self.gdb.select_hart(hart)
494 self.gdb.b("main")
495 self.gdb.c()
496 assertIn("main", self.gdb.where())
497 self.gdb.command("delete breakpoints")
498
499 # Run through the entire loop.
500 for hart in self.target.harts:
501 self.gdb.select_hart(hart)
502 self.gdb.b("main_end")
503 self.gdb.c()
504 assertIn("main_end", self.gdb.where())
505
506 hart_ids = []
507 for hart in self.target.harts:
508 self.gdb.select_hart(hart)
509 # Check register values.
510 hart_id = self.gdb.p("$x1")
511 assertNotIn(hart_id, hart_ids)
512 hart_ids.append(hart_id)
513 for n in range(2, 32):
514 value = self.gdb.p("$x%d" % n)
515 assertEqual(value, hart_ids[-1] + n - 1)
516
517 # Confirmed that we read different register values for different harts.
518 # Write a new value to x1, and run through the add sequence again.
519
520 for hart in self.target.harts:
521 self.gdb.select_hart(hart)
522 self.gdb.p("$x1=0x%x" % (hart.index * 0x800))
523 self.gdb.p("$pc=main_post_csrr")
524 self.gdb.c()
525 for hart in self.target.harts:
526 self.gdb.select_hart(hart)
527 assertIn("main", self.gdb.where())
528 # Check register values.
529 for n in range(1, 32):
530 value = self.gdb.p("$x%d" % n)
531 assertEqual(value, hart.index * 0x800 + n - 1)
532
533 class MulticoreRunHaltStepiTest(GdbTest):
534 compile_args = ("programs/multicore.c", "-DMULTICORE")
535
536 def early_applicable(self):
537 return len(self.target.harts) > 1
538
539 def setup(self):
540 self.gdb.load()
541 for hart in self.target.harts:
542 self.gdb.select_hart(hart)
543 self.gdb.p("$pc=_start")
544
545 def test(self):
546 previous_hart_count = [0 for h in self.target.harts]
547 previous_interrupt_count = [0 for h in self.target.harts]
548 for _ in range(10):
549 self.gdb.c(wait=False)
550 time.sleep(2)
551 self.gdb.interrupt()
552 self.gdb.p("$mie")
553 self.gdb.p("$mip")
554 self.gdb.p("$mstatus")
555 self.gdb.p("$priv")
556 self.gdb.p("buf", fmt="")
557 hart_count = self.gdb.p("hart_count")
558 interrupt_count = self.gdb.p("interrupt_count")
559 for i, h in enumerate(self.target.harts):
560 assertGreater(hart_count[i], previous_hart_count[i])
561 assertGreater(interrupt_count[i], previous_interrupt_count[i])
562 self.gdb.select_hart(h)
563 pc = self.gdb.p("$pc")
564 self.gdb.stepi()
565 stepped_pc = self.gdb.p("$pc")
566 assertNotEqual(pc, stepped_pc)
567
568 class StepTest(GdbTest):
569 compile_args = ("programs/step.S", )
570
571 def setup(self):
572 self.gdb.load()
573 self.gdb.b("main")
574 self.gdb.c()
575
576 def test(self):
577 main_address = self.gdb.p("$pc")
578 if self.hart.extensionSupported("c"):
579 sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
580 else:
581 sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
582 for expected in sequence:
583 self.gdb.stepi()
584 pc = self.gdb.p("$pc")
585 assertEqual("%x" % (pc - main_address), "%x" % expected)
586
587 class TriggerTest(GdbTest):
588 compile_args = ("programs/trigger.S", )
589 def setup(self):
590 self.gdb.load()
591 self.gdb.b("_exit")
592 self.gdb.b("main")
593 self.gdb.c()
594
595 def exit(self):
596 output = self.gdb.c()
597 assertIn("Breakpoint", output)
598 assertIn("_exit", output)
599
600 class TriggerExecuteInstant(TriggerTest):
601 """Test an execute breakpoint on the first instruction executed out of
602 debug mode."""
603 def test(self):
604 main_address = self.gdb.p("$pc")
605 self.gdb.command("hbreak *0x%x" % (main_address + 4))
606 self.gdb.c()
607 assertEqual(self.gdb.p("$pc"), main_address+4)
608
609 # FIXME: Triggers aren't quite working yet
610 #class TriggerLoadAddress(TriggerTest):
611 # def test(self):
612 # self.gdb.command("rwatch *((&data)+1)")
613 # output = self.gdb.c()
614 # assertIn("read_loop", output)
615 # assertEqual(self.gdb.p("$a0"),
616 # self.gdb.p("(&data)+1"))
617 # self.exit()
618
619 class TriggerLoadAddressInstant(TriggerTest):
620 """Test a load address breakpoint on the first instruction executed out of
621 debug mode."""
622 def test(self):
623 self.gdb.command("b just_before_read_loop")
624 self.gdb.c()
625 read_loop = self.gdb.p("&read_loop")
626 self.gdb.command("rwatch data")
627 self.gdb.c()
628 # Accept hitting the breakpoint before or after the load instruction.
629 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
630 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
631
632 # FIXME: Triggers aren't quite working yet
633 #class TriggerStoreAddress(TriggerTest):
634 # def test(self):
635 # self.gdb.command("watch *((&data)+3)")
636 # output = self.gdb.c()
637 # assertIn("write_loop", output)
638 # assertEqual(self.gdb.p("$a0"),
639 # self.gdb.p("(&data)+3"))
640 # self.exit()
641
642 class TriggerStoreAddressInstant(TriggerTest):
643 def test(self):
644 """Test a store address breakpoint on the first instruction executed out
645 of debug mode."""
646 self.gdb.command("b just_before_write_loop")
647 self.gdb.c()
648 write_loop = self.gdb.p("&write_loop")
649 self.gdb.command("watch data")
650 self.gdb.c()
651 # Accept hitting the breakpoint before or after the store instruction.
652 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
653 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
654
655 class TriggerDmode(TriggerTest):
656 def early_applicable(self):
657 return self.hart.honors_tdata1_hmode
658
659 def check_triggers(self, tdata1_lsbs, tdata2):
660 dmode = 1 << (self.hart.xlen-5)
661
662 triggers = []
663
664 if self.hart.xlen == 32:
665 xlen_type = 'int'
666 elif self.hart.xlen == 64:
667 xlen_type = 'long long'
668 else:
669 raise NotImplementedError
670
671 dmode_count = 0
672 i = 0
673 for i in range(16):
674 tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i))
675 if tdata1 == 0:
676 break
677 tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1))
678
679 if tdata1 & dmode:
680 dmode_count += 1
681 else:
682 assertEqual(tdata1 & 0xffff, tdata1_lsbs)
683 assertEqual(tdata2, tdata2)
684
685 assertGreater(i, 1)
686 assertEqual(dmode_count, 1)
687
688 return triggers
689
690 def test(self):
691 self.gdb.command("hbreak write_load_trigger")
692 self.gdb.b("clear_triggers")
693 self.gdb.p("$pc=write_store_trigger")
694 output = self.gdb.c()
695 assertIn("write_load_trigger", output)
696 self.check_triggers((1<<6) | (1<<1), 0xdeadbee0)
697 output = self.gdb.c()
698 assertIn("clear_triggers", output)
699 self.check_triggers((1<<6) | (1<<0), 0xfeedac00)
700
701 class RegsTest(GdbTest):
702 compile_args = ("programs/regs.S", )
703 def setup(self):
704 self.gdb.load()
705 self.gdb.b("main")
706 self.gdb.b("handle_trap")
707 self.gdb.c()
708
709 class WriteGprs(RegsTest):
710 def test(self):
711 regs = [("x%d" % n) for n in range(2, 32)]
712
713 self.gdb.p("$pc=write_regs")
714 for i, r in enumerate(regs):
715 self.gdb.p("$%s=%d" % (r, (0xdeadbeef<<i)+17))
716 self.gdb.p("$x1=data")
717 self.gdb.command("b all_done")
718 output = self.gdb.c()
719 assertIn("Breakpoint ", output)
720
721 # Just to get this data in the log.
722 self.gdb.command("x/30gx data")
723 self.gdb.command("info registers")
724 for n in range(len(regs)):
725 assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
726 ((0xdeadbeef<<n)+17) & ((1<<self.hart.xlen)-1))
727
728 class WriteCsrs(RegsTest):
729 def test(self):
730 # As much a test of gdb as of the simulator.
731 self.gdb.p("$mscratch=0")
732 self.gdb.stepi()
733 assertEqual(self.gdb.p("$mscratch"), 0)
734 self.gdb.p("$mscratch=123")
735 self.gdb.stepi()
736 assertEqual(self.gdb.p("$mscratch"), 123)
737
738 self.gdb.p("$pc=write_regs")
739 self.gdb.p("$x1=data")
740 self.gdb.command("b all_done")
741 self.gdb.command("c")
742
743 assertEqual(123, self.gdb.p("$mscratch"))
744 assertEqual(123, self.gdb.p("$x1"))
745 assertEqual(123, self.gdb.p("$csr832"))
746
747 class DownloadTest(GdbTest):
748 def setup(self):
749 # pylint: disable=attribute-defined-outside-init
750 length = min(2**10, self.hart.ram_size - 2048)
751 self.download_c = tempfile.NamedTemporaryFile(prefix="download_",
752 suffix=".c", delete=False)
753 self.download_c.write("#include <stdint.h>\n")
754 self.download_c.write(
755 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
756 self.download_c.write("uint32_t length = %d;\n" % length)
757 self.download_c.write("uint8_t d[%d] = {\n" % length)
758 self.crc = 0
759 assert length % 16 == 0
760 for i in range(length / 16):
761 self.download_c.write(" /* 0x%04x */ " % (i * 16))
762 for _ in range(16):
763 value = random.randrange(1<<8)
764 self.download_c.write("0x%02x, " % value)
765 self.crc = binascii.crc32("%c" % value, self.crc)
766 self.download_c.write("\n")
767 self.download_c.write("};\n")
768 self.download_c.write("uint8_t *data = &d[0];\n")
769 self.download_c.write(
770 "uint32_t main() { return crc32a(data, length); }\n")
771 self.download_c.flush()
772
773 if self.crc < 0:
774 self.crc += 2**32
775
776 self.binary = self.target.compile(self.hart, self.download_c.name,
777 "programs/checksum.c")
778 self.gdb.command("file %s" % self.binary)
779
780 def test(self):
781 self.gdb.load()
782 self.gdb.command("b _exit")
783 self.gdb.c(timeout=60)
784 assertEqual(self.gdb.p("status"), self.crc)
785 os.unlink(self.download_c.name)
786
787 #class MprvTest(GdbTest):
788 # compile_args = ("programs/mprv.S", )
789 # def setup(self):
790 # self.gdb.load()
791 #
792 # def test(self):
793 # """Test that the debugger can access memory when MPRV is set."""
794 # self.gdb.c(wait=False)
795 # time.sleep(0.5)
796 # self.gdb.interrupt()
797 # output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
798 # assertIn("0xbead", output)
799
800 class PrivTest(GdbTest):
801 compile_args = ("programs/priv.S", )
802 def setup(self):
803 # pylint: disable=attribute-defined-outside-init
804 self.gdb.load()
805
806 misa = self.hart.misa
807 self.supported = set()
808 if misa & (1<<20):
809 self.supported.add(0)
810 if misa & (1<<18):
811 self.supported.add(1)
812 if misa & (1<<7):
813 self.supported.add(2)
814 self.supported.add(3)
815
816 class PrivRw(PrivTest):
817 def test(self):
818 """Test reading/writing priv."""
819 # Disable physical memory protection by allowing U mode access to all
820 # memory.
821 self.gdb.p("$pmpcfg0=0xf") # TOR, R, W, X
822 self.gdb.p("$pmpaddr0=0x%x" %
823 ((self.hart.ram + self.hart.ram_size) >> 2))
824
825 # Leave the PC at _start, where the first 4 instructions should be
826 # legal in any mode.
827 for privilege in range(4):
828 self.gdb.p("$priv=%d" % privilege)
829 self.gdb.stepi()
830 actual = self.gdb.p("$priv")
831 assertIn(actual, self.supported)
832 if privilege in self.supported:
833 assertEqual(actual, privilege)
834
835 class PrivChange(PrivTest):
836 def test(self):
837 """Test that the core's privilege level actually changes."""
838
839 if 0 not in self.supported:
840 return 'not_applicable'
841
842 self.gdb.b("main")
843 self.gdb.c()
844
845 # Machine mode
846 self.gdb.p("$priv=3")
847 main_address = self.gdb.p("$pc")
848 self.gdb.stepi()
849 assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
850
851 # User mode
852 self.gdb.p("$priv=0")
853 self.gdb.stepi()
854 # Should have taken an exception, so be nowhere near main.
855 pc = self.gdb.p("$pc")
856 assertTrue(pc < main_address or pc > main_address + 0x100)
857
858 parsed = None
859 def main():
860 parser = argparse.ArgumentParser(
861 description="Test that gdb can talk to a RISC-V target.",
862 epilog="""
863 Example command line from the real world:
864 Run all RegsTest cases against a physical FPGA, with custom openocd command:
865 ./gdbserver.py --freedom-e300 --server_cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
866 """)
867 targets.add_target_options(parser)
868
869 testlib.add_test_run_options(parser)
870
871 # TODO: remove global
872 global parsed # pylint: disable=global-statement
873 parsed = parser.parse_args()
874 target = targets.target(parsed)
875 testlib.print_log_names = parsed.print_log_names
876
877 module = sys.modules[__name__]
878
879 return testlib.run_all_tests(module, target, parsed)
880
881 # TROUBLESHOOTING TIPS
882 # If a particular test fails, run just that one test, eg.:
883 # ./gdbserver.py MprvTest.test_mprv
884 # Then inspect gdb.log and spike.log to see what happened in more detail.
885
886 if __name__ == '__main__':
887 sys.exit(main())