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