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