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