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