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