import targets
import testlib
-from testlib import assertEqual, assertNotEqual, assertIn
+from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn
from testlib import assertGreater, assertRegexpMatches, assertLess
from testlib import GdbTest
self.gdb.p("i=0")
self.exit()
+class MulticoreTest(GdbTest):
+ compile_args = ("programs/infinite_loop.S", )
+
+ def setup(self):
+ self.gdb.load()
+ self.gdb.b("main")
+ self.gdb.b("main_end")
+ self.gdb.command("set non-stop on")
+ self.gdb.c()
+
+ def test(self):
+ threads = self.gdb.threads()
+ if len(threads) < 2:
+ return 'not_applicable'
+ # Run through the entire loop.
+ for t in threads:
+ self.gdb.thread(t)
+ self.gdb.p("$pc=_start")
+ # Run to main
+ for t in threads:
+ self.gdb.thread(t)
+ self.gdb.c()
+ for t in self.gdb.threads():
+ assertIn("main", t.frame)
+ # Run to end
+ for t in threads:
+ self.gdb.thread(t)
+ self.gdb.c()
+ hart_ids = []
+ for t in self.gdb.threads():
+ assertIn("main_end", t.frame)
+ # Check register values.
+ self.gdb.thread(t)
+ hart_id = self.gdb.p("$x1")
+ assertNotIn(hart_id, hart_ids)
+ hart_ids.append(hart_id)
+ for n in range(2, 32):
+ value = self.gdb.p("$x%d" % n)
+ assertEqual(value, hart_ids[-1] + n - 1)
+
+ # Confirmed that we read different register values for different harts.
+ # Write a new value to x1, and run through the add sequence again.
+
+ # This part isn't working right, because gdb doesn't resume Thread 2
+ # when asked. I don't know the root cause for that, but up to this
+ # point the test is still useful.
+
+# for t in threads:
+# self.gdb.thread(t)
+# self.gdb.p("$x1=0x%x" % (int(t.id) + 0x800))
+# self.gdb.p("$pc=main_post_csrr")
+# for t in threads:
+# self.gdb.thread(t)
+# self.gdb.c()
+# for t in self.gdb.threads():
+# assertIn("main_end", t.frame)
+# # Check register values.
+# self.gdb.thread(t)
+# for n in range(1, 32):
+# value = self.gdb.p("$x%d" % n)
+# assertEqual(value, int(t.id) + 0x800 + n - 1)
+
class StepTest(GdbTest):
compile_args = ("programs/step.S", )
+import collections
import os.path
import random
import re
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
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):
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)
"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)
# FIXME: OpenOCD doesn't handle PRIV now
#self.gdb.p("$priv=3")