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