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