Test FPRs that aren't XLEN in size.
[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 StepTest(GdbTest):
578 compile_args = ("programs/step.S", )
579
580 def setup(self):
581 self.gdb.load()
582 self.gdb.b("main")
583 self.gdb.c()
584
585 def test(self):
586 main_address = self.gdb.p("$pc")
587 if self.hart.extensionSupported("c"):
588 sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
589 else:
590 sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
591 for expected in sequence:
592 self.gdb.stepi()
593 pc = self.gdb.p("$pc")
594 assertEqual("%x" % (pc - main_address), "%x" % expected)
595
596 class TriggerTest(GdbTest):
597 compile_args = ("programs/trigger.S", )
598 def setup(self):
599 self.gdb.load()
600 self.gdb.b("_exit")
601 self.gdb.b("main")
602 self.gdb.c()
603
604 def exit(self):
605 output = self.gdb.c()
606 assertIn("Breakpoint", output)
607 assertIn("_exit", output)
608
609 class TriggerExecuteInstant(TriggerTest):
610 """Test an execute breakpoint on the first instruction executed out of
611 debug mode."""
612 def test(self):
613 main_address = self.gdb.p("$pc")
614 self.gdb.command("hbreak *0x%x" % (main_address + 4))
615 self.gdb.c()
616 assertEqual(self.gdb.p("$pc"), main_address+4)
617
618 # FIXME: Triggers aren't quite working yet
619 #class TriggerLoadAddress(TriggerTest):
620 # def test(self):
621 # self.gdb.command("rwatch *((&data)+1)")
622 # output = self.gdb.c()
623 # assertIn("read_loop", output)
624 # assertEqual(self.gdb.p("$a0"),
625 # self.gdb.p("(&data)+1"))
626 # self.exit()
627
628 class TriggerLoadAddressInstant(TriggerTest):
629 """Test a load address breakpoint on the first instruction executed out of
630 debug mode."""
631 def test(self):
632 self.gdb.command("b just_before_read_loop")
633 self.gdb.c()
634 read_loop = self.gdb.p("&read_loop")
635 self.gdb.command("rwatch data")
636 self.gdb.c()
637 # Accept hitting the breakpoint before or after the load instruction.
638 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
639 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
640
641 # FIXME: Triggers aren't quite working yet
642 #class TriggerStoreAddress(TriggerTest):
643 # def test(self):
644 # self.gdb.command("watch *((&data)+3)")
645 # output = self.gdb.c()
646 # assertIn("write_loop", output)
647 # assertEqual(self.gdb.p("$a0"),
648 # self.gdb.p("(&data)+3"))
649 # self.exit()
650
651 class TriggerStoreAddressInstant(TriggerTest):
652 def test(self):
653 """Test a store address breakpoint on the first instruction executed out
654 of debug mode."""
655 self.gdb.command("b just_before_write_loop")
656 self.gdb.c()
657 write_loop = self.gdb.p("&write_loop")
658 self.gdb.command("watch data")
659 self.gdb.c()
660 # Accept hitting the breakpoint before or after the store instruction.
661 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
662 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
663
664 class TriggerDmode(TriggerTest):
665 def early_applicable(self):
666 return self.hart.honors_tdata1_hmode
667
668 def check_triggers(self, tdata1_lsbs, tdata2):
669 dmode = 1 << (self.hart.xlen-5)
670
671 triggers = []
672
673 if self.hart.xlen == 32:
674 xlen_type = 'int'
675 elif self.hart.xlen == 64:
676 xlen_type = 'long long'
677 else:
678 raise NotImplementedError
679
680 dmode_count = 0
681 i = 0
682 for i in range(16):
683 tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i))
684 if tdata1 == 0:
685 break
686 tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1))
687
688 if tdata1 & dmode:
689 dmode_count += 1
690 else:
691 assertEqual(tdata1 & 0xffff, tdata1_lsbs)
692 assertEqual(tdata2, tdata2)
693
694 assertGreater(i, 1)
695 assertEqual(dmode_count, 1)
696
697 return triggers
698
699 def test(self):
700 self.gdb.command("hbreak write_load_trigger")
701 self.gdb.b("clear_triggers")
702 self.gdb.p("$pc=write_store_trigger")
703 output = self.gdb.c()
704 assertIn("write_load_trigger", output)
705 self.check_triggers((1<<6) | (1<<1), 0xdeadbee0)
706 output = self.gdb.c()
707 assertIn("clear_triggers", output)
708 self.check_triggers((1<<6) | (1<<0), 0xfeedac00)
709
710 class RegsTest(GdbTest):
711 compile_args = ("programs/regs.S", )
712 def setup(self):
713 self.gdb.load()
714 self.gdb.b("main")
715 self.gdb.b("handle_trap")
716 self.gdb.c()
717
718 class WriteGprs(RegsTest):
719 def test(self):
720 regs = [("x%d" % n) for n in range(2, 32)]
721
722 self.gdb.p("$pc=write_regs")
723 for i, r in enumerate(regs):
724 self.gdb.p("$%s=%d" % (r, (0xdeadbeef<<i)+17))
725 self.gdb.p("$x1=data")
726 self.gdb.command("b all_done")
727 output = self.gdb.c()
728 assertIn("Breakpoint ", output)
729
730 # Just to get this data in the log.
731 self.gdb.command("x/30gx data")
732 self.gdb.command("info registers")
733 for n in range(len(regs)):
734 assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
735 ((0xdeadbeef<<n)+17) & ((1<<self.hart.xlen)-1))
736
737 class WriteCsrs(RegsTest):
738 def test(self):
739 # As much a test of gdb as of the simulator.
740 self.gdb.p("$mscratch=0")
741 self.gdb.stepi()
742 assertEqual(self.gdb.p("$mscratch"), 0)
743 self.gdb.p("$mscratch=123")
744 self.gdb.stepi()
745 assertEqual(self.gdb.p("$mscratch"), 123)
746
747 self.gdb.p("$pc=write_regs")
748 self.gdb.p("$x1=data")
749 self.gdb.command("b all_done")
750 self.gdb.command("c")
751
752 assertEqual(123, self.gdb.p("$mscratch"))
753 assertEqual(123, self.gdb.p("$x1"))
754 assertEqual(123, self.gdb.p("$csr832"))
755
756 class DownloadTest(GdbTest):
757 def setup(self):
758 # pylint: disable=attribute-defined-outside-init
759 length = min(2**10, self.hart.ram_size - 2048)
760 self.download_c = tempfile.NamedTemporaryFile(prefix="download_",
761 suffix=".c", delete=False)
762 self.download_c.write("#include <stdint.h>\n")
763 self.download_c.write(
764 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
765 self.download_c.write("uint32_t length = %d;\n" % length)
766 self.download_c.write("uint8_t d[%d] = {\n" % length)
767 self.crc = 0
768 assert length % 16 == 0
769 for i in range(length / 16):
770 self.download_c.write(" /* 0x%04x */ " % (i * 16))
771 for _ in range(16):
772 value = random.randrange(1<<8)
773 self.download_c.write("0x%02x, " % value)
774 self.crc = binascii.crc32("%c" % value, self.crc)
775 self.download_c.write("\n")
776 self.download_c.write("};\n")
777 self.download_c.write("uint8_t *data = &d[0];\n")
778 self.download_c.write(
779 "uint32_t main() { return crc32a(data, length); }\n")
780 self.download_c.flush()
781
782 if self.crc < 0:
783 self.crc += 2**32
784
785 self.binary = self.target.compile(self.hart, self.download_c.name,
786 "programs/checksum.c")
787 self.gdb.command("file %s" % self.binary)
788
789 def test(self):
790 self.gdb.load()
791 self.gdb.command("b _exit")
792 self.gdb.c(timeout=60)
793 assertEqual(self.gdb.p("status"), self.crc)
794 os.unlink(self.download_c.name)
795
796 #class MprvTest(GdbTest):
797 # compile_args = ("programs/mprv.S", )
798 # def setup(self):
799 # self.gdb.load()
800 #
801 # def test(self):
802 # """Test that the debugger can access memory when MPRV is set."""
803 # self.gdb.c(wait=False)
804 # time.sleep(0.5)
805 # self.gdb.interrupt()
806 # output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
807 # assertIn("0xbead", output)
808
809 class PrivTest(GdbTest):
810 compile_args = ("programs/priv.S", )
811 def setup(self):
812 # pylint: disable=attribute-defined-outside-init
813 self.gdb.load()
814
815 misa = self.hart.misa
816 self.supported = set()
817 if misa & (1<<20):
818 self.supported.add(0)
819 if misa & (1<<18):
820 self.supported.add(1)
821 if misa & (1<<7):
822 self.supported.add(2)
823 self.supported.add(3)
824
825 class PrivRw(PrivTest):
826 def test(self):
827 """Test reading/writing priv."""
828 # Disable physical memory protection by allowing U mode access to all
829 # memory.
830 self.gdb.p("$pmpcfg0=0xf") # TOR, R, W, X
831 self.gdb.p("$pmpaddr0=0x%x" %
832 ((self.hart.ram + self.hart.ram_size) >> 2))
833
834 # Leave the PC at _start, where the first 4 instructions should be
835 # legal in any mode.
836 for privilege in range(4):
837 self.gdb.p("$priv=%d" % privilege)
838 self.gdb.stepi()
839 actual = self.gdb.p("$priv")
840 assertIn(actual, self.supported)
841 if privilege in self.supported:
842 assertEqual(actual, privilege)
843
844 class PrivChange(PrivTest):
845 def test(self):
846 """Test that the core's privilege level actually changes."""
847
848 if 0 not in self.supported:
849 return 'not_applicable'
850
851 self.gdb.b("main")
852 self.gdb.c()
853
854 # Machine mode
855 self.gdb.p("$priv=3")
856 main_address = self.gdb.p("$pc")
857 self.gdb.stepi()
858 assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
859
860 # User mode
861 self.gdb.p("$priv=0")
862 self.gdb.stepi()
863 # Should have taken an exception, so be nowhere near main.
864 pc = self.gdb.p("$pc")
865 assertTrue(pc < main_address or pc > main_address + 0x100)
866
867 parsed = None
868 def main():
869 parser = argparse.ArgumentParser(
870 description="Test that gdb can talk to a RISC-V target.",
871 epilog="""
872 Example command line from the real world:
873 Run all RegsTest cases against a physical FPGA, with custom openocd command:
874 ./gdbserver.py --freedom-e300 --server_cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
875 """)
876 targets.add_target_options(parser)
877
878 testlib.add_test_run_options(parser)
879
880 # TODO: remove global
881 global parsed # pylint: disable=global-statement
882 parsed = parser.parse_args()
883 target = targets.target(parsed)
884 testlib.print_log_names = parsed.print_log_names
885
886 module = sys.modules[__name__]
887
888 return testlib.run_all_tests(module, target, parsed)
889
890 # TROUBLESHOOTING TIPS
891 # If a particular test fails, run just that one test, eg.:
892 # ./gdbserver.py MprvTest.test_mprv
893 # Then inspect gdb.log and spike.log to see what happened in more detail.
894
895 if __name__ == '__main__':
896 sys.exit(main())