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