Add MemTestWriteInvalid.
[riscv-tests.git] / debug / gdbserver.py
index 75ab2922045babaa4478988ff2a9711cc35ce1f2..318428daba3407d70038c95fa6e2255a6479a0b4 100755 (executable)
@@ -1,12 +1,13 @@
 #!/usr/bin/env python
 
+import argparse
+import binascii
 import os
+import random
+import re
 import sys
-import argparse
 import tempfile
 import time
-import random
-import binascii
 import traceback
 
 import testlib
@@ -174,7 +175,9 @@ class TestFailed(Exception):
         Exception.__init__(self)
         self.message = message
 
-def run_all_tests(target, tests):
+def run_all_tests(target, tests, fail_fast):
+    good_results = set(('pass', 'not_applicable'))
+
     results = {}
     module = sys.modules[__name__]
     for name in dir(module):
@@ -184,11 +187,11 @@ def run_all_tests(target, tests):
             instance = definition(target)
             result = instance.run()
             results.setdefault(result, []).append(name)
+            if result not in good_results and fail_fast:
+                break
 
     print ":" * 40
 
-    good_results = set(('pass', 'not_applicable'))
-
     result = 0
     for key, value in results.iteritems():
         print "%d tests returned %s" % (len(value), key)
@@ -223,6 +226,10 @@ def assertTrue(a):
     if not a:
         raise TestFailed("%r is not True" % a)
 
+def assertRegexpMatches(text, regexp):
+    if not re.search(regexp, text):
+        raise TestFailed("can't find %r in %r" % (regexp, text))
+
 class SimpleRegisterTest(GdbTest):
     def check_reg(self, name):
         a = random.randrange(1<<self.target.xlen)
@@ -286,6 +293,28 @@ class MemTest64(SimpleMemoryTest):
     def test(self):
         self.access_test(8, 'long long')
 
+class MemTestReadInvalid(SimpleMemoryTest):
+    def test(self):
+        # This test relies on 'gdb_report_data_abort enable' being executed in
+        # the openocd.cfg file.
+        try:
+            self.gdb.p("*((int*)0xdeadbeef)")
+            assert False, "Read should have failed."
+        except testlib.CannotAccess as e:
+            assertEqual(e.address, 0xdeadbeef)
+        self.gdb.p("*((int*)0x%x)" % self.target.ram)
+
+class MemTestWriteInvalid(SimpleMemoryTest):
+    def test(self):
+        # This test relies on 'gdb_report_data_abort enable' being executed in
+        # the openocd.cfg file.
+        try:
+            self.gdb.p("*((int*)0xdeadbeef)=8675309")
+            assert False, "Write should have failed."
+        except testlib.CannotAccess as e:
+            assertEqual(e.address, 0xdeadbeef)
+        self.gdb.p("*((int*)0x%x)=6874742" % self.target.ram)
+
 class MemTestBlock(GdbTest):
     def test(self):
         length = 1024
@@ -428,7 +457,7 @@ class Hwbp1(DebugTest):
         for _ in range(2):
             output = self.gdb.c()
             self.gdb.p("$pc")
-            assertIn("Breakpoint ", output)
+            assertRegexpMatches(output, r"[bB]reakpoint")
             assertIn("rot13 ", output)
         self.exit()
 
@@ -443,7 +472,7 @@ class Hwbp2(DebugTest):
         for expected in ("main", "rot13", "rot13"):
             output = self.gdb.c()
             self.gdb.p("$pc")
-            assertIn("Breakpoint ", output)
+            assertRegexpMatches(output, r"[bB]reakpoint")
             assertIn("%s " % expected, output)
         self.exit()
 
@@ -534,9 +563,9 @@ class TriggerTest(GdbTest):
         assertIn("_exit", output)
 
 class TriggerExecuteInstant(TriggerTest):
+    """Test an execute breakpoint on the first instruction executed out of
+    debug mode."""
     def test(self):
-        """Test an execute breakpoint on the first instruction executed out of
-        debug mode."""
         main_address = self.gdb.p("$pc")
         self.gdb.command("hbreak *0x%x" % (main_address + 4))
         self.gdb.c()
@@ -552,9 +581,9 @@ class TriggerLoadAddress(TriggerTest):
         self.exit()
 
 class TriggerLoadAddressInstant(TriggerTest):
+    """Test a load address breakpoint on the first instruction executed out of
+    debug mode."""
     def test(self):
-        """Test a load address breakpoint on the first instruction executed out
-        of debug mode."""
         self.gdb.command("b just_before_read_loop")
         self.gdb.c()
         read_loop = self.gdb.p("&read_loop")
@@ -573,7 +602,7 @@ class TriggerStoreAddress(TriggerTest):
                 self.gdb.p("(&data)+3"))
         self.exit()
 
-class TriggerStoreAddressInstance(TriggerTest):
+class TriggerStoreAddressInstant(TriggerTest):
     def test(self):
         """Test a store address breakpoint on the first instruction executed out
         of debug mode."""
@@ -587,13 +616,47 @@ class TriggerStoreAddressInstance(TriggerTest):
         assertEqual(self.gdb.p("$a0"), self.gdb.p("&data"))
 
 class TriggerDmode(TriggerTest):
+    def check_triggers(self, tdata1_lsbs, tdata2):
+        dmode = 1 << (self.target.xlen-5)
+
+        triggers = []
+
+        if self.target.xlen == 32:
+            xlen_type = 'int'
+        elif self.target.xlen == 64:
+            xlen_type = 'long long'
+        else:
+            raise NotImplementedError
+
+        dmode_count = 0
+        i = 0
+        for i in range(16):
+            tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i))
+            if tdata1 == 0:
+                break
+            tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1))
+
+            if tdata1 & dmode:
+                dmode_count += 1
+            else:
+                assertEqual(tdata1 & 0xffff, tdata1_lsbs)
+                assertEqual(tdata2, tdata2)
+
+        assertGreater(i, 1)
+        assertEqual(dmode_count, 1)
+
+        return triggers
+
     def test(self):
-        self.gdb.command("hbreak handle_trap")
-        self.gdb.p("$pc=write_valid")
+        self.gdb.command("hbreak write_load_trigger")
+        self.gdb.b("clear_triggers")
+        self.gdb.p("$pc=write_store_trigger")
+        output = self.gdb.c()
+        assertIn("write_load_trigger", output)
+        self.check_triggers((1<<6) | (1<<1), 0xdeadbee0)
         output = self.gdb.c()
-        assertIn("handle_trap", output)
-        assertIn("mcause=2", output)
-        assertIn("mepc=%d" % self.gdb.p("&write_invalid_illegal"), output)
+        assertIn("clear_triggers", output)
+        self.check_triggers((1<<6) | (1<<0), 0xfeedac00)
 
 class RegsTest(GdbTest):
     compile_args = ("programs/regs.S", )
@@ -884,6 +947,9 @@ def main():
             "the same time. This may make it harder to debug a failure if it "
             "does occur.")
 
+    parser.add_argument("--fail-fast", "-f", action="store_true",
+            help="Exit as soon as any test fails.")
+
     parser.add_argument("test", nargs='*',
             help="Run only tests that are named here.")
 
@@ -895,7 +961,7 @@ def main():
     if parsed.xlen:
         target.xlen = parsed.xlen
 
-    return run_all_tests(target, parsed.test)
+    return run_all_tests(target, parsed.test, parsed.fail_fast)
 
 # TROUBLESHOOTING TIPS
 # If a particular test fails, run just that one test, eg.: