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