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