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