Clear triggers during entry.
[riscv-tests.git] / debug / gdbserver.py
1 #!/usr/bin/env python
2
3 import argparse
4 import binascii
5 import os
6 import random
7 import re
8 import sys
9 import tempfile
10 import time
11 import traceback
12
13 import testlib
14
15 MSTATUS_UIE = 0x00000001
16 MSTATUS_SIE = 0x00000002
17 MSTATUS_HIE = 0x00000004
18 MSTATUS_MIE = 0x00000008
19 MSTATUS_UPIE = 0x00000010
20 MSTATUS_SPIE = 0x00000020
21 MSTATUS_HPIE = 0x00000040
22 MSTATUS_MPIE = 0x00000080
23 MSTATUS_SPP = 0x00000100
24 MSTATUS_HPP = 0x00000600
25 MSTATUS_MPP = 0x00001800
26 MSTATUS_FS = 0x00006000
27 MSTATUS_XS = 0x00018000
28 MSTATUS_MPRV = 0x00020000
29 MSTATUS_PUM = 0x00040000
30 MSTATUS_MXR = 0x00080000
31 MSTATUS_VM = 0x1F000000
32 MSTATUS32_SD = 0x80000000
33 MSTATUS64_SD = 0x8000000000000000
34
35 # pylint: disable=abstract-method
36
37 def gdb(
38 target=None,
39 port=None,
40 binary=None
41 ):
42
43 g = None
44 if parsed.gdb:
45 g = testlib.Gdb(parsed.gdb)
46 else:
47 g = testlib.Gdb()
48
49 if binary:
50 g.command("file %s" % binary)
51 if target:
52 g.command("set arch riscv:rv%d" % target.xlen)
53 g.command("set remotetimeout %d" % target.timeout_sec)
54 if port:
55 g.command("target extended-remote localhost:%d" % port)
56
57 g.p("$priv=3")
58
59 return g
60
61 def ihex_line(address, record_type, data):
62 assert len(data) < 128
63 line = ":%02X%04X%02X" % (len(data), address, record_type)
64 check = len(data)
65 check += address % 256
66 check += address >> 8
67 check += record_type
68 for char in data:
69 value = ord(char)
70 check += value
71 line += "%02X" % value
72 line += "%02X\n" % ((256-check)%256)
73 return line
74
75 def ihex_parse(line):
76 assert line.startswith(":")
77 line = line[1:]
78 data_len = int(line[:2], 16)
79 address = int(line[2:6], 16)
80 record_type = int(line[6:8], 16)
81 data = ""
82 for i in range(data_len):
83 data += "%c" % int(line[8+2*i:10+2*i], 16)
84 return record_type, address, data
85
86 def readable_binary_string(s):
87 return "".join("%02x" % ord(c) for c in s)
88
89 def header(title):
90 dashes = '-' * (36 - len(title))
91 before = dashes[:len(dashes)/2]
92 after = dashes[len(dashes)/2:]
93 print "%s[ %s ]%s" % (before, title, after)
94
95 class GdbTest(object):
96 compiled = {}
97
98 def __init__(self, target):
99 self.target = target
100 self.server = None
101 self.binary = None
102 self.gdb = None
103
104 def setUp(self):
105 pass
106
107 def run(self):
108 """
109 If compile_args is set, compile a program and set self.binary.
110
111 Call setUp().
112
113 Then call test() and return the result, displaying relevant information
114 if an exception is raised.
115 """
116 self.server = self.target.server()
117
118 print "Running", type(self).__name__, "...",
119 sys.stdout.flush()
120
121 start = time.time()
122
123 compile_args = getattr(self, 'compile_args', None)
124 if compile_args:
125 if compile_args not in GdbTest.compiled:
126 try:
127 # pylint: disable=star-args
128 GdbTest.compiled[compile_args] = \
129 self.target.compile(*compile_args)
130 except Exception: # pylint: disable=broad-except
131 print "exception while compiling in %.2fs" % (
132 time.time() - start)
133 print "=" * 40
134 header("Traceback")
135 traceback.print_exc(file=sys.stdout)
136 print "/" * 40
137 return "exception"
138 self.binary = GdbTest.compiled.get(compile_args)
139
140 self.gdb = gdb(self.target, self.server.port, self.binary)
141
142 try:
143 self.setUp()
144 result = self.test() # pylint: disable=no-member
145 except Exception as e: # pylint: disable=broad-except
146 if isinstance(e, TestFailed):
147 result = "fail"
148 else:
149 result = "exception"
150 print "%s in %.2fs" % (result, time.time() - start)
151 print "=" * 40
152 if isinstance(e, TestFailed):
153 header("Message")
154 print e.message
155 header("Traceback")
156 traceback.print_exc(file=sys.stdout)
157 header("gdb.log")
158 print open("gdb.log", "r").read()
159 header(self.server.logname)
160 print open(self.server.logname, "r").read()
161 print "/" * 40
162 return result
163
164 finally:
165 del self.server
166 del self.gdb
167
168 if not result:
169 result = 'pass'
170 print "%s in %.2fs" % (result, time.time() - start)
171 return result
172
173 class TestFailed(Exception):
174 def __init__(self, message):
175 Exception.__init__(self)
176 self.message = message
177
178 def run_all_tests(target, tests):
179 results = {}
180 module = sys.modules[__name__]
181 for name in dir(module):
182 definition = getattr(module, name)
183 if type(definition) == type and hasattr(definition, 'test') and \
184 (not tests or any(test in name for test in tests)):
185 instance = definition(target)
186 result = instance.run()
187 results.setdefault(result, []).append(name)
188
189 print ":" * 40
190
191 good_results = set(('pass', 'not_applicable'))
192
193 result = 0
194 for key, value in results.iteritems():
195 print "%d tests returned %s" % (len(value), key)
196 if key not in good_results:
197 result = 1
198 for test in value:
199 print " ", test
200
201 return result
202
203 def assertEqual(a, b):
204 if a != b:
205 raise TestFailed("%r != %r" % (a, b))
206
207 def assertNotEqual(a, b):
208 if a == b:
209 raise TestFailed("%r == %r" % (a, b))
210
211 def assertIn(a, b):
212 if a not in b:
213 raise TestFailed("%r not in %r" % (a, b))
214
215 def assertNotIn(a, b):
216 if a in b:
217 raise TestFailed("%r in %r" % (a, b))
218
219 def assertGreater(a, b):
220 if not a > b:
221 raise TestFailed("%r not greater than %r" % (a, b))
222
223 def assertTrue(a):
224 if not a:
225 raise TestFailed("%r is not True" % a)
226
227 def assertRegexpMatches(text, regexp):
228 if not re.search(regexp, text):
229 raise TestFailed("can't find %r in %r" % (regexp, text))
230
231 class SimpleRegisterTest(GdbTest):
232 def check_reg(self, name):
233 a = random.randrange(1<<self.target.xlen)
234 b = random.randrange(1<<self.target.xlen)
235 self.gdb.p("$%s=0x%x" % (name, a))
236 self.gdb.stepi()
237 assertEqual(self.gdb.p("$%s" % name), a)
238 self.gdb.p("$%s=0x%x" % (name, b))
239 self.gdb.stepi()
240 assertEqual(self.gdb.p("$%s" % name), b)
241
242 def setUp(self):
243 # 0x13 is nop
244 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
245 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
246 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
247 self.gdb.p("$pc=0x%x" % self.target.ram)
248
249 class SimpleS0Test(SimpleRegisterTest):
250 def test(self):
251 self.check_reg("s0")
252
253 class SimpleS1Test(SimpleRegisterTest):
254 def test(self):
255 self.check_reg("s1")
256
257 class SimpleT0Test(SimpleRegisterTest):
258 def test(self):
259 self.check_reg("t0")
260
261 class SimpleT1Test(SimpleRegisterTest):
262 def test(self):
263 self.check_reg("t1")
264
265 class SimpleMemoryTest(GdbTest):
266 def access_test(self, size, data_type):
267 assertEqual(self.gdb.p("sizeof(%s)" % data_type), size)
268 a = 0x86753095555aaaa & ((1<<(size*8))-1)
269 b = 0xdeadbeef12345678 & ((1<<(size*8))-1)
270 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram, a))
271 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram + size,
272 b))
273 assertEqual(self.gdb.p("*((%s*)0x%x)" % (data_type, self.target.ram)),
274 a)
275 assertEqual(self.gdb.p("*((%s*)0x%x)" % (
276 data_type, self.target.ram + size)), b)
277
278 class MemTest8(SimpleMemoryTest):
279 def test(self):
280 self.access_test(1, 'char')
281
282 class MemTest16(SimpleMemoryTest):
283 def test(self):
284 self.access_test(2, 'short')
285
286 class MemTest32(SimpleMemoryTest):
287 def test(self):
288 self.access_test(4, 'int')
289
290 class MemTest64(SimpleMemoryTest):
291 def test(self):
292 self.access_test(8, 'long long')
293
294 class MemTestBlock(GdbTest):
295 def test(self):
296 length = 1024
297 line_length = 16
298 a = tempfile.NamedTemporaryFile(suffix=".ihex")
299 data = ""
300 for i in range(length / line_length):
301 line_data = "".join(["%c" % random.randrange(256)
302 for _ in range(line_length)])
303 data += line_data
304 a.write(ihex_line(i * line_length, 0, line_data))
305 a.flush()
306
307 self.gdb.command("restore %s 0x%x" % (a.name, self.target.ram))
308 for offset in range(0, length, 19*4) + [length-4]:
309 value = self.gdb.p("*((int*)0x%x)" % (self.target.ram + offset))
310 written = ord(data[offset]) | \
311 (ord(data[offset+1]) << 8) | \
312 (ord(data[offset+2]) << 16) | \
313 (ord(data[offset+3]) << 24)
314 assertEqual(value, written)
315
316 b = tempfile.NamedTemporaryFile(suffix=".ihex")
317 self.gdb.command("dump ihex memory %s 0x%x 0x%x" % (b.name,
318 self.target.ram, self.target.ram + length))
319 for line in b:
320 record_type, address, line_data = ihex_parse(line)
321 if record_type == 0:
322 assertEqual(readable_binary_string(line_data),
323 readable_binary_string(
324 data[address:address+len(line_data)]))
325
326 class InstantHaltTest(GdbTest):
327 def test(self):
328 assertEqual(self.target.reset_vector, self.gdb.p("$pc"))
329 # mcycle and minstret have no defined reset value.
330 mstatus = self.gdb.p("$mstatus")
331 assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
332 MSTATUS_VM), 0)
333
334 class InstantChangePc(GdbTest):
335 def test(self):
336 """Change the PC right as we come out of reset."""
337 # 0x13 is nop
338 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
339 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
340 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
341 self.gdb.p("$pc=0x%x" % self.target.ram)
342 self.gdb.stepi()
343 assertEqual((self.target.ram + 4), self.gdb.p("$pc"))
344 self.gdb.stepi()
345 assertEqual((self.target.ram + 8), self.gdb.p("$pc"))
346
347 class DebugTest(GdbTest):
348 # Include malloc so that gdb can make function calls. I suspect this malloc
349 # will silently blow through the memory set aside for it, so be careful.
350 compile_args = ("programs/debug.c", "programs/checksum.c",
351 "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE")
352
353 def setUp(self):
354 self.gdb.load()
355 self.gdb.b("_exit")
356
357 def exit(self, expected_result=0xc86455d4):
358 output = self.gdb.c()
359 assertIn("Breakpoint", output)
360 assertIn("_exit", output)
361 assertEqual(self.gdb.p("status"), expected_result)
362
363 class DebugFunctionCall(DebugTest):
364 def test(self):
365 self.gdb.b("main:start")
366 self.gdb.c()
367 assertEqual(self.gdb.p('fib(6)'), 8)
368 assertEqual(self.gdb.p('fib(7)'), 13)
369 self.exit()
370
371 class DebugChangeString(DebugTest):
372 def test(self):
373 text = "This little piggy went to the market."
374 self.gdb.b("main:start")
375 self.gdb.c()
376 self.gdb.p('fox = "%s"' % text)
377 self.exit(0x43b497b8)
378
379 class DebugTurbostep(DebugTest):
380 def test(self):
381 """Single step a bunch of times."""
382 self.gdb.b("main:start")
383 self.gdb.c()
384 self.gdb.command("p i=0")
385 last_pc = None
386 advances = 0
387 jumps = 0
388 for _ in range(100):
389 self.gdb.stepi()
390 pc = self.gdb.p("$pc")
391 assertNotEqual(last_pc, pc)
392 if last_pc and pc > last_pc and pc - last_pc <= 4:
393 advances += 1
394 else:
395 jumps += 1
396 last_pc = pc
397 # Some basic sanity that we're not running between breakpoints or
398 # something.
399 assertGreater(jumps, 10)
400 assertGreater(advances, 50)
401
402 class DebugExit(DebugTest):
403 def test(self):
404 self.exit()
405
406 class DebugSymbols(DebugTest):
407 def test(self):
408 self.gdb.b("main")
409 self.gdb.b("rot13")
410 output = self.gdb.c()
411 assertIn(", main ", output)
412 output = self.gdb.c()
413 assertIn(", rot13 ", output)
414
415 class DebugBreakpoint(DebugTest):
416 def test(self):
417 self.gdb.b("rot13")
418 # The breakpoint should be hit exactly 2 times.
419 for _ in range(2):
420 output = self.gdb.c()
421 self.gdb.p("$pc")
422 assertIn("Breakpoint ", output)
423 assertIn("rot13 ", output)
424 self.exit()
425
426 class Hwbp1(DebugTest):
427 def test(self):
428 if self.target.instruction_hardware_breakpoint_count < 1:
429 return 'not_applicable'
430
431 self.gdb.hbreak("rot13")
432 # The breakpoint should be hit exactly 2 times.
433 for _ in range(2):
434 output = self.gdb.c()
435 self.gdb.p("$pc")
436 assertRegexpMatches(output, r"[bB]reakpoint")
437 assertIn("rot13 ", output)
438 self.exit()
439
440 class Hwbp2(DebugTest):
441 def test(self):
442 if self.target.instruction_hardware_breakpoint_count < 2:
443 return 'not_applicable'
444
445 self.gdb.hbreak("main")
446 self.gdb.hbreak("rot13")
447 # We should hit 3 breakpoints.
448 for expected in ("main", "rot13", "rot13"):
449 output = self.gdb.c()
450 self.gdb.p("$pc")
451 assertRegexpMatches(output, r"[bB]reakpoint")
452 assertIn("%s " % expected, output)
453 self.exit()
454
455 class TooManyHwbp(DebugTest):
456 def run(self):
457 for i in range(30):
458 self.gdb.hbreak("*rot13 + %d" % (i * 4))
459
460 output = self.gdb.c()
461 assertIn("Cannot insert hardware breakpoint", output)
462 # Clean up, otherwise the hardware breakpoints stay set and future
463 # tests may fail.
464 self.gdb.command("D")
465
466 class Registers(DebugTest):
467 def test(self):
468 # Get to a point in the code where some registers have actually been
469 # used.
470 self.gdb.b("rot13")
471 self.gdb.c()
472 self.gdb.c()
473 # Try both forms to test gdb.
474 for cmd in ("info all-registers", "info registers all"):
475 output = self.gdb.command(cmd)
476 assertNotIn("Could not", output)
477 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
478 assertIn(reg, output)
479
480 #TODO
481 # mcpuid is one of the few registers that should have the high bit set
482 # (for rv64).
483 # Leave this commented out until gdb and spike agree on the encoding of
484 # mcpuid (which is going to be renamed to misa in any case).
485 #assertRegexpMatches(output, ".*mcpuid *0x80")
486
487 #TODO:
488 # The instret register should always be changing.
489 #last_instret = None
490 #for _ in range(5):
491 # instret = self.gdb.p("$instret")
492 # assertNotEqual(instret, last_instret)
493 # last_instret = instret
494 # self.gdb.stepi()
495
496 self.exit()
497
498 class UserInterrupt(DebugTest):
499 def test(self):
500 """Sending gdb ^C while the program is running should cause it to
501 halt."""
502 self.gdb.b("main:start")
503 self.gdb.c()
504 self.gdb.p("i=123")
505 self.gdb.c(wait=False)
506 time.sleep(0.1)
507 output = self.gdb.interrupt()
508 assert "main" in output
509 assertGreater(self.gdb.p("j"), 10)
510 self.gdb.p("i=0")
511 self.exit()
512
513 class StepTest(GdbTest):
514 compile_args = ("programs/step.S", )
515
516 def setUp(self):
517 self.gdb.load()
518 self.gdb.b("main")
519 self.gdb.c()
520
521 def test(self):
522 main_address = self.gdb.p("$pc")
523 for expected in (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c):
524 self.gdb.stepi()
525 pc = self.gdb.p("$pc")
526 assertEqual("%x" % pc, "%x" % (expected + main_address))
527
528 class TriggerTest(GdbTest):
529 compile_args = ("programs/trigger.S", )
530 def setUp(self):
531 self.gdb.load()
532 self.gdb.b("_exit")
533 self.gdb.b("main")
534 self.gdb.c()
535
536 def exit(self):
537 output = self.gdb.c()
538 assertIn("Breakpoint", output)
539 assertIn("_exit", output)
540
541 class TriggerExecuteInstant(TriggerTest):
542 """Test an execute breakpoint on the first instruction executed out of
543 debug mode."""
544 def test(self):
545 main_address = self.gdb.p("$pc")
546 self.gdb.command("hbreak *0x%x" % (main_address + 4))
547 self.gdb.c()
548 assertEqual(self.gdb.p("$pc"), main_address+4)
549
550 class TriggerLoadAddress(TriggerTest):
551 def test(self):
552 self.gdb.command("rwatch *((&data)+1)")
553 output = self.gdb.c()
554 assertIn("read_loop", output)
555 assertEqual(self.gdb.p("$a0"),
556 self.gdb.p("(&data)+1"))
557 self.exit()
558
559 class TriggerLoadAddressInstant(TriggerTest):
560 """Test a load address breakpoint on the first instruction executed out of
561 debug mode."""
562 def test(self):
563 self.gdb.command("b just_before_read_loop")
564 self.gdb.c()
565 read_loop = self.gdb.p("&read_loop")
566 self.gdb.command("rwatch data")
567 self.gdb.c()
568 # Accept hitting the breakpoint before or after the load instruction.
569 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
570 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
571
572 class TriggerStoreAddress(TriggerTest):
573 def test(self):
574 self.gdb.command("watch *((&data)+3)")
575 output = self.gdb.c()
576 assertIn("write_loop", output)
577 assertEqual(self.gdb.p("$a0"),
578 self.gdb.p("(&data)+3"))
579 self.exit()
580
581 class TriggerStoreAddressInstant(TriggerTest):
582 def test(self):
583 """Test a store address breakpoint on the first instruction executed out
584 of debug mode."""
585 self.gdb.command("b just_before_write_loop")
586 self.gdb.c()
587 write_loop = self.gdb.p("&write_loop")
588 self.gdb.command("watch data")
589 self.gdb.c()
590 # Accept hitting the breakpoint before or after the store instruction.
591 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
592 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
593
594 class TriggerDmode(TriggerTest):
595 def test(self):
596 return 'not_applicable'
597 # pylint: disable=unreachable
598 # Temporarily not applicable until spike is fixed to match the spec
599 # change.
600 self.gdb.command("hbreak handle_trap")
601 self.gdb.p("$pc=write_valid")
602 output = self.gdb.c()
603 assertIn("handle_trap", output)
604 assertIn("mcause=2", output)
605 assertIn("mepc=%d" % self.gdb.p("&write_invalid_illegal"), output)
606
607 class RegsTest(GdbTest):
608 compile_args = ("programs/regs.S", )
609 def setUp(self):
610 self.gdb.load()
611 self.gdb.b("main")
612 self.gdb.b("handle_trap")
613 self.gdb.c()
614
615 class WriteGprs(RegsTest):
616 def test(self):
617 regs = [("x%d" % n) for n in range(2, 32)]
618
619 self.gdb.p("$pc=write_regs")
620 for i, r in enumerate(regs):
621 self.gdb.p("$%s=%d" % (r, (0xdeadbeef<<i)+17))
622 self.gdb.p("$x1=data")
623 self.gdb.command("b all_done")
624 output = self.gdb.c()
625 assertIn("Breakpoint ", output)
626
627 # Just to get this data in the log.
628 self.gdb.command("x/30gx data")
629 self.gdb.command("info registers")
630 for n in range(len(regs)):
631 assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
632 ((0xdeadbeef<<n)+17) & ((1<<self.target.xlen)-1))
633
634 class WriteCsrs(RegsTest):
635 def test(self):
636 # As much a test of gdb as of the simulator.
637 self.gdb.p("$mscratch=0")
638 self.gdb.stepi()
639 assertEqual(self.gdb.p("$mscratch"), 0)
640 self.gdb.p("$mscratch=123")
641 self.gdb.stepi()
642 assertEqual(self.gdb.p("$mscratch"), 123)
643
644 self.gdb.command("p $pc=write_regs")
645 self.gdb.command("p $a0=data")
646 self.gdb.command("b all_done")
647 self.gdb.command("c")
648
649 assertEqual(123, self.gdb.p("$mscratch"))
650 assertEqual(123, self.gdb.p("$x1"))
651 assertEqual(123, self.gdb.p("$csr832"))
652
653 class DownloadTest(GdbTest):
654 def setUp(self):
655 length = min(2**20, self.target.ram_size - 2048)
656 download_c = tempfile.NamedTemporaryFile(prefix="download_",
657 suffix=".c")
658 download_c.write("#include <stdint.h>\n")
659 download_c.write(
660 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
661 download_c.write("uint32_t length = %d;\n" % length)
662 download_c.write("uint8_t d[%d] = {\n" % length)
663 self.crc = 0
664 for i in range(length / 16):
665 download_c.write(" /* 0x%04x */ " % (i * 16))
666 for _ in range(16):
667 value = random.randrange(1<<8)
668 download_c.write("%d, " % value)
669 self.crc = binascii.crc32("%c" % value, self.crc)
670 download_c.write("\n")
671 download_c.write("};\n")
672 download_c.write("uint8_t *data = &d[0];\n")
673 download_c.write("uint32_t main() { return crc32a(data, length); }\n")
674 download_c.flush()
675
676 if self.crc < 0:
677 self.crc += 2**32
678
679 self.binary = self.target.compile(download_c.name,
680 "programs/checksum.c")
681 self.gdb.command("file %s" % self.binary)
682
683 def test(self):
684 self.gdb.load()
685 self.gdb.command("b _exit")
686 self.gdb.c()
687 assertEqual(self.gdb.p("status"), self.crc)
688
689 class MprvTest(GdbTest):
690 compile_args = ("programs/mprv.S", )
691 def setUp(self):
692 self.gdb.load()
693
694 def test(self):
695 """Test that the debugger can access memory when MPRV is set."""
696 self.gdb.c(wait=False)
697 time.sleep(0.5)
698 self.gdb.interrupt()
699 output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
700 assertIn("0xbead", output)
701
702 class PrivTest(GdbTest):
703 compile_args = ("programs/priv.S", )
704 def setUp(self):
705 self.gdb.load()
706
707 misa = self.gdb.p("$misa")
708 self.supported = set()
709 if misa & (1<<20):
710 self.supported.add(0)
711 if misa & (1<<18):
712 self.supported.add(1)
713 if misa & (1<<7):
714 self.supported.add(2)
715 self.supported.add(3)
716
717 class PrivRw(PrivTest):
718 def test(self):
719 """Test reading/writing priv."""
720 for privilege in range(4):
721 self.gdb.p("$priv=%d" % privilege)
722 self.gdb.stepi()
723 actual = self.gdb.p("$priv")
724 assertIn(actual, self.supported)
725 if privilege in self.supported:
726 assertEqual(actual, privilege)
727
728 class PrivChange(PrivTest):
729 def test(self):
730 """Test that the core's privilege level actually changes."""
731
732 if 0 not in self.supported:
733 return 'not_applicable'
734
735 self.gdb.b("main")
736 self.gdb.c()
737
738 # Machine mode
739 self.gdb.p("$priv=3")
740 main_address = self.gdb.p("$pc")
741 self.gdb.stepi()
742 assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
743
744 # User mode
745 self.gdb.p("$priv=0")
746 self.gdb.stepi()
747 # Should have taken an exception, so be nowhere near main.
748 pc = self.gdb.p("$pc")
749 assertTrue(pc < main_address or pc > main_address + 0x100)
750
751 class Target(object):
752 name = "name"
753 xlen = 0
754 directory = None
755 timeout_sec = 2
756 temporary_files = []
757 temporary_binary = None
758
759 def server(self):
760 raise NotImplementedError
761
762 def compile(self, *sources):
763 binary_name = "%s_%s-%d" % (
764 self.name,
765 os.path.basename(os.path.splitext(sources[0])[0]),
766 self.xlen)
767 if parsed.isolate:
768 self.temporary_binary = tempfile.NamedTemporaryFile(
769 prefix=binary_name + "_")
770 binary_name = self.temporary_binary.name
771 Target.temporary_files.append(self.temporary_binary)
772 testlib.compile(sources +
773 ("programs/entry.S", "programs/init.c",
774 "-I", "../env",
775 "-T", "targets/%s/link.lds" % (self.directory or self.name),
776 "-nostartfiles",
777 "-mcmodel=medany",
778 "-o", binary_name),
779 xlen=self.xlen)
780 return binary_name
781
782 class SpikeTarget(Target):
783 directory = "spike"
784 ram = 0x80010000
785 ram_size = 5 * 1024 * 1024
786 instruction_hardware_breakpoint_count = 4
787 reset_vector = 0x1000
788
789 class Spike64Target(SpikeTarget):
790 name = "spike64"
791 xlen = 64
792
793 def server(self):
794 return testlib.Spike(parsed.cmd, halted=True)
795
796 class Spike32Target(SpikeTarget):
797 name = "spike32"
798 xlen = 32
799
800 def server(self):
801 return testlib.Spike(parsed.cmd, halted=True, xlen=32)
802
803 class FreedomE300Target(Target):
804 name = "freedom-e300"
805 xlen = 32
806 ram = 0x80000000
807 ram_size = 16 * 1024
808 instruction_hardware_breakpoint_count = 2
809
810 def server(self):
811 return testlib.Openocd(cmd=parsed.cmd,
812 config="targets/%s/openocd.cfg" % self.name)
813
814 class FreedomE300SimTarget(Target):
815 name = "freedom-e300-sim"
816 xlen = 32
817 timeout_sec = 240
818 ram = 0x80000000
819 ram_size = 256 * 1024 * 1024
820 instruction_hardware_breakpoint_count = 2
821
822 def server(self):
823 sim = testlib.VcsSim(simv=parsed.run, debug=False)
824 openocd = testlib.Openocd(cmd=parsed.cmd,
825 config="targets/%s/openocd.cfg" % self.name,
826 otherProcess=sim)
827 time.sleep(20)
828 return openocd
829
830 class FreedomU500Target(Target):
831 name = "freedom-u500"
832 xlen = 64
833 ram = 0x80000000
834 ram_size = 16 * 1024
835 instruction_hardware_breakpoint_count = 2
836
837 def server(self):
838 return testlib.Openocd(cmd=parsed.cmd,
839 config="targets/%s/openocd.cfg" % self.name)
840
841 class FreedomU500SimTarget(Target):
842 name = "freedom-u500-sim"
843 xlen = 64
844 timeout_sec = 240
845 ram = 0x80000000
846 ram_size = 256 * 1024 * 1024
847 instruction_hardware_breakpoint_count = 2
848
849 def server(self):
850 sim = testlib.VcsSim(simv=parsed.run, debug=False)
851 openocd = testlib.Openocd(cmd=parsed.cmd,
852 config="targets/%s/openocd.cfg" % self.name,
853 otherProcess=sim)
854 time.sleep(20)
855 return openocd
856
857 targets = [
858 Spike32Target,
859 Spike64Target,
860 FreedomE300Target,
861 FreedomU500Target,
862 FreedomE300SimTarget,
863 FreedomU500SimTarget]
864
865 parsed = None
866 def main():
867 parser = argparse.ArgumentParser(
868 epilog="""
869 Example command line from the real world:
870 Run all RegsTest cases against a physical FPGA, with custom openocd command:
871 ./gdbserver.py --freedom-e300 --cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" RegsTest
872 """)
873 group = parser.add_mutually_exclusive_group(required=True)
874 for t in targets:
875 group.add_argument("--%s" % t.name, action="store_const", const=t,
876 dest="target")
877 parser.add_argument("--run",
878 help="The command to use to start the actual target (e.g. "
879 "simulation)")
880 parser.add_argument("--cmd",
881 help="The command to use to start the debug server.")
882 parser.add_argument("--gdb",
883 help="The command to use to start gdb.")
884
885 xlen_group = parser.add_mutually_exclusive_group()
886 xlen_group.add_argument("--32", action="store_const", const=32, dest="xlen",
887 help="Force the target to be 32-bit.")
888 xlen_group.add_argument("--64", action="store_const", const=64, dest="xlen",
889 help="Force the target to be 64-bit.")
890
891 parser.add_argument("--isolate", action="store_true",
892 help="Try to run in such a way that multiple instances can run at "
893 "the same time. This may make it harder to debug a failure if it "
894 "does occur.")
895
896 parser.add_argument("test", nargs='*',
897 help="Run only tests that are named here.")
898
899 # TODO: remove global
900 global parsed # pylint: disable=global-statement
901 parsed = parser.parse_args()
902
903 target = parsed.target()
904 if parsed.xlen:
905 target.xlen = parsed.xlen
906
907 return run_all_tests(target, parsed.test)
908
909 # TROUBLESHOOTING TIPS
910 # If a particular test fails, run just that one test, eg.:
911 # ./gdbserver.py MprvTest.test_mprv
912 # Then inspect gdb.log and spike.log to see what happened in more detail.
913
914 if __name__ == '__main__':
915 sys.exit(main())