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