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