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