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