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