Increase delay in UserInterrupt.
[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
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.target.xlen)
70 b = random.randrange(1<<self.target.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.target.ram)
81 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
82 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
83 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 12))
84 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 16))
85 self.gdb.p("$pc=0x%x" % self.target.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.target.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.target.ram
128 addrB = self.target.ram + self.target.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.target.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.target.ram)
172
173 class MemTestBlock(GdbTest):
174 def test(self):
175 length = 1024
176 line_length = 16
177 a = tempfile.NamedTemporaryFile(suffix=".ihex")
178 data = ""
179 for i in range(length / line_length):
180 line_data = "".join(["%c" % random.randrange(256)
181 for _ in range(line_length)])
182 data += line_data
183 a.write(ihex_line(i * line_length, 0, line_data))
184 a.flush()
185
186 self.gdb.command("restore %s 0x%x" % (a.name, self.target.ram))
187 for offset in range(0, length, 19*4) + [length-4]:
188 value = self.gdb.p("*((int*)0x%x)" % (self.target.ram + offset))
189 written = ord(data[offset]) | \
190 (ord(data[offset+1]) << 8) | \
191 (ord(data[offset+2]) << 16) | \
192 (ord(data[offset+3]) << 24)
193 assertEqual(value, written)
194
195 b = tempfile.NamedTemporaryFile(suffix=".ihex")
196 self.gdb.command("dump ihex memory %s 0x%x 0x%x" % (b.name,
197 self.target.ram, self.target.ram + length))
198 for line in b:
199 record_type, address, line_data = ihex_parse(line)
200 if record_type == 0:
201 assertEqual(readable_binary_string(line_data),
202 readable_binary_string(
203 data[address:address+len(line_data)]))
204
205 class InstantHaltTest(GdbTest):
206 def test(self):
207 """Assert that reset is really resetting what it should."""
208 self.gdb.command("monitor reset halt")
209 self.gdb.command("flushregs")
210 threads = self.gdb.threads()
211 pcs = []
212 for t in threads:
213 self.gdb.thread(t)
214 pcs.append(self.gdb.p("$pc"))
215 for pc in pcs:
216 assertEqual(self.target.reset_vector, pc)
217 # mcycle and minstret have no defined reset value.
218 mstatus = self.gdb.p("$mstatus")
219 assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
220 MSTATUS_VM), 0)
221
222 class InstantChangePc(GdbTest):
223 def test(self):
224 """Change the PC right as we come out of reset."""
225 # 0x13 is nop
226 self.gdb.command("monitor reset halt")
227 self.gdb.command("flushregs")
228 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
229 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
230 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
231 self.gdb.p("$pc=0x%x" % self.target.ram)
232 self.gdb.stepi()
233 assertEqual((self.target.ram + 4), self.gdb.p("$pc"))
234 self.gdb.stepi()
235 assertEqual((self.target.ram + 8), self.gdb.p("$pc"))
236
237 class DebugTest(GdbTest):
238 # Include malloc so that gdb can make function calls. I suspect this malloc
239 # will silently blow through the memory set aside for it, so be careful.
240 compile_args = ("programs/debug.c", "programs/checksum.c",
241 "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE")
242
243 def setup(self):
244 self.gdb.load()
245 self.gdb.b("_exit")
246
247 def exit(self, expected_result=0xc86455d4):
248 output = self.gdb.c()
249 assertIn("Breakpoint", output)
250 assertIn("_exit", output)
251 assertEqual(self.gdb.p("status"), expected_result)
252
253 class DebugCompareSections(DebugTest):
254 def test(self):
255 output = self.gdb.command("compare-sections")
256 matched = 0
257 for line in output.splitlines():
258 if line.startswith("Section"):
259 assert line.endswith("matched.")
260 matched += 1
261 assertGreater(matched, 1)
262
263 class DebugFunctionCall(DebugTest):
264 def test(self):
265 self.gdb.b("main:start")
266 self.gdb.c()
267 assertEqual(self.gdb.p('fib(6)'), 8)
268 assertEqual(self.gdb.p('fib(7)'), 13)
269 self.exit()
270
271 class DebugChangeString(DebugTest):
272 def test(self):
273 text = "This little piggy went to the market."
274 self.gdb.b("main:start")
275 self.gdb.c()
276 self.gdb.p('fox = "%s"' % text)
277 self.exit(0x43b497b8)
278
279 class DebugTurbostep(DebugTest):
280 def test(self):
281 """Single step a bunch of times."""
282 self.gdb.b("main:start")
283 self.gdb.c()
284 self.gdb.command("p i=0")
285 last_pc = None
286 advances = 0
287 jumps = 0
288 for _ in range(10):
289 self.gdb.stepi()
290 pc = self.gdb.p("$pc")
291 assertNotEqual(last_pc, pc)
292 if last_pc and pc > last_pc and pc - last_pc <= 4:
293 advances += 1
294 else:
295 jumps += 1
296 last_pc = pc
297 # Some basic sanity that we're not running between breakpoints or
298 # something.
299 assertGreater(jumps, 1)
300 assertGreater(advances, 5)
301
302 class DebugExit(DebugTest):
303 def test(self):
304 self.exit()
305
306 class DebugSymbols(DebugTest):
307 def test(self):
308 self.gdb.b("main")
309 self.gdb.b("rot13")
310 output = self.gdb.c()
311 assertIn(", main ", output)
312 output = self.gdb.c()
313 assertIn(", rot13 ", output)
314
315 class DebugBreakpoint(DebugTest):
316 def test(self):
317 self.gdb.b("rot13")
318 # The breakpoint should be hit exactly 2 times.
319 for _ in range(2):
320 output = self.gdb.c()
321 self.gdb.p("$pc")
322 assertIn("Breakpoint ", output)
323 assertIn("rot13 ", output)
324 self.exit()
325
326 class Hwbp1(DebugTest):
327 def test(self):
328 if self.target.instruction_hardware_breakpoint_count < 1:
329 return 'not_applicable'
330
331 if not self.target.honors_tdata1_hmode:
332 # Run to main before setting the breakpoint, because startup code
333 # will otherwise clear the trigger that we set.
334 self.gdb.b("main")
335 self.gdb.c()
336
337 self.gdb.hbreak("rot13")
338 # The breakpoint should be hit exactly 2 times.
339 for _ in range(2):
340 output = self.gdb.c()
341 self.gdb.p("$pc")
342 assertRegexpMatches(output, r"[bB]reakpoint")
343 assertIn("rot13 ", output)
344 self.exit()
345
346 class Hwbp2(DebugTest):
347 def test(self):
348 if self.target.instruction_hardware_breakpoint_count < 2:
349 return 'not_applicable'
350
351 self.gdb.hbreak("main")
352 self.gdb.hbreak("rot13")
353 # We should hit 3 breakpoints.
354 for expected in ("main", "rot13", "rot13"):
355 output = self.gdb.c()
356 self.gdb.p("$pc")
357 assertRegexpMatches(output, r"[bB]reakpoint")
358 assertIn("%s " % expected, output)
359 self.exit()
360
361 class TooManyHwbp(DebugTest):
362 def run(self):
363 for i in range(30):
364 self.gdb.hbreak("*rot13 + %d" % (i * 4))
365
366 output = self.gdb.c()
367 assertIn("Cannot insert hardware breakpoint", output)
368 # Clean up, otherwise the hardware breakpoints stay set and future
369 # tests may fail.
370 self.gdb.command("D")
371
372 class Registers(DebugTest):
373 def test(self):
374 # Get to a point in the code where some registers have actually been
375 # used.
376 self.gdb.b("rot13")
377 self.gdb.c()
378 self.gdb.c()
379 # Try both forms to test gdb.
380 for cmd in ("info all-registers", "info registers all"):
381 output = self.gdb.command(cmd)
382 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
383 assertIn(reg, output)
384
385 #TODO
386 # mcpuid is one of the few registers that should have the high bit set
387 # (for rv64).
388 # Leave this commented out until gdb and spike agree on the encoding of
389 # mcpuid (which is going to be renamed to misa in any case).
390 #assertRegexpMatches(output, ".*mcpuid *0x80")
391
392 #TODO:
393 # The instret register should always be changing.
394 #last_instret = None
395 #for _ in range(5):
396 # instret = self.gdb.p("$instret")
397 # assertNotEqual(instret, last_instret)
398 # last_instret = instret
399 # self.gdb.stepi()
400
401 self.exit()
402
403 class UserInterrupt(DebugTest):
404 def test(self):
405 """Sending gdb ^C while the program is running should cause it to
406 halt."""
407 self.gdb.b("main:start")
408 self.gdb.c()
409 self.gdb.p("i=123")
410 self.gdb.c(wait=False)
411 time.sleep(2)
412 output = self.gdb.interrupt()
413 assert "main" in output
414 assertGreater(self.gdb.p("j"), 10)
415 self.gdb.p("i=0")
416 self.exit()
417
418 class MulticoreTest(GdbTest):
419 compile_args = ("programs/infinite_loop.S", )
420
421 def setup(self):
422 self.gdb.load()
423
424 def test(self):
425 threads = self.gdb.threads()
426 if len(threads) < 2:
427 return 'not_applicable'
428
429 for t in threads:
430 self.gdb.thread(t)
431 self.gdb.p("$pc=_start")
432
433 # Run to main
434 self.gdb.b("main")
435 self.gdb.c()
436 for t in self.gdb.threads():
437 assertIn("main", t.frame)
438 self.gdb.command("delete breakpoints")
439
440 # Run through the entire loop.
441 self.gdb.b("main_end")
442 self.gdb.c()
443
444 hart_ids = []
445 for t in self.gdb.threads():
446 assertIn("main_end", t.frame)
447 # Check register values.
448 self.gdb.thread(t)
449 hart_id = self.gdb.p("$x1")
450 assertNotIn(hart_id, hart_ids)
451 hart_ids.append(hart_id)
452 for n in range(2, 32):
453 value = self.gdb.p("$x%d" % n)
454 assertEqual(value, hart_ids[-1] + n - 1)
455
456 # Confirmed that we read different register values for different harts.
457 # Write a new value to x1, and run through the add sequence again.
458
459 for t in threads:
460 self.gdb.thread(t)
461 self.gdb.p("$x1=0x%x" % (int(t.id) * 0x800))
462 self.gdb.p("$pc=main_post_csrr")
463 self.gdb.c()
464 for t in self.gdb.threads():
465 assertIn("main_end", t.frame)
466 # Check register values.
467 self.gdb.thread(t)
468 for n in range(1, 32):
469 value = self.gdb.p("$x%d" % n)
470 assertEqual(value, int(t.id) * 0x800 + n - 1)
471
472 class StepTest(GdbTest):
473 compile_args = ("programs/step.S", )
474
475 def setup(self):
476 self.gdb.load()
477 self.gdb.b("main")
478 self.gdb.c()
479
480 def test(self):
481 main_address = self.gdb.p("$pc")
482 if self.target.extensionSupported("c"):
483 sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
484 else:
485 sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
486 for expected in sequence:
487 self.gdb.stepi()
488 pc = self.gdb.p("$pc")
489 assertEqual("%x" % (pc - main_address), "%x" % expected)
490
491 class TriggerTest(GdbTest):
492 compile_args = ("programs/trigger.S", )
493 def setup(self):
494 self.gdb.load()
495 self.gdb.b("_exit")
496 self.gdb.b("main")
497 self.gdb.c()
498
499 def exit(self):
500 output = self.gdb.c()
501 assertIn("Breakpoint", output)
502 assertIn("_exit", output)
503
504 class TriggerExecuteInstant(TriggerTest):
505 """Test an execute breakpoint on the first instruction executed out of
506 debug mode."""
507 def test(self):
508 main_address = self.gdb.p("$pc")
509 self.gdb.command("hbreak *0x%x" % (main_address + 4))
510 self.gdb.c()
511 assertEqual(self.gdb.p("$pc"), main_address+4)
512
513 # FIXME: Triggers aren't quite working yet
514 #class TriggerLoadAddress(TriggerTest):
515 # def test(self):
516 # self.gdb.command("rwatch *((&data)+1)")
517 # output = self.gdb.c()
518 # assertIn("read_loop", output)
519 # assertEqual(self.gdb.p("$a0"),
520 # self.gdb.p("(&data)+1"))
521 # self.exit()
522
523 class TriggerLoadAddressInstant(TriggerTest):
524 """Test a load address breakpoint on the first instruction executed out of
525 debug mode."""
526 def test(self):
527 self.gdb.command("b just_before_read_loop")
528 self.gdb.c()
529 read_loop = self.gdb.p("&read_loop")
530 self.gdb.command("rwatch data")
531 self.gdb.c()
532 # Accept hitting the breakpoint before or after the load instruction.
533 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
534 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
535
536 # FIXME: Triggers aren't quite working yet
537 #class TriggerStoreAddress(TriggerTest):
538 # def test(self):
539 # self.gdb.command("watch *((&data)+3)")
540 # output = self.gdb.c()
541 # assertIn("write_loop", output)
542 # assertEqual(self.gdb.p("$a0"),
543 # self.gdb.p("(&data)+3"))
544 # self.exit()
545
546 class TriggerStoreAddressInstant(TriggerTest):
547 def test(self):
548 """Test a store address breakpoint on the first instruction executed out
549 of debug mode."""
550 self.gdb.command("b just_before_write_loop")
551 self.gdb.c()
552 write_loop = self.gdb.p("&write_loop")
553 self.gdb.command("watch data")
554 self.gdb.c()
555 # Accept hitting the breakpoint before or after the store instruction.
556 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
557 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
558
559 class TriggerDmode(TriggerTest):
560 def early_applicable(self):
561 return self.target.honors_tdata1_hmode
562
563 def check_triggers(self, tdata1_lsbs, tdata2):
564 dmode = 1 << (self.target.xlen-5)
565
566 triggers = []
567
568 if self.target.xlen == 32:
569 xlen_type = 'int'
570 elif self.target.xlen == 64:
571 xlen_type = 'long long'
572 else:
573 raise NotImplementedError
574
575 dmode_count = 0
576 i = 0
577 for i in range(16):
578 tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i))
579 if tdata1 == 0:
580 break
581 tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1))
582
583 if tdata1 & dmode:
584 dmode_count += 1
585 else:
586 assertEqual(tdata1 & 0xffff, tdata1_lsbs)
587 assertEqual(tdata2, tdata2)
588
589 assertGreater(i, 1)
590 assertEqual(dmode_count, 1)
591
592 return triggers
593
594 def test(self):
595 self.gdb.command("hbreak write_load_trigger")
596 self.gdb.b("clear_triggers")
597 self.gdb.p("$pc=write_store_trigger")
598 output = self.gdb.c()
599 assertIn("write_load_trigger", output)
600 self.check_triggers((1<<6) | (1<<1), 0xdeadbee0)
601 output = self.gdb.c()
602 assertIn("clear_triggers", output)
603 self.check_triggers((1<<6) | (1<<0), 0xfeedac00)
604
605 class RegsTest(GdbTest):
606 compile_args = ("programs/regs.S", )
607 def setup(self):
608 self.gdb.load()
609 self.gdb.b("main")
610 self.gdb.b("handle_trap")
611 self.gdb.c()
612
613 class WriteGprs(RegsTest):
614 def test(self):
615 regs = [("x%d" % n) for n in range(2, 32)]
616
617 self.gdb.p("$pc=write_regs")
618 for i, r in enumerate(regs):
619 self.gdb.p("$%s=%d" % (r, (0xdeadbeef<<i)+17))
620 self.gdb.p("$x1=data")
621 self.gdb.command("b all_done")
622 output = self.gdb.c()
623 assertIn("Breakpoint ", output)
624
625 # Just to get this data in the log.
626 self.gdb.command("x/30gx data")
627 self.gdb.command("info registers")
628 for n in range(len(regs)):
629 assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
630 ((0xdeadbeef<<n)+17) & ((1<<self.target.xlen)-1))
631
632 class WriteCsrs(RegsTest):
633 def test(self):
634 # As much a test of gdb as of the simulator.
635 self.gdb.p("$mscratch=0")
636 self.gdb.stepi()
637 assertEqual(self.gdb.p("$mscratch"), 0)
638 self.gdb.p("$mscratch=123")
639 self.gdb.stepi()
640 assertEqual(self.gdb.p("$mscratch"), 123)
641
642 self.gdb.p("$pc=write_regs")
643 self.gdb.p("$x1=data")
644 self.gdb.command("b all_done")
645 self.gdb.command("c")
646
647 assertEqual(123, self.gdb.p("$mscratch"))
648 assertEqual(123, self.gdb.p("$x1"))
649 assertEqual(123, self.gdb.p("$csr832"))
650
651 class DownloadTest(GdbTest):
652 def setup(self):
653 # pylint: disable=attribute-defined-outside-init
654 length = min(2**10, self.target.ram_size - 2048)
655 self.download_c = tempfile.NamedTemporaryFile(prefix="download_",
656 suffix=".c", delete=False)
657 self.download_c.write("#include <stdint.h>\n")
658 self.download_c.write(
659 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
660 self.download_c.write("uint32_t length = %d;\n" % length)
661 self.download_c.write("uint8_t d[%d] = {\n" % length)
662 self.crc = 0
663 assert length % 16 == 0
664 for i in range(length / 16):
665 self.download_c.write(" /* 0x%04x */ " % (i * 16))
666 for _ in range(16):
667 value = random.randrange(1<<8)
668 self.download_c.write("0x%02x, " % value)
669 self.crc = binascii.crc32("%c" % value, self.crc)
670 self.download_c.write("\n")
671 self.download_c.write("};\n")
672 self.download_c.write("uint8_t *data = &d[0];\n")
673 self.download_c.write(
674 "uint32_t main() { return crc32a(data, length); }\n")
675 self.download_c.flush()
676
677 if self.crc < 0:
678 self.crc += 2**32
679
680 self.binary = self.target.compile(self.download_c.name,
681 "programs/checksum.c")
682 self.gdb.command("file %s" % self.binary)
683
684 def test(self):
685 self.gdb.load()
686 self.gdb.command("b _exit")
687 self.gdb.c(timeout=60)
688 assertEqual(self.gdb.p("status"), self.crc)
689 os.unlink(self.download_c.name)
690
691 # FIXME: PRIV isn't implemented in the current OpenOCD
692 #class MprvTest(GdbTest):
693 # compile_args = ("programs/mprv.S", )
694 # def setup(self):
695 # self.gdb.load()
696 #
697 # def test(self):
698 # """Test that the debugger can access memory when MPRV is set."""
699 # self.gdb.c(wait=False)
700 # time.sleep(0.5)
701 # self.gdb.interrupt()
702 # output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
703 # assertIn("0xbead", output)
704 #
705 #class PrivTest(GdbTest):
706 # compile_args = ("programs/priv.S", )
707 # def setup(self):
708 # # pylint: disable=attribute-defined-outside-init
709 # self.gdb.load()
710 #
711 # misa = self.target.misa
712 # self.supported = set()
713 # if misa & (1<<20):
714 # self.supported.add(0)
715 # if misa & (1<<18):
716 # self.supported.add(1)
717 # if misa & (1<<7):
718 # self.supported.add(2)
719 # self.supported.add(3)
720 #
721 #class PrivRw(PrivTest):
722 # def test(self):
723 # """Test reading/writing priv."""
724 # for privilege in range(4):
725 # self.gdb.p("$priv=%d" % privilege)
726 # self.gdb.stepi()
727 # actual = self.gdb.p("$priv")
728 # assertIn(actual, self.supported)
729 # if privilege in self.supported:
730 # assertEqual(actual, privilege)
731 #
732 #class PrivChange(PrivTest):
733 # def test(self):
734 # """Test that the core's privilege level actually changes."""
735 #
736 # if 0 not in self.supported:
737 # return 'not_applicable'
738 #
739 # self.gdb.b("main")
740 # self.gdb.c()
741 #
742 # # Machine mode
743 # self.gdb.p("$priv=3")
744 # main_address = self.gdb.p("$pc")
745 # self.gdb.stepi()
746 # assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
747 #
748 # # User mode
749 # self.gdb.p("$priv=0")
750 # self.gdb.stepi()
751 # # Should have taken an exception, so be nowhere near main.
752 # pc = self.gdb.p("$pc")
753 # assertTrue(pc < main_address or pc > main_address + 0x100)
754
755 parsed = None
756 def main():
757 parser = argparse.ArgumentParser(
758 description="Test that gdb can talk to a RISC-V target.",
759 epilog="""
760 Example command line from the real world:
761 Run all RegsTest cases against a physical FPGA, with custom openocd command:
762 ./gdbserver.py --freedom-e300 --server_cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
763 """)
764 targets.add_target_options(parser)
765
766 testlib.add_test_run_options(parser)
767
768 # TODO: remove global
769 global parsed # pylint: disable=global-statement
770 parsed = parser.parse_args()
771 target = targets.target(parsed)
772
773 if parsed.xlen:
774 target.xlen = parsed.xlen
775
776 module = sys.modules[__name__]
777
778 return testlib.run_all_tests(module, target, parsed)
779
780 # TROUBLESHOOTING TIPS
781 # If a particular test fails, run just that one test, eg.:
782 # ./gdbserver.py MprvTest.test_mprv
783 # Then inspect gdb.log and spike.log to see what happened in more detail.
784
785 if __name__ == '__main__':
786 sys.exit(main())