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