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