Fix the end of MulticoreTest.
[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 if not self.target.honors_tdata1_hmode:
333 # Run to main before setting the breakpoint, because startup code
334 # will otherwise clear the trigger that we set.
335 self.gdb.b("main")
336 self.gdb.c()
337
338 self.gdb.hbreak("rot13")
339 # The breakpoint should be hit exactly 2 times.
340 for _ in range(2):
341 output = self.gdb.c()
342 self.gdb.p("$pc")
343 assertRegexpMatches(output, r"[bB]reakpoint")
344 assertIn("rot13 ", output)
345 self.exit()
346
347 class Hwbp2(DebugTest):
348 def test(self):
349 if self.target.instruction_hardware_breakpoint_count < 2:
350 return 'not_applicable'
351
352 self.gdb.hbreak("main")
353 self.gdb.hbreak("rot13")
354 # We should hit 3 breakpoints.
355 for expected in ("main", "rot13", "rot13"):
356 output = self.gdb.c()
357 self.gdb.p("$pc")
358 assertRegexpMatches(output, r"[bB]reakpoint")
359 assertIn("%s " % expected, output)
360 self.exit()
361
362 class TooManyHwbp(DebugTest):
363 def run(self):
364 for i in range(30):
365 self.gdb.hbreak("*rot13 + %d" % (i * 4))
366
367 output = self.gdb.c()
368 assertIn("Cannot insert hardware breakpoint", output)
369 # Clean up, otherwise the hardware breakpoints stay set and future
370 # tests may fail.
371 self.gdb.command("D")
372
373 class Registers(DebugTest):
374 def test(self):
375 # Get to a point in the code where some registers have actually been
376 # used.
377 self.gdb.b("rot13")
378 self.gdb.c()
379 self.gdb.c()
380 # Try both forms to test gdb.
381 for cmd in ("info all-registers", "info registers all"):
382 output = self.gdb.command(cmd)
383 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
384 assertIn(reg, output)
385
386 #TODO
387 # mcpuid is one of the few registers that should have the high bit set
388 # (for rv64).
389 # Leave this commented out until gdb and spike agree on the encoding of
390 # mcpuid (which is going to be renamed to misa in any case).
391 #assertRegexpMatches(output, ".*mcpuid *0x80")
392
393 #TODO:
394 # The instret register should always be changing.
395 #last_instret = None
396 #for _ in range(5):
397 # instret = self.gdb.p("$instret")
398 # assertNotEqual(instret, last_instret)
399 # last_instret = instret
400 # self.gdb.stepi()
401
402 self.exit()
403
404 class UserInterrupt(DebugTest):
405 def test(self):
406 """Sending gdb ^C while the program is running should cause it to
407 halt."""
408 self.gdb.b("main:start")
409 self.gdb.c()
410 self.gdb.p("i=123")
411 self.gdb.c(wait=False)
412 time.sleep(0.5)
413 output = self.gdb.interrupt()
414 assert "main" in output
415 assertGreater(self.gdb.p("j"), 10)
416 self.gdb.p("i=0")
417 self.exit()
418
419 class MulticoreTest(GdbTest):
420 compile_args = ("programs/infinite_loop.S", )
421
422 def setup(self):
423 self.gdb.load()
424
425 def test(self):
426 threads = self.gdb.threads()
427 if len(threads) < 2:
428 return 'not_applicable'
429
430 for t in threads:
431 self.gdb.thread(t)
432 self.gdb.p("$pc=_start")
433
434 # Run to main
435 self.gdb.b("main")
436 self.gdb.c()
437 for t in self.gdb.threads():
438 assertIn("main", t.frame)
439 self.gdb.command("delete breakpoints")
440
441 # Run through the entire loop.
442 self.gdb.b("main_end")
443 self.gdb.c()
444
445 hart_ids = []
446 for t in self.gdb.threads():
447 assertIn("main_end", t.frame)
448 # Check register values.
449 self.gdb.thread(t)
450 hart_id = self.gdb.p("$x1")
451 assertNotIn(hart_id, hart_ids)
452 hart_ids.append(hart_id)
453 for n in range(2, 32):
454 value = self.gdb.p("$x%d" % n)
455 assertEqual(value, hart_ids[-1] + n - 1)
456
457 # Confirmed that we read different register values for different harts.
458 # Write a new value to x1, and run through the add sequence again.
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 self.gdb.c()
465 for t in self.gdb.threads():
466 assertIn("main_end", t.frame)
467 # Check register values.
468 self.gdb.thread(t)
469 for n in range(1, 32):
470 value = self.gdb.p("$x%d" % n)
471 assertEqual(value, int(t.id) * 0x800 + n - 1)
472
473 class StepTest(GdbTest):
474 compile_args = ("programs/step.S", )
475
476 def setup(self):
477 self.gdb.load()
478 self.gdb.b("main")
479 self.gdb.c()
480
481 def test(self):
482 main_address = self.gdb.p("$pc")
483 if self.target.extensionSupported("c"):
484 sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
485 else:
486 sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
487 for expected in sequence:
488 self.gdb.stepi()
489 pc = self.gdb.p("$pc")
490 assertEqual("%x" % (pc - main_address), "%x" % expected)
491
492 class TriggerTest(GdbTest):
493 compile_args = ("programs/trigger.S", )
494 def setup(self):
495 self.gdb.load()
496 self.gdb.b("_exit")
497 self.gdb.b("main")
498 self.gdb.c()
499
500 def exit(self):
501 output = self.gdb.c()
502 assertIn("Breakpoint", output)
503 assertIn("_exit", output)
504
505 class TriggerExecuteInstant(TriggerTest):
506 """Test an execute breakpoint on the first instruction executed out of
507 debug mode."""
508 def test(self):
509 main_address = self.gdb.p("$pc")
510 self.gdb.command("hbreak *0x%x" % (main_address + 4))
511 self.gdb.c()
512 assertEqual(self.gdb.p("$pc"), main_address+4)
513
514 # FIXME: Triggers aren't quite working yet
515 #class TriggerLoadAddress(TriggerTest):
516 # def test(self):
517 # self.gdb.command("rwatch *((&data)+1)")
518 # output = self.gdb.c()
519 # assertIn("read_loop", output)
520 # assertEqual(self.gdb.p("$a0"),
521 # self.gdb.p("(&data)+1"))
522 # self.exit()
523
524 class TriggerLoadAddressInstant(TriggerTest):
525 """Test a load address breakpoint on the first instruction executed out of
526 debug mode."""
527 def test(self):
528 self.gdb.command("b just_before_read_loop")
529 self.gdb.c()
530 read_loop = self.gdb.p("&read_loop")
531 self.gdb.command("rwatch data")
532 self.gdb.c()
533 # Accept hitting the breakpoint before or after the load instruction.
534 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
535 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
536
537 # FIXME: Triggers aren't quite working yet
538 #class TriggerStoreAddress(TriggerTest):
539 # def test(self):
540 # self.gdb.command("watch *((&data)+3)")
541 # output = self.gdb.c()
542 # assertIn("write_loop", output)
543 # assertEqual(self.gdb.p("$a0"),
544 # self.gdb.p("(&data)+3"))
545 # self.exit()
546
547 class TriggerStoreAddressInstant(TriggerTest):
548 def test(self):
549 """Test a store address breakpoint on the first instruction executed out
550 of debug mode."""
551 self.gdb.command("b just_before_write_loop")
552 self.gdb.c()
553 write_loop = self.gdb.p("&write_loop")
554 self.gdb.command("watch data")
555 self.gdb.c()
556 # Accept hitting the breakpoint before or after the store instruction.
557 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
558 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
559
560 class TriggerDmode(TriggerTest):
561 def early_applicable(self):
562 return self.target.honors_tdata1_hmode
563
564 def check_triggers(self, tdata1_lsbs, tdata2):
565 dmode = 1 << (self.target.xlen-5)
566
567 triggers = []
568
569 if self.target.xlen == 32:
570 xlen_type = 'int'
571 elif self.target.xlen == 64:
572 xlen_type = 'long long'
573 else:
574 raise NotImplementedError
575
576 dmode_count = 0
577 i = 0
578 for i in range(16):
579 tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i))
580 if tdata1 == 0:
581 break
582 tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1))
583
584 if tdata1 & dmode:
585 dmode_count += 1
586 else:
587 assertEqual(tdata1 & 0xffff, tdata1_lsbs)
588 assertEqual(tdata2, tdata2)
589
590 assertGreater(i, 1)
591 assertEqual(dmode_count, 1)
592
593 return triggers
594
595 def test(self):
596 self.gdb.command("hbreak write_load_trigger")
597 self.gdb.b("clear_triggers")
598 self.gdb.p("$pc=write_store_trigger")
599 output = self.gdb.c()
600 assertIn("write_load_trigger", output)
601 self.check_triggers((1<<6) | (1<<1), 0xdeadbee0)
602 output = self.gdb.c()
603 assertIn("clear_triggers", output)
604 self.check_triggers((1<<6) | (1<<0), 0xfeedac00)
605
606 class RegsTest(GdbTest):
607 compile_args = ("programs/regs.S", )
608 def setup(self):
609 self.gdb.load()
610 self.gdb.b("main")
611 self.gdb.b("handle_trap")
612 self.gdb.c()
613
614 class WriteGprs(RegsTest):
615 def test(self):
616 regs = [("x%d" % n) for n in range(2, 32)]
617
618 self.gdb.p("$pc=write_regs")
619 for i, r in enumerate(regs):
620 self.gdb.p("$%s=%d" % (r, (0xdeadbeef<<i)+17))
621 self.gdb.p("$x1=data")
622 self.gdb.command("b all_done")
623 output = self.gdb.c()
624 assertIn("Breakpoint ", output)
625
626 # Just to get this data in the log.
627 self.gdb.command("x/30gx data")
628 self.gdb.command("info registers")
629 for n in range(len(regs)):
630 assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
631 ((0xdeadbeef<<n)+17) & ((1<<self.target.xlen)-1))
632
633 class WriteCsrs(RegsTest):
634 def test(self):
635 # As much a test of gdb as of the simulator.
636 self.gdb.p("$mscratch=0")
637 self.gdb.stepi()
638 assertEqual(self.gdb.p("$mscratch"), 0)
639 self.gdb.p("$mscratch=123")
640 self.gdb.stepi()
641 assertEqual(self.gdb.p("$mscratch"), 123)
642
643 self.gdb.p("$pc=write_regs")
644 self.gdb.p("$x1=data")
645 self.gdb.command("b all_done")
646 self.gdb.command("c")
647
648 assertEqual(123, self.gdb.p("$mscratch"))
649 assertEqual(123, self.gdb.p("$x1"))
650 assertEqual(123, self.gdb.p("$csr832"))
651
652 class DownloadTest(GdbTest):
653 def setup(self):
654 # pylint: disable=attribute-defined-outside-init
655 length = min(2**10, self.target.ram_size - 2048)
656 self.download_c = tempfile.NamedTemporaryFile(prefix="download_",
657 suffix=".c", delete=False)
658 self.download_c.write("#include <stdint.h>\n")
659 self.download_c.write(
660 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
661 self.download_c.write("uint32_t length = %d;\n" % length)
662 self.download_c.write("uint8_t d[%d] = {\n" % length)
663 self.crc = 0
664 assert length % 16 == 0
665 for i in range(length / 16):
666 self.download_c.write(" /* 0x%04x */ " % (i * 16))
667 for _ in range(16):
668 value = random.randrange(1<<8)
669 self.download_c.write("0x%02x, " % value)
670 self.crc = binascii.crc32("%c" % value, self.crc)
671 self.download_c.write("\n")
672 self.download_c.write("};\n")
673 self.download_c.write("uint8_t *data = &d[0];\n")
674 self.download_c.write(
675 "uint32_t main() { return crc32a(data, length); }\n")
676 self.download_c.flush()
677
678 if self.crc < 0:
679 self.crc += 2**32
680
681 self.binary = self.target.compile(self.download_c.name,
682 "programs/checksum.c")
683 self.gdb.command("file %s" % self.binary)
684
685 def test(self):
686 self.gdb.load()
687 self.gdb.command("b _exit")
688 self.gdb.c(timeout=60)
689 assertEqual(self.gdb.p("status"), self.crc)
690 os.unlink(self.download_c.name)
691
692 # FIXME: PRIV isn't implemented in the current OpenOCD
693 #class MprvTest(GdbTest):
694 # compile_args = ("programs/mprv.S", )
695 # def setup(self):
696 # self.gdb.load()
697 #
698 # def test(self):
699 # """Test that the debugger can access memory when MPRV is set."""
700 # self.gdb.c(wait=False)
701 # time.sleep(0.5)
702 # self.gdb.interrupt()
703 # output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
704 # assertIn("0xbead", output)
705 #
706 #class PrivTest(GdbTest):
707 # compile_args = ("programs/priv.S", )
708 # def setup(self):
709 # # pylint: disable=attribute-defined-outside-init
710 # self.gdb.load()
711 #
712 # misa = self.target.misa
713 # self.supported = set()
714 # if misa & (1<<20):
715 # self.supported.add(0)
716 # if misa & (1<<18):
717 # self.supported.add(1)
718 # if misa & (1<<7):
719 # self.supported.add(2)
720 # self.supported.add(3)
721 #
722 #class PrivRw(PrivTest):
723 # def test(self):
724 # """Test reading/writing priv."""
725 # for privilege in range(4):
726 # self.gdb.p("$priv=%d" % privilege)
727 # self.gdb.stepi()
728 # actual = self.gdb.p("$priv")
729 # assertIn(actual, self.supported)
730 # if privilege in self.supported:
731 # assertEqual(actual, privilege)
732 #
733 #class PrivChange(PrivTest):
734 # def test(self):
735 # """Test that the core's privilege level actually changes."""
736 #
737 # if 0 not in self.supported:
738 # return 'not_applicable'
739 #
740 # self.gdb.b("main")
741 # self.gdb.c()
742 #
743 # # Machine mode
744 # self.gdb.p("$priv=3")
745 # main_address = self.gdb.p("$pc")
746 # self.gdb.stepi()
747 # assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
748 #
749 # # User mode
750 # self.gdb.p("$priv=0")
751 # self.gdb.stepi()
752 # # Should have taken an exception, so be nowhere near main.
753 # pc = self.gdb.p("$pc")
754 # assertTrue(pc < main_address or pc > main_address + 0x100)
755
756 parsed = None
757 def main():
758 parser = argparse.ArgumentParser(
759 description="Test that gdb can talk to a RISC-V target.",
760 epilog="""
761 Example command line from the real world:
762 Run all RegsTest cases against a physical FPGA, with custom openocd command:
763 ./gdbserver.py --freedom-e300 --server_cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
764 """)
765 targets.add_target_options(parser)
766
767 testlib.add_test_run_options(parser)
768
769 # TODO: remove global
770 global parsed # pylint: disable=global-statement
771 parsed = parser.parse_args()
772 target = targets.target(parsed)
773
774 if parsed.xlen:
775 target.xlen = parsed.xlen
776
777 module = sys.modules[__name__]
778
779 return testlib.run_all_tests(module, target, parsed)
780
781 # TROUBLESHOOTING TIPS
782 # If a particular test fails, run just that one test, eg.:
783 # ./gdbserver.py MprvTest.test_mprv
784 # Then inspect gdb.log and spike.log to see what happened in more detail.
785
786 if __name__ == '__main__':
787 sys.exit(main())