Add gdb_setup to target for arbitrary gdb commands
[riscv-tests.git] / debug / testlib.py
index b8ff5c2edceb3e6d6b1c6982f15d542ae5ae2f51..c44a763f212837bfe509e941a07d36f303f19d0a 100644 (file)
@@ -1,3 +1,4 @@
+import collections
 import os.path
 import random
 import re
@@ -260,7 +261,7 @@ class Openocd(object):
         try:
             self.process.kill()
             self.process.wait()
-        except OSError:
+        except (OSError, AttributeError):
             pass
 
 class OpenocdCli(object):
@@ -294,6 +295,9 @@ class CannotAccess(Exception):
         Exception.__init__(self)
         self.address = address
 
+Thread = collections.namedtuple('Thread', ('id', 'target_id', 'name',
+    'frame'))
+
 class Gdb(object):
     logfile = tempfile.NamedTemporaryFile(prefix="gdb", suffix=".log")
     logname = logfile.name
@@ -320,13 +324,17 @@ class Gdb(object):
         self.child.expect(r"\(gdb\)", timeout=timeout)
         return self.child.before.strip()
 
-    def c(self, wait=True, timeout=-1):
+    def c(self, wait=True, timeout=-1, async=False):
+        if async:
+            async = "&"
+        else:
+            async = ""
         if wait:
-            output = self.command("c", timeout=timeout)
+            output = self.command("c%s" % async, timeout=timeout)
             assert "Continuing" in output
             return output
         else:
-            self.child.sendline("c")
+            self.child.sendline("c%s" % async)
             self.child.expect("Continuing")
 
     def interrupt(self):
@@ -380,6 +388,22 @@ class Gdb(object):
         assert "Hardware assisted breakpoint" in output
         return output
 
+    def threads(self):
+        output = self.command("info threads")
+        threads = []
+        for line in output.splitlines():
+            m = re.match(
+                    r"[\s\*]*(\d+)\s*Thread (\d+)\s*\(Name: ([^\)]+)\s*(.*)",
+                    line)
+            if m:
+                threads.append(Thread(*m.groups()))
+        if not threads:
+            threads.append(Thread('1', '1', 'Default', '???'))
+        return threads
+
+    def thread(self, thread):
+        return self.command("thread %s" % thread.id)
+
 def run_all_tests(module, target, parsed):
     if not os.path.exists(parsed.logs):
         os.makedirs(parsed.logs)
@@ -392,8 +416,9 @@ def run_all_tests(module, target, parsed):
     todo = []
     if parsed.misaval:
         target.misa = int(parsed.misaval, 16)
-        print "Assuming $MISA value of 0x%x. Skipping ExamineTarget." % \
-                target.misa
+        print "Using $misa from command line: 0x%x" % target.misa
+    elif target.misa:
+        print "Using $misa from target definition: 0x%x" % target.misa
     else:
         todo.append(("ExamineTarget", ExamineTarget))
 
@@ -514,7 +539,7 @@ class BaseTest(object):
 
     def classSetup(self):
         self.compile()
-        self.target_process = self.target.target()
+        self.target_process = self.target.create()
         self.server = self.target.server()
         self.logs.append(self.server.logname)
 
@@ -594,11 +619,11 @@ class GdbTest(BaseTest):
                     "target extended-remote localhost:%d" % self.server.port)
             # Select a random thread.
             # TODO: Allow a command line option to force a specific thread.
-            output = self.gdb.command("info threads")
-            threads = re.findall(r"Thread (\d+)", output)
-            if threads:
-                thread = random.choice(threads)
-                self.gdb.command("thread %s" % thread)
+            thread = random.choice(self.gdb.threads())
+            self.gdb.thread(thread)
+
+        for cmd in self.target.gdb_setup:
+            self.gdb.command(cmd)
 
         # FIXME: OpenOCD doesn't handle PRIV now
         #self.gdb.p("$priv=3")