Check all PCs after reset.
[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 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram, a))
128 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram + size,
129 b))
130 assertEqual(self.gdb.p("*((%s*)0x%x)" % (data_type, self.target.ram)),
131 a)
132 assertEqual(self.gdb.p("*((%s*)0x%x)" % (
133 data_type, self.target.ram + size)), b)
134
135 class MemTest8(SimpleMemoryTest):
136 def test(self):
137 self.access_test(1, 'char')
138
139 class MemTest16(SimpleMemoryTest):
140 def test(self):
141 self.access_test(2, 'short')
142
143 class MemTest32(SimpleMemoryTest):
144 def test(self):
145 self.access_test(4, 'int')
146
147 class MemTest64(SimpleMemoryTest):
148 def test(self):
149 self.access_test(8, 'long long')
150
151 # FIXME: I'm not passing back invalid addresses correctly in read/write memory.
152 #class MemTestReadInvalid(SimpleMemoryTest):
153 # def test(self):
154 # # This test relies on 'gdb_report_data_abort enable' being executed in
155 # # the openocd.cfg file.
156 # try:
157 # self.gdb.p("*((int*)0xdeadbeef)")
158 # assert False, "Read should have failed."
159 # except testlib.CannotAccess as e:
160 # assertEqual(e.address, 0xdeadbeef)
161 # self.gdb.p("*((int*)0x%x)" % self.target.ram)
162 #
163 #class MemTestWriteInvalid(SimpleMemoryTest):
164 # def test(self):
165 # # This test relies on 'gdb_report_data_abort enable' being executed in
166 # # the openocd.cfg file.
167 # try:
168 # self.gdb.p("*((int*)0xdeadbeef)=8675309")
169 # assert False, "Write should have failed."
170 # except testlib.CannotAccess as e:
171 # assertEqual(e.address, 0xdeadbeef)
172 # self.gdb.p("*((int*)0x%x)=6874742" % self.target.ram)
173
174 class MemTestBlock(GdbTest):
175 def test(self):
176 length = 1024
177 line_length = 16
178 a = tempfile.NamedTemporaryFile(suffix=".ihex")
179 data = ""
180 for i in range(length / line_length):
181 line_data = "".join(["%c" % random.randrange(256)
182 for _ in range(line_length)])
183 data += line_data
184 a.write(ihex_line(i * line_length, 0, line_data))
185 a.flush()
186
187 self.gdb.command("restore %s 0x%x" % (a.name, self.target.ram))
188 for offset in range(0, length, 19*4) + [length-4]:
189 value = self.gdb.p("*((int*)0x%x)" % (self.target.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.target.ram, self.target.ram + length))
199 for line in b:
200 record_type, address, line_data = ihex_parse(line)
201 if record_type == 0:
202 assertEqual(readable_binary_string(line_data),
203 readable_binary_string(
204 data[address:address+len(line_data)]))
205
206 class InstantHaltTest(GdbTest):
207 def test(self):
208 """Assert that reset is really resetting what it should."""
209 self.gdb.command("monitor reset halt")
210 self.gdb.command("flushregs")
211 threads = self.gdb.threads()
212 pcs = []
213 for t in threads:
214 self.gdb.thread(t)
215 pcs.append(self.gdb.p("$pc"))
216 for pc in pcs:
217 assertEqual(self.target.reset_vector, pc)
218 # mcycle and minstret have no defined reset value.
219 mstatus = self.gdb.p("$mstatus")
220 assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
221 MSTATUS_VM), 0)
222
223 class InstantChangePc(GdbTest):
224 def test(self):
225 """Change the PC right as we come out of reset."""
226 # 0x13 is nop
227 self.gdb.command("monitor reset halt")
228 self.gdb.command("flushregs")
229 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
230 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
231 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
232 self.gdb.p("$pc=0x%x" % self.target.ram)
233 self.gdb.stepi()
234 assertEqual((self.target.ram + 4), self.gdb.p("$pc"))
235 self.gdb.stepi()
236 assertEqual((self.target.ram + 8), self.gdb.p("$pc"))
237
238 class DebugTest(GdbTest):
239 # Include malloc so that gdb can make function calls. I suspect this malloc
240 # will silently blow through the memory set aside for it, so be careful.
241 compile_args = ("programs/debug.c", "programs/checksum.c",
242 "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE")
243
244 def setup(self):
245 self.gdb.load()
246 self.gdb.b("_exit")
247
248 def exit(self, expected_result=0xc86455d4):
249 output = self.gdb.c()
250 assertIn("Breakpoint", output)
251 assertIn("_exit", output)
252 assertEqual(self.gdb.p("status"), expected_result)
253
254 class DebugCompareSections(DebugTest):
255 def test(self):
256 output = self.gdb.command("compare-sections")
257 matched = 0
258 for line in output.splitlines():
259 if line.startswith("Section"):
260 assert line.endswith("matched.")
261 matched += 1
262 assertGreater(matched, 1)
263
264 class DebugFunctionCall(DebugTest):
265 def test(self):
266 self.gdb.b("main:start")
267 self.gdb.c()
268 assertEqual(self.gdb.p('fib(6)'), 8)
269 assertEqual(self.gdb.p('fib(7)'), 13)
270 self.exit()
271
272 class DebugChangeString(DebugTest):
273 def test(self):
274 text = "This little piggy went to the market."
275 self.gdb.b("main:start")
276 self.gdb.c()
277 self.gdb.p('fox = "%s"' % text)
278 self.exit(0x43b497b8)
279
280 class DebugTurbostep(DebugTest):
281 def test(self):
282 """Single step a bunch of times."""
283 self.gdb.b("main:start")
284 self.gdb.c()
285 self.gdb.command("p i=0")
286 last_pc = None
287 advances = 0
288 jumps = 0
289 for _ in range(10):
290 self.gdb.stepi()
291 pc = self.gdb.p("$pc")
292 assertNotEqual(last_pc, pc)
293 if last_pc and pc > last_pc and pc - last_pc <= 4:
294 advances += 1
295 else:
296 jumps += 1
297 last_pc = pc
298 # Some basic sanity that we're not running between breakpoints or
299 # something.
300 assertGreater(jumps, 1)
301 assertGreater(advances, 5)
302
303 class DebugExit(DebugTest):
304 def test(self):
305 self.exit()
306
307 class DebugSymbols(DebugTest):
308 def test(self):
309 self.gdb.b("main")
310 self.gdb.b("rot13")
311 output = self.gdb.c()
312 assertIn(", main ", output)
313 output = self.gdb.c()
314 assertIn(", rot13 ", output)
315
316 class DebugBreakpoint(DebugTest):
317 def test(self):
318 self.gdb.b("rot13")
319 # The breakpoint should be hit exactly 2 times.
320 for _ in range(2):
321 output = self.gdb.c()
322 self.gdb.p("$pc")
323 assertIn("Breakpoint ", output)
324 assertIn("rot13 ", output)
325 self.exit()
326
327 class Hwbp1(DebugTest):
328 def test(self):
329 if self.target.instruction_hardware_breakpoint_count < 1:
330 return 'not_applicable'
331
332 self.gdb.hbreak("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 assertRegexpMatches(output, r"[bB]reakpoint")
338 assertIn("rot13 ", output)
339 self.exit()
340
341 class Hwbp2(DebugTest):
342 def test(self):
343 if self.target.instruction_hardware_breakpoint_count < 2:
344 return 'not_applicable'
345
346 self.gdb.hbreak("main")
347 self.gdb.hbreak("rot13")
348 # We should hit 3 breakpoints.
349 for expected in ("main", "rot13", "rot13"):
350 output = self.gdb.c()
351 self.gdb.p("$pc")
352 assertRegexpMatches(output, r"[bB]reakpoint")
353 assertIn("%s " % expected, output)
354 self.exit()
355
356 class TooManyHwbp(DebugTest):
357 def run(self):
358 for i in range(30):
359 self.gdb.hbreak("*rot13 + %d" % (i * 4))
360
361 output = self.gdb.c()
362 assertIn("Cannot insert hardware breakpoint", output)
363 # Clean up, otherwise the hardware breakpoints stay set and future
364 # tests may fail.
365 self.gdb.command("D")
366
367 class Registers(DebugTest):
368 def test(self):
369 # Get to a point in the code where some registers have actually been
370 # used.
371 self.gdb.b("rot13")
372 self.gdb.c()
373 self.gdb.c()
374 # Try both forms to test gdb.
375 for cmd in ("info all-registers", "info registers all"):
376 output = self.gdb.command(cmd)
377 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
378 assertIn(reg, output)
379
380 #TODO
381 # mcpuid is one of the few registers that should have the high bit set
382 # (for rv64).
383 # Leave this commented out until gdb and spike agree on the encoding of
384 # mcpuid (which is going to be renamed to misa in any case).
385 #assertRegexpMatches(output, ".*mcpuid *0x80")
386
387 #TODO:
388 # The instret register should always be changing.
389 #last_instret = None
390 #for _ in range(5):
391 # instret = self.gdb.p("$instret")
392 # assertNotEqual(instret, last_instret)
393 # last_instret = instret
394 # self.gdb.stepi()
395
396 self.exit()
397
398 class UserInterrupt(DebugTest):
399 def test(self):
400 """Sending gdb ^C while the program is running should cause it to
401 halt."""
402 self.gdb.b("main:start")
403 self.gdb.c()
404 self.gdb.p("i=123")
405 self.gdb.c(wait=False)
406 time.sleep(0.5)
407 output = self.gdb.interrupt()
408 assert "main" in output
409 assertGreater(self.gdb.p("j"), 10)
410 self.gdb.p("i=0")
411 self.exit()
412
413 class MulticoreTest(GdbTest):
414 compile_args = ("programs/infinite_loop.S", )
415
416 def setup(self):
417 self.gdb.load()
418 self.gdb.b("main")
419 self.gdb.b("main_end")
420 self.gdb.command("set non-stop on")
421 self.gdb.c()
422
423 def test(self):
424 threads = self.gdb.threads()
425 if len(threads) < 2:
426 return 'not_applicable'
427 # Run through the entire loop.
428 for t in threads:
429 self.gdb.thread(t)
430 self.gdb.p("$pc=_start")
431 # Run to main
432 for t in threads:
433 self.gdb.thread(t)
434 self.gdb.c()
435 for t in self.gdb.threads():
436 assertIn("main", t.frame)
437 # Run to end
438 for t in threads:
439 self.gdb.thread(t)
440 self.gdb.c()
441 hart_ids = []
442 for t in self.gdb.threads():
443 assertIn("main_end", t.frame)
444 # Check register values.
445 self.gdb.thread(t)
446 hart_id = self.gdb.p("$x1")
447 assertNotIn(hart_id, hart_ids)
448 hart_ids.append(hart_id)
449 for n in range(2, 32):
450 value = self.gdb.p("$x%d" % n)
451 assertEqual(value, hart_ids[-1] + n - 1)
452
453 # Confirmed that we read different register values for different harts.
454 # Write a new value to x1, and run through the add sequence again.
455
456 # This part isn't working right, because gdb doesn't resume Thread 2
457 # when asked. I don't know the root cause for that, but up to this
458 # point the test is still useful.
459
460 # for t in threads:
461 # self.gdb.thread(t)
462 # self.gdb.p("$x1=0x%x" % (int(t.id) + 0x800))
463 # self.gdb.p("$pc=main_post_csrr")
464 # for t in threads:
465 # self.gdb.thread(t)
466 # self.gdb.c()
467 # for t in self.gdb.threads():
468 # assertIn("main_end", t.frame)
469 # # Check register values.
470 # self.gdb.thread(t)
471 # for n in range(1, 32):
472 # value = self.gdb.p("$x%d" % n)
473 # assertEqual(value, int(t.id) + 0x800 + n - 1)
474
475 class StepTest(GdbTest):
476 compile_args = ("programs/step.S", )
477
478 def setup(self):
479 self.gdb.load()
480 self.gdb.b("main")
481 self.gdb.c()
482
483 def test(self):
484 main_address = self.gdb.p("$pc")
485 if self.target.extensionSupported("c"):
486 sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
487 else:
488 sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
489 for expected in sequence:
490 self.gdb.stepi()
491 pc = self.gdb.p("$pc")
492 assertEqual("%x" % (pc - main_address), "%x" % expected)
493
494 class TriggerTest(GdbTest):
495 compile_args = ("programs/trigger.S", )
496 def setup(self):
497 self.gdb.load()
498 self.gdb.b("_exit")
499 self.gdb.b("main")
500 self.gdb.c()
501
502 def exit(self):
503 output = self.gdb.c()
504 assertIn("Breakpoint", output)
505 assertIn("_exit", output)
506
507 class TriggerExecuteInstant(TriggerTest):
508 """Test an execute breakpoint on the first instruction executed out of
509 debug mode."""
510 def test(self):
511 main_address = self.gdb.p("$pc")
512 self.gdb.command("hbreak *0x%x" % (main_address + 4))
513 self.gdb.c()
514 assertEqual(self.gdb.p("$pc"), main_address+4)
515
516 # FIXME: Triggers aren't quite working yet
517 #class TriggerLoadAddress(TriggerTest):
518 # def test(self):
519 # self.gdb.command("rwatch *((&data)+1)")
520 # output = self.gdb.c()
521 # assertIn("read_loop", output)
522 # assertEqual(self.gdb.p("$a0"),
523 # self.gdb.p("(&data)+1"))
524 # self.exit()
525
526 class TriggerLoadAddressInstant(TriggerTest):
527 """Test a load address breakpoint on the first instruction executed out of
528 debug mode."""
529 def test(self):
530 self.gdb.command("b just_before_read_loop")
531 self.gdb.c()
532 read_loop = self.gdb.p("&read_loop")
533 self.gdb.command("rwatch data")
534 self.gdb.c()
535 # Accept hitting the breakpoint before or after the load instruction.
536 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
537 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
538
539 # FIXME: Triggers aren't quite working yet
540 #class TriggerStoreAddress(TriggerTest):
541 # def test(self):
542 # self.gdb.command("watch *((&data)+3)")
543 # output = self.gdb.c()
544 # assertIn("write_loop", output)
545 # assertEqual(self.gdb.p("$a0"),
546 # self.gdb.p("(&data)+3"))
547 # self.exit()
548
549 class TriggerStoreAddressInstant(TriggerTest):
550 def test(self):
551 """Test a store address breakpoint on the first instruction executed out
552 of debug mode."""
553 self.gdb.command("b just_before_write_loop")
554 self.gdb.c()
555 write_loop = self.gdb.p("&write_loop")
556 self.gdb.command("watch data")
557 self.gdb.c()
558 # Accept hitting the breakpoint before or after the store instruction.
559 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
560 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
561
562 class TriggerDmode(TriggerTest):
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())