Improve reg test a little.
[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
10 import targets
11 import testlib
12 from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn
13 from testlib import assertGreater, assertTrue, assertRegexpMatches
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 class GdbTest(testlib.BaseTest):
90 def __init__(self, target):
91 testlib.BaseTest.__init__(self, target)
92 self.gdb = None
93
94 def classSetup(self):
95 testlib.BaseTest.classSetup(self)
96 self.logs.append("gdb.log")
97 self.gdb = gdb(self.target, self.server.port, self.binary)
98
99 def classTeardown(self):
100 del self.gdb
101 testlib.BaseTest.classTeardown(self)
102
103 class SimpleRegisterTest(GdbTest):
104 def check_reg(self, name):
105 a = random.randrange(1<<self.target.xlen)
106 b = random.randrange(1<<self.target.xlen)
107 self.gdb.p("$%s=0x%x" % (name, a))
108 self.gdb.stepi()
109 assertEqual(self.gdb.p("$%s" % name), a)
110 self.gdb.p("$%s=0x%x" % (name, b))
111 self.gdb.stepi()
112 assertEqual(self.gdb.p("$%s" % name), b)
113
114 def setup(self):
115 # 0x13 is nop
116 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
117 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
118 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
119 self.gdb.p("$pc=0x%x" % self.target.ram)
120
121 class SimpleS0Test(SimpleRegisterTest):
122 def test(self):
123 self.check_reg("s0")
124
125 class SimpleS1Test(SimpleRegisterTest):
126 def test(self):
127 self.check_reg("s1")
128
129 class SimpleT0Test(SimpleRegisterTest):
130 def test(self):
131 self.check_reg("t0")
132
133 class SimpleT1Test(SimpleRegisterTest):
134 def test(self):
135 self.check_reg("t1")
136
137 class SimpleMemoryTest(GdbTest):
138 def access_test(self, size, data_type):
139 assertEqual(self.gdb.p("sizeof(%s)" % data_type), size)
140 a = 0x86753095555aaaa & ((1<<(size*8))-1)
141 b = 0xdeadbeef12345678 & ((1<<(size*8))-1)
142 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram, a))
143 self.gdb.p("*((%s*)0x%x) = 0x%x" % (data_type, self.target.ram + size,
144 b))
145 assertEqual(self.gdb.p("*((%s*)0x%x)" % (data_type, self.target.ram)),
146 a)
147 assertEqual(self.gdb.p("*((%s*)0x%x)" % (
148 data_type, self.target.ram + size)), b)
149
150 class MemTest8(SimpleMemoryTest):
151 def test(self):
152 self.access_test(1, 'char')
153
154 class MemTest16(SimpleMemoryTest):
155 def test(self):
156 self.access_test(2, 'short')
157
158 class MemTest32(SimpleMemoryTest):
159 def test(self):
160 self.access_test(4, 'int')
161
162 class MemTest64(SimpleMemoryTest):
163 def test(self):
164 self.access_test(8, 'long long')
165
166 class MemTestReadInvalid(SimpleMemoryTest):
167 def test(self):
168 # This test relies on 'gdb_report_data_abort enable' being executed in
169 # the openocd.cfg file.
170 try:
171 self.gdb.p("*((int*)0xdeadbeef)")
172 assert False, "Read should have failed."
173 except testlib.CannotAccess as e:
174 assertEqual(e.address, 0xdeadbeef)
175 self.gdb.p("*((int*)0x%x)" % self.target.ram)
176
177 class MemTestWriteInvalid(SimpleMemoryTest):
178 def test(self):
179 # This test relies on 'gdb_report_data_abort enable' being executed in
180 # the openocd.cfg file.
181 try:
182 self.gdb.p("*((int*)0xdeadbeef)=8675309")
183 assert False, "Write should have failed."
184 except testlib.CannotAccess as e:
185 assertEqual(e.address, 0xdeadbeef)
186 self.gdb.p("*((int*)0x%x)=6874742" % self.target.ram)
187
188 class MemTestBlock(GdbTest):
189 def test(self):
190 length = 1024
191 line_length = 16
192 a = tempfile.NamedTemporaryFile(suffix=".ihex")
193 data = ""
194 for i in range(length / line_length):
195 line_data = "".join(["%c" % random.randrange(256)
196 for _ in range(line_length)])
197 data += line_data
198 a.write(ihex_line(i * line_length, 0, line_data))
199 a.flush()
200
201 self.gdb.command("restore %s 0x%x" % (a.name, self.target.ram))
202 for offset in range(0, length, 19*4) + [length-4]:
203 value = self.gdb.p("*((int*)0x%x)" % (self.target.ram + offset))
204 written = ord(data[offset]) | \
205 (ord(data[offset+1]) << 8) | \
206 (ord(data[offset+2]) << 16) | \
207 (ord(data[offset+3]) << 24)
208 assertEqual(value, written)
209
210 b = tempfile.NamedTemporaryFile(suffix=".ihex")
211 self.gdb.command("dump ihex memory %s 0x%x 0x%x" % (b.name,
212 self.target.ram, self.target.ram + length))
213 for line in b:
214 record_type, address, line_data = ihex_parse(line)
215 if record_type == 0:
216 assertEqual(readable_binary_string(line_data),
217 readable_binary_string(
218 data[address:address+len(line_data)]))
219
220 class InstantHaltTest(GdbTest):
221 def test(self):
222 assertEqual(self.target.reset_vector, self.gdb.p("$pc"))
223 # mcycle and minstret have no defined reset value.
224 mstatus = self.gdb.p("$mstatus")
225 assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
226 MSTATUS_VM), 0)
227
228 class InstantChangePc(GdbTest):
229 def test(self):
230 """Change the PC right as we come out of reset."""
231 # 0x13 is nop
232 self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
233 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
234 self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
235 self.gdb.p("$pc=0x%x" % self.target.ram)
236 self.gdb.stepi()
237 assertEqual((self.target.ram + 4), self.gdb.p("$pc"))
238 self.gdb.stepi()
239 assertEqual((self.target.ram + 8), self.gdb.p("$pc"))
240
241 class DebugTest(GdbTest):
242 # Include malloc so that gdb can make function calls. I suspect this malloc
243 # will silently blow through the memory set aside for it, so be careful.
244 compile_args = ("programs/debug.c", "programs/checksum.c",
245 "programs/tiny-malloc.c", "-DDEFINE_MALLOC", "-DDEFINE_FREE")
246
247 def setup(self):
248 self.gdb.load()
249 self.gdb.b("_exit")
250
251 def exit(self, expected_result=0xc86455d4):
252 output = self.gdb.c()
253 assertIn("Breakpoint", output)
254 assertIn("_exit", output)
255 assertEqual(self.gdb.p("status"), expected_result)
256
257 class DebugFunctionCall(DebugTest):
258 def test(self):
259 self.gdb.b("main:start")
260 self.gdb.c()
261 assertEqual(self.gdb.p('fib(6)'), 8)
262 assertEqual(self.gdb.p('fib(7)'), 13)
263 self.exit()
264
265 class DebugChangeString(DebugTest):
266 def test(self):
267 text = "This little piggy went to the market."
268 self.gdb.b("main:start")
269 self.gdb.c()
270 self.gdb.p('fox = "%s"' % text)
271 self.exit(0x43b497b8)
272
273 class DebugTurbostep(DebugTest):
274 def test(self):
275 """Single step a bunch of times."""
276 self.gdb.b("main:start")
277 self.gdb.c()
278 self.gdb.command("p i=0")
279 last_pc = None
280 advances = 0
281 jumps = 0
282 for _ in range(100):
283 self.gdb.stepi()
284 pc = self.gdb.p("$pc")
285 assertNotEqual(last_pc, pc)
286 if last_pc and pc > last_pc and pc - last_pc <= 4:
287 advances += 1
288 else:
289 jumps += 1
290 last_pc = pc
291 # Some basic sanity that we're not running between breakpoints or
292 # something.
293 assertGreater(jumps, 10)
294 assertGreater(advances, 50)
295
296 class DebugExit(DebugTest):
297 def test(self):
298 self.exit()
299
300 class DebugSymbols(DebugTest):
301 def test(self):
302 self.gdb.b("main")
303 self.gdb.b("rot13")
304 output = self.gdb.c()
305 assertIn(", main ", output)
306 output = self.gdb.c()
307 assertIn(", rot13 ", output)
308
309 class DebugBreakpoint(DebugTest):
310 def test(self):
311 self.gdb.b("rot13")
312 # The breakpoint should be hit exactly 2 times.
313 for _ in range(2):
314 output = self.gdb.c()
315 self.gdb.p("$pc")
316 assertIn("Breakpoint ", output)
317 assertIn("rot13 ", output)
318 self.exit()
319
320 class Hwbp1(DebugTest):
321 def test(self):
322 if self.target.instruction_hardware_breakpoint_count < 1:
323 return 'not_applicable'
324
325 self.gdb.hbreak("rot13")
326 # The breakpoint should be hit exactly 2 times.
327 for _ in range(2):
328 output = self.gdb.c()
329 self.gdb.p("$pc")
330 assertRegexpMatches(output, r"[bB]reakpoint")
331 assertIn("rot13 ", output)
332 self.exit()
333
334 class Hwbp2(DebugTest):
335 def test(self):
336 if self.target.instruction_hardware_breakpoint_count < 2:
337 return 'not_applicable'
338
339 self.gdb.hbreak("main")
340 self.gdb.hbreak("rot13")
341 # We should hit 3 breakpoints.
342 for expected in ("main", "rot13", "rot13"):
343 output = self.gdb.c()
344 self.gdb.p("$pc")
345 assertRegexpMatches(output, r"[bB]reakpoint")
346 assertIn("%s " % expected, output)
347 self.exit()
348
349 class TooManyHwbp(DebugTest):
350 def run(self):
351 for i in range(30):
352 self.gdb.hbreak("*rot13 + %d" % (i * 4))
353
354 output = self.gdb.c()
355 assertIn("Cannot insert hardware breakpoint", output)
356 # Clean up, otherwise the hardware breakpoints stay set and future
357 # tests may fail.
358 self.gdb.command("D")
359
360 class Registers(DebugTest):
361 def test(self):
362 # Get to a point in the code where some registers have actually been
363 # used.
364 self.gdb.b("rot13")
365 self.gdb.c()
366 self.gdb.c()
367 # Try both forms to test gdb.
368 for cmd in ("info all-registers", "info registers all"):
369 output = self.gdb.command(cmd)
370 assertNotIn("Could not", output)
371 for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
372 assertIn(reg, output)
373
374 #TODO
375 # mcpuid is one of the few registers that should have the high bit set
376 # (for rv64).
377 # Leave this commented out until gdb and spike agree on the encoding of
378 # mcpuid (which is going to be renamed to misa in any case).
379 #assertRegexpMatches(output, ".*mcpuid *0x80")
380
381 #TODO:
382 # The instret register should always be changing.
383 #last_instret = None
384 #for _ in range(5):
385 # instret = self.gdb.p("$instret")
386 # assertNotEqual(instret, last_instret)
387 # last_instret = instret
388 # self.gdb.stepi()
389
390 self.exit()
391
392 class UserInterrupt(DebugTest):
393 def test(self):
394 """Sending gdb ^C while the program is running should cause it to
395 halt."""
396 self.gdb.b("main:start")
397 self.gdb.c()
398 self.gdb.p("i=123")
399 self.gdb.c(wait=False)
400 time.sleep(0.1)
401 output = self.gdb.interrupt()
402 assert "main" in output
403 assertGreater(self.gdb.p("j"), 10)
404 self.gdb.p("i=0")
405 self.exit()
406
407 class StepTest(GdbTest):
408 compile_args = ("programs/step.S", )
409
410 def setup(self):
411 self.gdb.load()
412 self.gdb.b("main")
413 self.gdb.c()
414
415 def test(self):
416 main_address = self.gdb.p("$pc")
417 for expected in (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c):
418 self.gdb.stepi()
419 pc = self.gdb.p("$pc")
420 assertEqual("%x" % pc, "%x" % (expected + main_address))
421
422 class TriggerTest(GdbTest):
423 compile_args = ("programs/trigger.S", )
424 def setup(self):
425 self.gdb.load()
426 self.gdb.b("_exit")
427 self.gdb.b("main")
428 self.gdb.c()
429
430 def exit(self):
431 output = self.gdb.c()
432 assertIn("Breakpoint", output)
433 assertIn("_exit", output)
434
435 class TriggerExecuteInstant(TriggerTest):
436 """Test an execute breakpoint on the first instruction executed out of
437 debug mode."""
438 def test(self):
439 main_address = self.gdb.p("$pc")
440 self.gdb.command("hbreak *0x%x" % (main_address + 4))
441 self.gdb.c()
442 assertEqual(self.gdb.p("$pc"), main_address+4)
443
444 class TriggerLoadAddress(TriggerTest):
445 def test(self):
446 self.gdb.command("rwatch *((&data)+1)")
447 output = self.gdb.c()
448 assertIn("read_loop", output)
449 assertEqual(self.gdb.p("$a0"),
450 self.gdb.p("(&data)+1"))
451 self.exit()
452
453 class TriggerLoadAddressInstant(TriggerTest):
454 """Test a load address breakpoint on the first instruction executed out of
455 debug mode."""
456 def test(self):
457 self.gdb.command("b just_before_read_loop")
458 self.gdb.c()
459 read_loop = self.gdb.p("&read_loop")
460 self.gdb.command("rwatch data")
461 self.gdb.c()
462 # Accept hitting the breakpoint before or after the load instruction.
463 assertIn(self.gdb.p("$pc"), [read_loop, read_loop + 4])
464 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
465
466 class TriggerStoreAddress(TriggerTest):
467 def test(self):
468 self.gdb.command("watch *((&data)+3)")
469 output = self.gdb.c()
470 assertIn("write_loop", output)
471 assertEqual(self.gdb.p("$a0"),
472 self.gdb.p("(&data)+3"))
473 self.exit()
474
475 class TriggerStoreAddressInstant(TriggerTest):
476 def test(self):
477 """Test a store address breakpoint on the first instruction executed out
478 of debug mode."""
479 self.gdb.command("b just_before_write_loop")
480 self.gdb.c()
481 write_loop = self.gdb.p("&write_loop")
482 self.gdb.command("watch data")
483 self.gdb.c()
484 # Accept hitting the breakpoint before or after the store instruction.
485 assertIn(self.gdb.p("$pc"), [write_loop, write_loop + 4])
486 assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
487
488 class TriggerDmode(TriggerTest):
489 def check_triggers(self, tdata1_lsbs, tdata2):
490 dmode = 1 << (self.target.xlen-5)
491
492 triggers = []
493
494 if self.target.xlen == 32:
495 xlen_type = 'int'
496 elif self.target.xlen == 64:
497 xlen_type = 'long long'
498 else:
499 raise NotImplementedError
500
501 dmode_count = 0
502 i = 0
503 for i in range(16):
504 tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i))
505 if tdata1 == 0:
506 break
507 tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1))
508
509 if tdata1 & dmode:
510 dmode_count += 1
511 else:
512 assertEqual(tdata1 & 0xffff, tdata1_lsbs)
513 assertEqual(tdata2, tdata2)
514
515 assertGreater(i, 1)
516 assertEqual(dmode_count, 1)
517
518 return triggers
519
520 def test(self):
521 self.gdb.command("hbreak write_load_trigger")
522 self.gdb.b("clear_triggers")
523 self.gdb.p("$pc=write_store_trigger")
524 output = self.gdb.c()
525 assertIn("write_load_trigger", output)
526 self.check_triggers((1<<6) | (1<<1), 0xdeadbee0)
527 output = self.gdb.c()
528 assertIn("clear_triggers", output)
529 self.check_triggers((1<<6) | (1<<0), 0xfeedac00)
530
531 class RegsTest(GdbTest):
532 compile_args = ("programs/regs.S", )
533 def setup(self):
534 self.gdb.load()
535 self.gdb.b("main")
536 self.gdb.b("handle_trap")
537 self.gdb.c()
538
539 class WriteGprs(RegsTest):
540 def test(self):
541 regs = [("x%d" % n) for n in range(2, 32)]
542
543 self.gdb.p("$pc=write_regs")
544 for i, r in enumerate(regs):
545 self.gdb.p("$%s=%d" % (r, (0xdeadbeef<<i)+17))
546 self.gdb.p("$x1=data")
547 self.gdb.command("b all_done")
548 output = self.gdb.c()
549 assertIn("Breakpoint ", output)
550
551 # Just to get this data in the log.
552 self.gdb.command("x/30gx data")
553 self.gdb.command("info registers")
554 for n in range(len(regs)):
555 assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
556 ((0xdeadbeef<<n)+17) & ((1<<self.target.xlen)-1))
557
558 class WriteCsrs(RegsTest):
559 def test(self):
560 # As much a test of gdb as of the simulator.
561 self.gdb.p("$mscratch=0")
562 self.gdb.stepi()
563 assertEqual(self.gdb.p("$mscratch"), 0)
564 self.gdb.p("$mscratch=123")
565 self.gdb.stepi()
566 assertEqual(self.gdb.p("$mscratch"), 123)
567
568 self.gdb.command("p $pc=write_regs")
569 self.gdb.command("p $a0=data")
570 self.gdb.command("b all_done")
571 self.gdb.command("c")
572
573 assertEqual(123, self.gdb.p("$mscratch"))
574 assertEqual(123, self.gdb.p("$x1"))
575 assertEqual(123, self.gdb.p("$csr832"))
576
577 class DownloadTest(GdbTest):
578 def setup(self):
579 # pylint: disable=attribute-defined-outside-init
580 length = min(2**20, self.target.ram_size - 2048)
581 download_c = tempfile.NamedTemporaryFile(prefix="download_",
582 suffix=".c")
583 download_c.write("#include <stdint.h>\n")
584 download_c.write(
585 "unsigned int crc32a(uint8_t *message, unsigned int size);\n")
586 download_c.write("uint32_t length = %d;\n" % length)
587 download_c.write("uint8_t d[%d] = {\n" % length)
588 self.crc = 0
589 for i in range(length / 16):
590 download_c.write(" /* 0x%04x */ " % (i * 16))
591 for _ in range(16):
592 value = random.randrange(1<<8)
593 download_c.write("%d, " % value)
594 self.crc = binascii.crc32("%c" % value, self.crc)
595 download_c.write("\n")
596 download_c.write("};\n")
597 download_c.write("uint8_t *data = &d[0];\n")
598 download_c.write("uint32_t main() { return crc32a(data, length); }\n")
599 download_c.flush()
600
601 if self.crc < 0:
602 self.crc += 2**32
603
604 self.binary = self.target.compile(download_c.name,
605 "programs/checksum.c")
606 self.gdb.command("file %s" % self.binary)
607
608 def test(self):
609 self.gdb.load()
610 self.gdb.command("b _exit")
611 self.gdb.c()
612 assertEqual(self.gdb.p("status"), self.crc)
613
614 class MprvTest(GdbTest):
615 compile_args = ("programs/mprv.S", )
616 def setup(self):
617 self.gdb.load()
618
619 def test(self):
620 """Test that the debugger can access memory when MPRV is set."""
621 self.gdb.c(wait=False)
622 time.sleep(0.5)
623 self.gdb.interrupt()
624 output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)")
625 assertIn("0xbead", output)
626
627 class PrivTest(GdbTest):
628 compile_args = ("programs/priv.S", )
629 def setup(self):
630 # pylint: disable=attribute-defined-outside-init
631 self.gdb.load()
632
633 misa = self.gdb.p("$misa")
634 self.supported = set()
635 if misa & (1<<20):
636 self.supported.add(0)
637 if misa & (1<<18):
638 self.supported.add(1)
639 if misa & (1<<7):
640 self.supported.add(2)
641 self.supported.add(3)
642
643 class PrivRw(PrivTest):
644 def test(self):
645 """Test reading/writing priv."""
646 for privilege in range(4):
647 self.gdb.p("$priv=%d" % privilege)
648 self.gdb.stepi()
649 actual = self.gdb.p("$priv")
650 assertIn(actual, self.supported)
651 if privilege in self.supported:
652 assertEqual(actual, privilege)
653
654 class PrivChange(PrivTest):
655 def test(self):
656 """Test that the core's privilege level actually changes."""
657
658 if 0 not in self.supported:
659 return 'not_applicable'
660
661 self.gdb.b("main")
662 self.gdb.c()
663
664 # Machine mode
665 self.gdb.p("$priv=3")
666 main_address = self.gdb.p("$pc")
667 self.gdb.stepi()
668 assertEqual("%x" % self.gdb.p("$pc"), "%x" % (main_address+4))
669
670 # User mode
671 self.gdb.p("$priv=0")
672 self.gdb.stepi()
673 # Should have taken an exception, so be nowhere near main.
674 pc = self.gdb.p("$pc")
675 assertTrue(pc < main_address or pc > main_address + 0x100)
676
677 parsed = None
678 def main():
679 parser = argparse.ArgumentParser(
680 description="Test that gdb can talk to a RISC-V target.",
681 epilog="""
682 Example command line from the real world:
683 Run all RegsTest cases against a physical FPGA, with custom openocd command:
684 ./gdbserver.py --freedom-e300 --cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
685 """)
686 targets.add_target_options(parser)
687 parser.add_argument("--gdb",
688 help="The command to use to start gdb.")
689
690 testlib.add_test_run_options(parser)
691
692 # TODO: remove global
693 global parsed # pylint: disable=global-statement
694 parsed = parser.parse_args()
695
696 target = parsed.target(parsed.cmd, parsed.run, parsed.isolate)
697 if parsed.xlen:
698 target.xlen = parsed.xlen
699
700 module = sys.modules[__name__]
701
702 return testlib.run_all_tests(module, target, parsed.test, parsed.fail_fast)
703
704 # TROUBLESHOOTING TIPS
705 # If a particular test fails, run just that one test, eg.:
706 # ./gdbserver.py MprvTest.test_mprv
707 # Then inspect gdb.log and spike.log to see what happened in more detail.
708
709 if __name__ == '__main__':
710 sys.exit(main())