summaryrefslogtreecommitdiff
path: root/tester
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2014-02-15 06:30:06 +1100
committerChris Johns <chrisj@rtems.org>2014-02-15 06:30:06 +1100
commit50fdf12244e784bd52732be1e68d966bc9629b24 (patch)
tree93b6656d397f3ef358b50aeaef6dc4d10a653f8c /tester
parent8f75c4a380cb0a4330f65966784ccdfeff756e70 (diff)
rt: Add the rtems-tester.
Diffstat (limited to 'tester')
-rw-r--r--tester/.gitignore4
-rw-r--r--tester/config/base.cfg35
-rw-r--r--tester/config/checks.cfg37
-rw-r--r--tester/rt/__init__.py30
-rw-r--r--tester/rt/config.py205
-rw-r--r--tester/rt/console.py143
-rw-r--r--tester/rt/gdb.py321
-rw-r--r--tester/rt/options.py118
-rw-r--r--tester/rt/pygdb/__init__.py21
-rwxr-xr-xtester/rt/pygdb/mi_parser.py423
-rw-r--r--tester/rt/pygdb/spark.py847
-rw-r--r--tester/rt/report.py185
-rw-r--r--tester/rt/stty.py567
-rw-r--r--tester/rt/test.py304
-rw-r--r--tester/rt/version.py48
-rwxr-xr-xtester/rtems-test42
-rw-r--r--tester/rtems/testing/bsps/mcf5235.mc63
-rw-r--r--tester/rtems/testing/bsps/realview_pbx_a9_qemu.mc53
-rw-r--r--tester/rtems/testing/bsps/sis-run.mc54
-rw-r--r--tester/rtems/testing/bsps/sis.mc56
-rw-r--r--tester/rtems/testing/bsps/xilinx_zynq_a9_qemu.mc54
-rw-r--r--tester/rtems/testing/bsps/xilinx_zynq_a9_qemu_smp.mc55
-rw-r--r--tester/rtems/testing/bsps/xilinx_zynq_zc706.mc65
-rw-r--r--tester/rtems/testing/console.cfg60
-rw-r--r--tester/rtems/testing/defaults.mc127
-rw-r--r--tester/rtems/testing/gdb.cfg60
-rw-r--r--tester/rtems/testing/qemu.cfg60
-rw-r--r--tester/rtems/testing/run.cfg70
-rw-r--r--tester/rtems/testing/testing.mc57
-rw-r--r--tester/rtems/version.cfg35
30 files changed, 4199 insertions, 0 deletions
diff --git a/tester/.gitignore b/tester/.gitignore
new file mode 100644
index 0000000..7e4a24c
--- /dev/null
+++ b/tester/.gitignore
@@ -0,0 +1,4 @@
+*~
+*.pyc
+*.log
+log_*
diff --git a/tester/config/base.cfg b/tester/config/base.cfg
new file mode 100644
index 0000000..bb058d2
--- /dev/null
+++ b/tester/config/base.cfg
@@ -0,0 +1,35 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Base settings for RTEMS testing support.
+#
+
+%define _target %{%{bsp_arch}-rtems%{version}
diff --git a/tester/config/checks.cfg b/tester/config/checks.cfg
new file mode 100644
index 0000000..b21d912
--- /dev/null
+++ b/tester/config/checks.cfg
@@ -0,0 +1,37 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Commdon checks for the RTEMS Tests.
+#
+
+%if %{_target} == %{nil}
+ %error No 'target' defined
+%endif
diff --git a/tester/rt/__init__.py b/tester/rt/__init__.py
new file mode 100644
index 0000000..c7eac97
--- /dev/null
+++ b/tester/rt/__init__.py
@@ -0,0 +1,30 @@
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+all = ['test']
diff --git a/tester/rt/config.py b/tester/rt/config.py
new file mode 100644
index 0000000..d426026
--- /dev/null
+++ b/tester/rt/config.py
@@ -0,0 +1,205 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# RTEMS Testing Config
+#
+
+import datetime
+import os
+import threading
+
+from rtemstoolkit import config
+from rtemstoolkit import error
+from rtemstoolkit import execute
+from rtemstoolkit import log
+from rtemstoolkit import path
+
+import console
+import gdb
+
+timeout = 15
+
+class file(config.file):
+ """RTEMS Testing configuration."""
+
+ _directives = ['%execute',
+ '%gdb',
+ '%console']
+
+ def __init__(self, report, name, opts, _directives = _directives):
+ super(file, self).__init__(name, opts, directives = _directives)
+ self.lock = threading.Lock()
+ self.realtime_trace = self.debug_trace('output')
+ self.process = None
+ self.console = None
+ self.output = None
+ self.report = report
+ self.load(name)
+
+ def __del__(self):
+ if self.console:
+ del self.console
+ super(file, self).__del__()
+
+ def _lock(self):
+ self.lock.acquire()
+
+ def _unlock(self):
+ self.lock.release()
+
+ def _timeout(self):
+ self.capture('*** TIMEOUT TIMEOUT')
+
+ def _dir_console(self, data):
+ if self.console is not None:
+ raise error.general(self._name_line_msg('console already configured'))
+ if len(data) == 0:
+ raise error.general(self._name_line_msg('no console configuration provided'))
+ console_trace = trace = self.debug_trace('console')
+ if data[0] == 'stdio':
+ self.console = console.stdio(trace = console_trace)
+ elif data[0] == 'tty':
+ if len(data) < 2 or len(data) >3:
+ raise error.general(self._name_line_msg('no tty configuration provided'))
+ if len(data) == 3:
+ settings = data[2]
+ else:
+ settings = None
+ self.console = console.tty(data[1],
+ output = self.capture,
+ setup = settings,
+ trace = console_trace)
+ else:
+ raise error.general(self._name_line_msg('invalid console type'))
+
+ def _dir_execute(self, data, total, index, exe, bsp_arch, bsp):
+ self.process = execute.execute(output = self.capture)
+ if not self.in_error:
+ if self.console:
+ self.console.open()
+ self.capture_console('run: %s' % (' '.join(data)))
+ ec, proc = self.process.open(data,
+ timeout = (int(self.expand('%{timeout}')),
+ self._timeout))
+ if ec > 0:
+ self._lock()
+ self._error('execute failed: %s: %s' % (' '.join(data), os.strerror(ec)))
+ self._unlock()
+ if self.console:
+ self.console.close()
+
+ def _dir_gdb(self, data, total, index, exe, bsp_arch, bsp):
+ if len(data) < 3 or len(data) > 4:
+ raise error.general('invalid %gdb arguments')
+ self.process = gdb.gdb(bsp_arch, bsp,
+ trace = self.debug_trace('gdb'),
+ mi_trace = self.debug_trace('gdb-mi'))
+ script = self.expand('%%{%s}' % data[2])
+ if script:
+ script = [l.strip() for l in script.splitlines()]
+ if not self.in_error:
+ if self.console:
+ self.console.open()
+ self.process.open(data[0], data[1],
+ script = script,
+ output = self.capture,
+ gdb_console = self.capture_console,
+ timeout = int(self.expand('%{timeout}')))
+ if self.console:
+ self.console.close()
+
+ def _directive_filter(self, results, directive, info, data):
+ if results[0] == 'directive':
+ _directive = results[1]
+ _data = results[2]
+ ds = []
+ if len(_data):
+ ds = [_data[0]]
+ if len(_data) > 1:
+ ds += _data[1].split()
+ ds = self.expand(ds)
+
+ if _directive == '%console':
+ self._dir_console(ds)
+ else:
+ self._lock()
+ try:
+ total = int(self.expand('%{test_total}'))
+ index = int(self.expand('%{test_index}'))
+ exe = self.expand('%{test_executable}')
+ bsp_arch = self.expand('%{bsp_arch}')
+ bsp = self.expand('%{bsp}')
+ self.report.start(index, total, exe, exe, bsp_arch, bsp)
+ self.output = []
+ finally:
+ self._unlock()
+ if _directive == '%execute':
+ self._dir_execute(ds, total, index, exe, bsp_arch, bsp)
+ elif _directive == '%gdb':
+ self._dir_gdb(ds, total, index, exe, bsp_arch, bsp)
+ else:
+ raise error.general(self._name_line_msg('invalid directive'))
+ self._lock()
+ try:
+ self.report.end(exe, self.output)
+ self.process = None
+ self.output = None
+ finally:
+ self._unlock()
+ return None, None, None
+
+ def _realtime_trace(self, text):
+ if self.realtime_trace:
+ for l in text:
+ print ' '.join(l)
+
+ def capture(self, text):
+ text = [(']', l) for l in text.replace(chr(13), '').splitlines()]
+ self._lock()
+ if self.output is not None:
+ self._realtime_trace(text)
+ self.output += text
+ self._unlock()
+
+ def capture_console(self, text):
+ text = [('>', l) for l in text.replace(chr(13), '').splitlines()]
+ self._lock()
+ if self.output is not None:
+ self._realtime_trace(text)
+ self.output += text
+ self._unlock()
+
+ def debug_trace(self, flag):
+ dt = self.macros['debug_trace']
+ if dt:
+ if flag in dt.split(','):
+ return True
+ return False
diff --git a/tester/rt/console.py b/tester/rt/console.py
new file mode 100644
index 0000000..74ec3bf
--- /dev/null
+++ b/tester/rt/console.py
@@ -0,0 +1,143 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# RTEMS Testing Consoles
+#
+
+import errno
+import fcntl
+import os
+import threading
+import time
+
+import stty
+
+def save():
+ return stty.save()
+
+def restore(attributes):
+ stty.restore(attributes)
+
+class console(object):
+ '''RTEMS Testing console base.'''
+
+ def __init__(self, name, trace):
+ self.name = name
+ self.trace = trace
+
+ def __del__(self):
+ pass
+
+ def _tracing(self):
+ return self.trace
+
+ def open(self):
+ pass
+
+ def close(self):
+ pass
+
+class stdio(console):
+ '''STDIO console.'''
+
+ def __init__(self, trace = False):
+ super(stdio, self).__init__('stdio', trace)
+
+class tty(console):
+ '''TTY console connects to serial ports.'''
+
+ raw = 'B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS'
+
+ def __init__(self, dev, output, setup = None, trace = False):
+ self.tty = None
+ self.read_thread = None
+ self.dev = dev
+ self.output = output
+ if setup is None:
+ self.setup = raw
+ else:
+ self.setup = setup
+ super(tty, self).__init__(dev, trace)
+
+ def __del__(self):
+ super(tty, self).__del__()
+ if self._tracing():
+ print ':: tty close', self.dev
+ fcntl.fcntl(me.tty.fd, fcntl.F_SETFL,
+ fcntl.fcntl(me.tty.fd, fcntl.F_GETFL) & ~os.O_NONBLOCK)
+ self.close()
+
+ def open(self):
+ def _readthread(me, x):
+ if self._tracing():
+ print ':: tty runner started', self.dev
+ fcntl.fcntl(me.tty.fd, fcntl.F_SETFL,
+ fcntl.fcntl(me.tty.fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+ line = ''
+ while me.running:
+ time.sleep(0.05)
+ try:
+ data = me.tty.fd.read()
+ except IOError, ioe:
+ if ioe.errno == errno.EAGAIN:
+ continue
+ raise
+ except:
+ raise
+ for c in data:
+ if len(c) == 0:
+ continue
+ if c != chr(0):
+ line += c
+ if c == '\n':
+ me.output(line)
+ line = ''
+ if self._tracing():
+ print ':: tty runner finished', self.dev
+ if self._tracing():
+ print ':: tty open', self.dev
+ self.tty = stty.tty(self.dev)
+ self.tty.set(self.setup)
+ self.tty.on()
+ self.read_thread = threading.Thread(target = _readthread,
+ name = 'tty[%s]' % (self.dev),
+ args = (self, 0))
+ self.read_thread.daemon = True
+ self.running = True
+ self.read_thread.start()
+
+ def close(self):
+ if self.tty:
+ time.sleep(1)
+ if self.read_thread:
+ self.running = False
+ self.read_thread.join(1)
+ self.tty = None
diff --git a/tester/rt/gdb.py b/tester/rt/gdb.py
new file mode 100644
index 0000000..4449222
--- /dev/null
+++ b/tester/rt/gdb.py
@@ -0,0 +1,321 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# RTEMS Testing GDB Interface
+#
+
+import os
+import Queue
+import sys
+import termios
+import threading
+
+from rtemstoolkit import error
+from rtemstoolkit import execute
+from rtemstoolkit import options
+from rtemstoolkit import path
+
+import console
+import pygdb
+
+#
+# The MI parser needs a global lock. It has global objects.
+#
+mi_lock = threading.Lock()
+
+class gdb(object):
+ '''RTEMS Testing GDB base.'''
+
+ def __init__(self, bsp_arch, bsp, trace = False, mi_trace = False):
+ self.trace = trace
+ self.mi_trace = mi_trace
+ self.lock_trace = False
+ self.lock = threading.RLock()
+ self.script = None
+ self.script_line = 0
+ self.bsp = bsp
+ self.bsp_arch = bsp_arch
+ self.output = None
+ self.gdb_console = None
+ self.input = Queue.Queue()
+ self.commands = Queue.Queue()
+ self.process = None
+ self.state = {}
+ self.running = False
+ self.breakpoints = {}
+ self.output = None
+ self.output_buffer = ''
+ self.lc = 0
+
+ def _lock(self, msg):
+ if self.lock_trace:
+ print '|[ LOCK:%s ]|' % (msg)
+ self.lock.acquire()
+
+ def _unlock(self, msg):
+ if self.lock_trace:
+ print '|] UNLOCK:%s [|' % (msg)
+ self.lock.release()
+
+ def _mi_lock(self):
+ mi_lock.acquire()
+
+ def _mi_unlock(self):
+ mi_lock.release()
+
+ def _put(self, text):
+ if self.trace:
+ print ')))', text
+ self.commands.put(text)
+
+ def _input_commands(self):
+ if self.commands.empty():
+ return False
+ try:
+ if self.trace:
+ print '... input empty ', self.input.empty()
+ if self.input.empty():
+ line = self.commands.get(block = False)
+ if self.trace:
+ print '+++', line
+ self.input.put(line)
+ except:
+ pass
+ return True
+
+ def _reader(self, line):
+ self._lock('_reader')
+ if self.trace:
+ print '<<<', line
+ try:
+ self.lc += 1
+ if line.startswith('(gdb)'):
+ if self.trace:
+ print '^^^ (gdb)'
+ if not self._input_commands():
+ self.gdb_expect()
+ self._input_commands()
+ else:
+ self.gdb_parse(line)
+ finally:
+ self._unlock('_reader')
+
+ def _writer(self):
+ try:
+ try:
+ self._lock('_open')
+ try:
+ if self.process is None:
+ return None
+ finally:
+ self._unlock('_open')
+ line = self.input.get(timeout = 0.5)
+ if self.trace:
+ print '>>> input: queue=%d' % (self.input.qsize()), line
+ except Queue.Empty:
+ return True
+ if line is None:
+ return None
+ return line + os.linesep
+ except:
+ if self.trace:
+ print 'writer exception'
+ pass
+ if self.trace:
+ print 'writer closing'
+ return False
+
+ def _timeout(self):
+ self._lock('_timeout')
+ try:
+ if self.output:
+ self.output('*** TIMEOUT TIMEOUT')
+ self._gdb_quit(backtrace = True)
+ finally:
+ self._unlock('_timeout')
+
+ def _cleanup(self, proc):
+ self._lock('_cleanup')
+ try:
+ self._put(None)
+ finally:
+ self._unlock('_cleanup')
+
+ def _gdb_quit(self, backtrace = False):
+ self._lock('_gdb_quit')
+ try:
+ self._put('-exec-interrupt')
+ if backtrace:
+ self._put('bt')
+ self._put('quit')
+ self._put('None')
+ if self.script:
+ self.script_line = len(self.script)
+ finally:
+ self._unlock('_gdb_quit')
+
+ def open(self, command, executable,
+ output, gdb_console, script = None, tty = None,
+ timeout = 300):
+ self._lock('_open')
+ try:
+ cmds = execute.arg_list(command) + ['-i=mi',
+ '--nx',
+ '--quiet']
+ if tty:
+ cmds += ['--tty=%s' % tty]
+ if executable:
+ cmds += [executable]
+ self.output = output
+ self.gdb_console = gdb_console
+ self.script = script
+ self.running = False
+ self.process = execute.execute(output = self._reader,
+ input = self._writer,
+ cleanup = self._cleanup)
+ finally:
+ self._unlock('_open')
+ try:
+ self.gdb_console('gdb: %s' % (' '.join(cmds)))
+ ec, proc = self.process.open(cmds, timeout = (timeout, self._timeout))
+ if self.trace:
+ print 'gdb done', ec
+ if ec > 0:
+ raise error.general('gdb exec: %s' % (os.strerror(ec)))
+ except:
+ raise
+ self._lock('_open')
+ try:
+ self.process = None
+ finally:
+ self._unlock('_open')
+
+ def gdb_expect(self):
+ if self.trace:
+ print '}}} gdb-expect'
+ if self.process and not self.running and self.script is not None:
+ if self.script_line == len(self.script):
+ self._put(None)
+ else:
+ if self.script_line == 0:
+ self._put('-gdb-set confirm no')
+ self._put('-data-list-register-names')
+ line = self.script[self.script_line]
+ self.script_line += 1
+ self._put(line)
+ else:
+ self._put(line)
+
+ def gdb_parse(self, lines):
+ try:
+ self._mi_lock()
+ try:
+ if self.mi_trace:
+ print 'mi-data:', lines
+ rec = pygdb.mi_parser.process(lines)
+ finally:
+ self._mi_unlock()
+ if self.mi_trace:
+ print 'mi-rec:', rec
+ if rec.record_type == 'result':
+ if rec.type == 'result':
+ if rec.class_ == 'error':
+ self._gdb_quit()
+ elif 'register_names' in dir(rec.result):
+ self.register_names = rec.result.register_names
+ elif 'register_values' in dir(rec.result):
+ self.register_values = rec.result.register_values
+ elif rec.type == 'exec':
+ if rec.class_ == 'running':
+ if self.trace:
+ print '*** running'
+ self._put('')
+ self.running = True
+ elif rec.class_ == 'stopped':
+ if self.trace:
+ print '*** stopped'
+ self.running = False
+ #self._put('-data-list-register-values')
+ elif rec.type == 'breakpoint':
+ if rec.class_ == 'breakpoint-created':
+ self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
+ elif rec.class_ == 'breakpoint-modified':
+ self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
+ elif rec.class_ == 'breakpoint-deleted':
+ if rec.result.id in self.breakpoints:
+ del self.breakpoints[rec.result.id]
+ elif rec.record_type == 'error':
+ self._gdb_quit()
+ elif rec.record_type == 'stream':
+ if rec.type == 'console' or rec.type == 'log':
+ for line in rec.value.splitlines():
+ self.gdb_console(line)
+ if rec.type == 'target':
+ self.output_buffer += rec.value
+ last_lf = self.output_buffer.rfind('\n')
+ if last_lf >= 0:
+ lines = self.output_buffer[:last_lf]
+ if self.trace:
+ print '/// console output'
+ for line in lines.splitlines():
+ self.output(line)
+ self.output_buffer = self.output_buffer[last_lf + 1:]
+ except:
+ if self.trace:
+ print '/// console output'
+ for line in lines.splitlines():
+ self.output(line)
+
+if __name__ == "__main__":
+ stdtty = console.save()
+ try:
+ def output(text):
+ print ']', text
+ def gdb_console(text):
+ print '>', text
+ script = ['target sim']
+ if len(sys.argv) > 1:
+ executable = sys.argv[1]
+ script += ['load',
+ 'run',
+ 'info reg',
+ '-stack-list-frames',
+ '-stack-list-arguments --all-values']
+ else:
+ executable = None
+ script += ['quit']
+ g = gdb('sparc', 'sis', mi_trace = True)
+ g.open('sparc-rtems4.11-gdb', executable, output, gdb_console, script)
+ except:
+ console.restore(stdtty)
+ raise
+ finally:
+ console.restore(stdtty)
diff --git a/tester/rt/options.py b/tester/rt/options.py
new file mode 100644
index 0000000..f637017
--- /dev/null
+++ b/tester/rt/options.py
@@ -0,0 +1,118 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Determine the defaults and load the specific file.
+#
+
+import glob
+import pprint
+import re
+import os
+import string
+
+from rtemstoolkit import error
+from rtemstoolkit import execute
+from rtemstoolkit import git
+from rtemstoolkit import log
+from rtemstoolkit import macros
+from rtemstoolkit import options
+from rtemstoolkit import path
+
+import version
+
+class command_line(options.command_line):
+ """Process the command line in a common way for all Tool Builder commands."""
+
+ def __init__(self, argv = None, optargs = None, defaults = None, command_path = None):
+ if argv is None:
+ return
+ long_opts = {
+ # key macro handler param defs init
+ '--target' : ('_target', "triplet", True, None, False),
+ '--timeout' : ('timeout', "int", True, None, False),
+ }
+ long_opts_help = {
+ '--target': 'Set the target triplet',
+ '--timeout': 'Set the test timeout in seconds (default 180 seconds)'
+ }
+ super(command_line, self).__init__('rt', argv, optargs, defaults,
+ long_opts, long_opts_help, command_path);
+
+ def __copy__(self):
+ return super(command_line, self).__copy__()
+
+def load(args, optargs = None,
+ command_path = None,
+ defaults = '%{_rtdir}/rtems/testing/defaults.mc'):
+ #
+ # The path to this command if not supplied by the upper layers.
+ #
+ if command_path is None:
+ command_path = path.dirname(args[0])
+ if len(command_path) == 0:
+ command_path = '.'
+ #
+ # The command line contains the base defaults object all build objects copy
+ # and modify by loading a configuration.
+ #
+ opts = command_line(args,
+ optargs,
+ macros.macros(name = defaults,
+ rtdir = command_path),
+ command_path)
+ options.load(opts)
+ return opts
+
+def run(args):
+ try:
+ _opts = load(args = args, defaults = 'rtems/testing/defaults.mc')
+ log.notice('RTEMS Test - Defaults, v%s' % (version.str()))
+ _opts.log_info()
+ log.notice('Options:')
+ log.notice(str(_opts))
+ log.notice('Defaults:')
+ log.notice(str(_opts.defaults))
+ except error.general, gerr:
+ print gerr
+ sys.exit(1)
+ except error.internal, ierr:
+ print ierr
+ sys.exit(1)
+ except error.exit, eerr:
+ pass
+ except KeyboardInterrupt:
+ log.notice('abort: user terminated')
+ sys.exit(1)
+ sys.exit(0)
+
+if __name__ == '__main__':
+ import sys
+ run(sys.argv)
diff --git a/tester/rt/pygdb/__init__.py b/tester/rt/pygdb/__init__.py
new file mode 100644
index 0000000..b52f6f9
--- /dev/null
+++ b/tester/rt/pygdb/__init__.py
@@ -0,0 +1,21 @@
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+all = ['mi_parser']
+from mi_parser import scan
+from mi_parser import process
diff --git a/tester/rt/pygdb/mi_parser.py b/tester/rt/pygdb/mi_parser.py
new file mode 100755
index 0000000..65ea5e0
--- /dev/null
+++ b/tester/rt/pygdb/mi_parser.py
@@ -0,0 +1,423 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2008 Michael Eddington
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+# Authors:
+# Frank Laub (frank.laub@gmail.com)
+# Michael Eddington (mike@phed.org)
+
+# $Id$
+
+
+import re
+import pprint
+import spark
+
+def __private():
+ class Token:
+ def __init__(self, type, value=None):
+ self.type = type
+ self.value = value
+ def __cmp__(self, o):
+ return cmp(self.type, o)
+ def __repr__(self):
+ return self.value or self.type
+
+ class AST:
+ def __init__(self, type):
+ self.type = type
+ self._kids = []
+ def __getitem__(self, i):
+ return self._kids[i]
+ def __len__(self):
+ return len(self._kids)
+ def __setslice__(self, low, high, seq):
+ self._kids[low:high] = seq
+ def __cmp__(self, o):
+ return cmp(self.type, o)
+
+ class GdbMiScannerBase(spark.GenericScanner):
+ def tokenize(self, input):
+ self.rv = []
+ spark.GenericScanner.tokenize(self, input)
+ return self.rv
+
+ def t_nl(self, s):
+ r'\n|\r\n'
+ self.rv.append(Token('nl'))
+
+ def t_whitespace(self, s):
+ r'[ \t\f\v]+'
+ pass
+
+ def t_symbol(self, s):
+ r',|\{|\}|\[|\]|\='
+ self.rv.append(Token(s, s))
+
+ def t_result_type(self, s):
+ r'\*|\+|\^'
+ self.rv.append(Token('result_type', s))
+
+ def t_stream_type(self, s):
+ r'\@|\&|\~'
+ self.rv.append(Token('stream_type', s))
+
+ def t_string(self, s):
+ r'[\w-]+'
+ self.rv.append(Token('string', s))
+
+ def t_c_string(self, s):
+ r'\".*?(?<![\\\\])\"'
+ inner = self.__unescape(s[1:len(s)-1])
+ self.rv.append(Token('c_string', inner))
+
+ def t_default(self, s):
+ r'( . | \n )+'
+ raise Exception, "Specification error: unmatched input for '%s'" % s
+
+ def __unescape(self, s):
+ s = re.sub(r'\\r', r'\r', s)
+ s = re.sub(r'\\n', r'\n', s)
+ s = re.sub(r'\\t', r'\t', s)
+ return re.sub(r'\\(.)', r'\1', s)
+
+
+ class GdbMiScanner(GdbMiScannerBase):
+ def t_token(self, s):
+ r'\d+'
+ self.rv.append(Token('token', s))
+
+ class GdbMiParser(spark.GenericASTBuilder):
+ def __init__(self):
+ spark.GenericASTBuilder.__init__(self, AST, 'output')
+
+ def p_output(self, args):
+ '''
+ output ::= record_list
+ record_list ::= generic_record
+ record_list ::= generic_record record_list
+ generic_record ::= result_record
+ generic_record ::= stream_record
+ result_record ::= result_header result_list nl
+ result_record ::= result_header nl
+ result_header ::= token result_type class
+ result_header ::= result_type class
+ result_header ::= token = class
+ result_header ::= = class
+ stream_record ::= stream_type c_string nl
+ result_list ::= , result result_list
+ result_list ::= , result
+ result_list ::= , tuple
+ result ::= variable = value
+ class ::= string
+ variable ::= string
+ value ::= const
+ value ::= tuple
+ value ::= list
+ value_list ::= , value
+ value_list ::= , value value_list
+ const ::= c_string
+ tuple ::= { }
+ tuple ::= { result }
+ tuple ::= { result result_list }
+ list ::= [ ]
+ list ::= [ value ]
+ list ::= [ value value_list ]
+ list ::= [ result ]
+ list ::= [ result result_list ]
+ list ::= { value }
+ list ::= { value value_list }
+ '''
+ pass
+
+ def terminal(self, token):
+ # Homogeneous AST.
+ rv = AST(token.type)
+ rv.value = token.value
+ return rv
+
+ def nonterminal(self, type, args):
+ # Flatten AST a bit by not making nodes if there's only one child.
+ exclude = [
+ 'record_list'
+ ]
+ if len(args) == 1 and type not in exclude:
+ return args[0]
+ return spark.GenericASTBuilder.nonterminal(self, type, args)
+
+ def error(self, token, i=0, tokens=None):
+ if i > 2:
+ print '%s %s %s %s' % (tokens[i-3], tokens[i-2], tokens[i-1], tokens[i])
+ raise Exception, "Syntax error at or near %d:'%s' token" % (i, token)
+
+ class GdbMiInterpreter(spark.GenericASTTraversal):
+ def __init__(self, ast):
+ spark.GenericASTTraversal.__init__(self, ast)
+ self.postorder()
+
+ def __translate_type(self, type):
+ table = {
+ '^': 'result',
+ '=': 'notify',
+ '+': 'status',
+ '*': 'exec',
+ '~': 'console',
+ '@': 'target',
+ '&': 'log'
+ }
+ return table[type]
+
+ def n_result(self, node):
+ # result ::= variable = value
+ node.value = { node[0].value: node[2].value }
+ #print 'result: %s' % node.value
+
+ def n_tuple(self, node):
+ if len(node) == 2:
+ # tuple ::= {}
+ node.value = {}
+ elif len(node) == 3:
+ # tuple ::= { result }
+ node.value = node[1].value
+ elif len(node) == 4:
+ # tuple ::= { result result_list }
+ node.value = node[1].value
+ for result in node[2].value:
+ for n, v in result.items():
+ if node.value.has_key(n):
+ #print '**********list conversion: [%s] %s -> %s' % (n, node.value[n], v)
+ old = node.value[n]
+ if not isinstance(old, list):
+ node.value[n] = [ node.value[n] ]
+ node.value[n].append(v)
+ else:
+ node.value[n] = v
+ else:
+ raise Exception, 'Invalid tuple'
+ #print 'tuple: %s' % node.value
+
+ def n_list(self, node):
+ if len(node) == 2:
+ # list ::= []
+ node.value = []
+ elif len(node) == 3:
+ # list ::= [ value ]
+ node.value = [ node[1].value ]
+ elif len(node) == 4:
+ # list ::= [ value value_list ]
+ node.value = [ node[1].value ] + node[2].value
+ #list ::= [ result ]
+ #list ::= [ result result_list ]
+ #list ::= { value }
+ #list ::= { value value_list }
+ #print 'list %s' % node.value
+
+ def n_value_list(self, node):
+ if len(node) == 2:
+ #value_list ::= , value
+ node.value = [ node[1].value ]
+ elif len(node) == 3:
+ #value_list ::= , value value_list
+ node.value = [ node[1].value ] + node[2].value
+
+ def n_result_list(self, node):
+ if len(node) == 2:
+ # result_list ::= , result
+ node.value = [ node[1].value ]
+ else:
+ # result_list ::= , result result_list
+ node.value = [ node[1].value ] + node[2].value
+ #print 'result_list: %s' % node.value
+
+ def n_result_record(self, node):
+ node.value = node[0].value
+ if len(node) == 3:
+ # result_record ::= result_header result_list nl
+ node.value['results'] = node[1].value
+ elif len(node) == 2:
+ # result_record ::= result_header nl
+ pass
+ #print 'result_record: %s' % (node.value)
+
+ def n_result_header(self, node):
+ if len(node) == 3:
+ # result_header ::= token result_type class
+ node.value = {
+ 'token': node[0].value,
+ 'type': self.__translate_type(node[1].value),
+ 'class_': node[2].value,
+ 'record_type': 'result'
+ }
+ elif len(node) == 2:
+ # result_header ::= result_type class
+ node.value = {
+ 'token': None,
+ 'type': self.__translate_type(node[0].value),
+ 'class_': node[1].value,
+ 'record_type': 'result'
+ }
+
+ def n_stream_record(self, node):
+ # stream_record ::= stream_type c_string nl
+ node.value = {
+ 'type': self.__translate_type(node[0].value),
+ 'value': node[1].value,
+ 'record_type': 'stream'
+ }
+ #print 'stream_record: %s' % node.value
+
+ def n_record_list(self, node):
+ if len(node) == 1:
+ # record_list ::= generic_record
+ node.value = [ node[0].value ]
+ elif len(node) == 2:
+ # record_list ::= generic_record record_list
+ node.value = [ node[0].value ] + node[1].value
+ #print 'record_list: %s' % node.value
+
+ #def default(self, node):
+ #print 'default: ' + node.type
+
+ class GdbDynamicObject:
+ def __init__(self, dict_):
+ self.graft(dict_)
+
+ def __repr__(self):
+ return pprint.pformat(self.__dict__)
+
+ def __nonzero__(self):
+ return len(self.__dict__) > 0
+
+ def __getitem__(self, i):
+ if i == 0 and len(self.__dict__) > 0:
+ return self
+ else:
+ raise IndexError
+
+ def __getattr__(self, name):
+ if name.startswith('__'):
+ raise AttributeError
+ return None
+
+ def graft(self, dict_):
+ for name, value in dict_.items():
+ name = name.replace('-', '_')
+ if isinstance(value, dict):
+ value = GdbDynamicObject(value)
+ elif isinstance(value, list):
+ x = value
+ value = []
+ for item in x:
+ if isinstance(item, dict):
+ item = GdbDynamicObject(item)
+ value.append(item)
+ setattr(self, name, value)
+
+ class GdbMiRecord:
+ def __init__(self, record):
+ self.result = None
+ for name, value in record[0].items():
+ name = name.replace('-', '_')
+ if name == 'results':
+ for result in value:
+ if not self.result:
+ self.result = GdbDynamicObject(result)
+ else:
+ # graft this result to self.results
+ self.result.graft(result)
+ else:
+ setattr(self, name, value)
+
+ def __repr__(self):
+ return pprint.pformat(self.__dict__)
+
+ return (GdbMiScanner(), GdbMiParser(), GdbMiInterpreter, GdbMiRecord)
+
+(__the_scanner, __the_parser, __the_interpreter, __the_output) = __private()
+
+def scan(input):
+ return __the_scanner.tokenize(input)
+
+def parse(tokens):
+ return __the_parser.parse(tokens)
+
+def process(input):
+ tokens = scan(input)
+ ast = parse(tokens)
+ __the_interpreter(ast)
+ return __the_output(ast.value)
+
+if __name__ == '__main__':
+ def main():
+ def print_tokens(tokens):
+ print
+ for token in tokens:
+ if token.value:
+ print token.type + ': ' + token.value
+ else:
+ print token.type
+
+ def run_test(test):
+ lines = test.splitlines()
+ for line in lines:
+ tokens = scan(line + '\n')
+ #print_tokens(tokens)
+
+ ast = parse(tokens)
+ __the_interpreter(ast)
+ output = __the_output(ast.value)
+ print output
+
+ x = '"No symbol table is loaded. Use the \\"file\\" command."'
+ m = re.match('\".*?(?<![\\\\])\"', x)
+ z = x[m.start():m.end()]
+
+ test1 = '22^done,time={wallclock="0.05395",user="0.02996",system="0.02222",start="1210321030.972724",end="1210321031.026675"}\n'
+ test2 = '''~"[Switching to process 3832 local thread 0x3607]\\n"
+=shlibs-updated
+^running
+'''
+
+ test3 = '''=shlibs-added,shlib-info={num="2",name="qi",kind="-",dyld-addr="0x1000",reason="exec",requested-state="Y",state="Y",path="/Users/franklaub/bin/qi",description="/Users/franklaub/bin/qi",loaded_addr="",slide="0x0",prefix="",dsym-objpath="/Users/franklaub/bin/qi.dSYM/Contents/Resources/DWARF/qi"},time={now="1210290757.432413"}
+=shlibs-added,shlib-info={num="3",name="libgcc_s.1.dylib",kind="-",dyld-addr="0x9230a000",reason="dyld",requested-state="Y",state="Y",path="/usr/lib/libgcc_s.1.dylib",description="/usr/lib/libgcc_s.1.dylib",loaded_addr="0x9230a000",slide="-0x6dcf6000",prefix=""},time={now="1210290757.432771"}
+=shlibs-added,shlib-info={num="4",name="libSystem.B.dylib",kind="-",dyld-addr="0x950aa000",reason="dyld",requested-state="Y",state="Y",path="/usr/lib/libSystem.B.dylib",description="/usr/lib/libSystem.B.dylib",loaded_addr="0x950aa000",slide="-0x6af56000",prefix="",commpage-objpath="/usr/lib/libSystem.B.dylib[LC_SEGMENT.__DATA.__commpage]"},time={now="1210290757.433091"}
+=shlibs-added,shlib-info={num="5",name="libmathCommon.A.dylib",kind="-",dyld-addr="0x95018000",reason="dyld",requested-state="Y",state="Y",path="/usr/lib/system/libmathCommon.A.dylib",description="/usr/lib/system/libmathCommon.A.dylib",loaded_addr="0x95018000",slide="-0x6afe8000",prefix=""},time={now="1210290757.433390"}
+*stopped,time={wallclock="1.02740",user="0.00379",system="0.00791",start="1210290756.408774",end="1210290757.436179"},reason="breakpoint-hit",commands="no",times="1",bkptno="1",thread-id="1"
+'''
+
+ test4 = '''=shlibs-added,shlib-info={num="2",name="qi",kind="-",dyld-addr="0x1000",reason="exec",requested-state="Y",state="Y",path="/Users/franklaub/bin/qi",description="/Users/franklaub/bin/qi",loaded_addr="",slide="0x0",prefix="",dsym-objpath="/Users/franklaub/bin/qi.dSYM/Contents/Resources/DWARF/qi"},time={now="1210290757.432413"}
+^running
+'''
+ test5 = '''=class,variable={frame={x="2"},frame={x="2"}, regs={"1","2","3"}}
+^running
+'''
+ test6 = '10^done,stack-args={frame={level="0",args={}}},time={wallclock="0.00006",user="0.00004",system="0.00002",start="1210530442.460765",end="1210530442.460825"}\n'
+
+ run_test(test1)
+ run_test(test2)
+ run_test(test3)
+ run_test(test4)
+ run_test(test5)
+ run_test(test6)
+
+ main()
diff --git a/tester/rt/pygdb/spark.py b/tester/rt/pygdb/spark.py
new file mode 100644
index 0000000..aab2d19
--- /dev/null
+++ b/tester/rt/pygdb/spark.py
@@ -0,0 +1,847 @@
+# Copyright (c) 1998-2002 John Aycock
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+__version__ = 'SPARK-0.7 (pre-alpha-7)'
+
+import re
+import sys
+import string
+
+def _namelist(instance):
+ namelist, namedict, classlist = [], {}, [instance.__class__]
+ for c in classlist:
+ for b in c.__bases__:
+ classlist.append(b)
+ for name in c.__dict__.keys():
+ if not namedict.has_key(name):
+ namelist.append(name)
+ namedict[name] = 1
+ return namelist
+
+class GenericScanner:
+ def __init__(self, flags=0):
+ pattern = self.reflect()
+ self.re = re.compile(pattern, re.VERBOSE|flags)
+
+ self.index2func = {}
+ for name, number in self.re.groupindex.items():
+ self.index2func[number-1] = getattr(self, 't_' + name)
+
+ def makeRE(self, name):
+ doc = getattr(self, name).__doc__
+ rv = '(?P<%s>%s)' % (name[2:], doc)
+ return rv
+
+ def reflect(self):
+ rv = []
+ for name in _namelist(self):
+ if name[:2] == 't_' and name != 't_default':
+ rv.append(self.makeRE(name))
+
+ rv.append(self.makeRE('t_default'))
+ return string.join(rv, '|')
+
+ def error(self, s, pos):
+ print "Lexical error at position %s" % pos
+ raise SystemExit
+
+ def position(self, newpos=None):
+ oldpos = self.pos
+ if newpos is not None:
+ self.pos = newpos
+ return self.string, oldpos
+
+ def tokenize(self, s):
+ self.string = s
+ self.pos = 0
+ n = len(s)
+ while self.pos < n:
+ m = self.re.match(s, self.pos)
+ if m is None:
+ self.error(s, self.pos)
+
+ groups = m.groups()
+ self.pos = m.end()
+ for i in range(len(groups)):
+ if groups[i] is not None and self.index2func.has_key(i):
+ self.index2func[i](groups[i])
+
+ def t_default(self, s):
+ r'( . | \n )+'
+ print "Specification error: unmatched input"
+ raise SystemExit
+
+#
+# Extracted from GenericParser and made global so that [un]picking works.
+#
+class _State:
+ def __init__(self, stateno, items):
+ self.T, self.complete, self.items = [], [], items
+ self.stateno = stateno
+
+class GenericParser:
+ #
+ # An Earley parser, as per J. Earley, "An Efficient Context-Free
+ # Parsing Algorithm", CACM 13(2), pp. 94-102. Also J. C. Earley,
+ # "An Efficient Context-Free Parsing Algorithm", Ph.D. thesis,
+ # Carnegie-Mellon University, August 1968. New formulation of
+ # the parser according to J. Aycock, "Practical Earley Parsing
+ # and the SPARK Toolkit", Ph.D. thesis, University of Victoria,
+ # 2001, and J. Aycock and R. N. Horspool, "Practical Earley
+ # Parsing", unpublished paper, 2001.
+ #
+
+ def __init__(self, start):
+ self.rules = {}
+ self.rule2func = {}
+ self.rule2name = {}
+ self.collectRules()
+ self.augment(start)
+ self.ruleschanged = 1
+
+ _NULLABLE = '\e_'
+ _START = 'START'
+ _BOF = '|-'
+
+ #
+ # When pickling, take the time to generate the full state machine;
+ # some information is then extraneous, too. Unfortunately we
+ # can't save the rule2func map.
+ #
+ def __getstate__(self):
+ if self.ruleschanged:
+ #
+ # XXX - duplicated from parse()
+ #
+ self.computeNull()
+ self.newrules = {}
+ self.new2old = {}
+ self.makeNewRules()
+ self.ruleschanged = 0
+ self.edges, self.cores = {}, {}
+ self.states = { 0: self.makeState0() }
+ self.makeState(0, self._BOF)
+ #
+ # XXX - should find a better way to do this..
+ #
+ changes = 1
+ while changes:
+ changes = 0
+ for k, v in self.edges.items():
+ if v is None:
+ state, sym = k
+ if self.states.has_key(state):
+ self.goto(state, sym)
+ changes = 1
+ rv = self.__dict__.copy()
+ for s in self.states.values():
+ del s.items
+ del rv['rule2func']
+ del rv['nullable']
+ del rv['cores']
+ return rv
+
+ def __setstate__(self, D):
+ self.rules = {}
+ self.rule2func = {}
+ self.rule2name = {}
+ self.collectRules()
+ start = D['rules'][self._START][0][1][1] # Blech.
+ self.augment(start)
+ D['rule2func'] = self.rule2func
+ D['makeSet'] = self.makeSet_fast
+ self.__dict__ = D
+
+ #
+ # A hook for GenericASTBuilder and GenericASTMatcher. Mess
+ # thee not with this; nor shall thee toucheth the _preprocess
+ # argument to addRule.
+ #
+ def preprocess(self, rule, func): return rule, func
+
+ def addRule(self, doc, func, _preprocess=1):
+ fn = func
+ rules = string.split(doc)
+
+ index = []
+ for i in range(len(rules)):
+ if rules[i] == '::=':
+ index.append(i-1)
+ index.append(len(rules))
+
+ for i in range(len(index)-1):
+ lhs = rules[index[i]]
+ rhs = rules[index[i]+2:index[i+1]]
+ rule = (lhs, tuple(rhs))
+
+ if _preprocess:
+ rule, fn = self.preprocess(rule, func)
+
+ if self.rules.has_key(lhs):
+ self.rules[lhs].append(rule)
+ else:
+ self.rules[lhs] = [ rule ]
+ self.rule2func[rule] = fn
+ self.rule2name[rule] = func.__name__[2:]
+ self.ruleschanged = 1
+
+ def collectRules(self):
+ for name in _namelist(self):
+ if name[:2] == 'p_':
+ func = getattr(self, name)
+ doc = func.__doc__
+ self.addRule(doc, func)
+
+ def augment(self, start):
+ rule = '%s ::= %s %s' % (self._START, self._BOF, start)
+ self.addRule(rule, lambda args: args[1], 0)
+
+ def computeNull(self):
+ self.nullable = {}
+ tbd = []
+
+ for rulelist in self.rules.values():
+ lhs = rulelist[0][0]
+ self.nullable[lhs] = 0
+ for rule in rulelist:
+ rhs = rule[1]
+ if len(rhs) == 0:
+ self.nullable[lhs] = 1
+ continue
+ #
+ # We only need to consider rules which
+ # consist entirely of nonterminal symbols.
+ # This should be a savings on typical
+ # grammars.
+ #
+ for sym in rhs:
+ if not self.rules.has_key(sym):
+ break
+ else:
+ tbd.append(rule)
+ changes = 1
+ while changes:
+ changes = 0
+ for lhs, rhs in tbd:
+ if self.nullable[lhs]:
+ continue
+ for sym in rhs:
+ if not self.nullable[sym]:
+ break
+ else:
+ self.nullable[lhs] = 1
+ changes = 1
+
+ def makeState0(self):
+ s0 = _State(0, [])
+ for rule in self.newrules[self._START]:
+ s0.items.append((rule, 0))
+ return s0
+
+ def finalState(self, tokens):
+ #
+ # Yuck.
+ #
+ if len(self.newrules[self._START]) == 2 and len(tokens) == 0:
+ return 1
+ start = self.rules[self._START][0][1][1]
+ return self.goto(1, start)
+
+ def makeNewRules(self):
+ worklist = []
+ for rulelist in self.rules.values():
+ for rule in rulelist:
+ worklist.append((rule, 0, 1, rule))
+
+ for rule, i, candidate, oldrule in worklist:
+ lhs, rhs = rule
+ n = len(rhs)
+ while i < n:
+ sym = rhs[i]
+ if not self.rules.has_key(sym) or \
+ not self.nullable[sym]:
+ candidate = 0
+ i = i + 1
+ continue
+
+ newrhs = list(rhs)
+ newrhs[i] = self._NULLABLE+sym
+ newrule = (lhs, tuple(newrhs))
+ worklist.append((newrule, i+1,
+ candidate, oldrule))
+ candidate = 0
+ i = i + 1
+ else:
+ if candidate:
+ lhs = self._NULLABLE+lhs
+ rule = (lhs, rhs)
+ if self.newrules.has_key(lhs):
+ self.newrules[lhs].append(rule)
+ else:
+ self.newrules[lhs] = [ rule ]
+ self.new2old[rule] = oldrule
+
+ def typestring(self, token):
+ return None
+
+ def error(self, token):
+ print "Syntax error at or near `%s' token" % token
+ raise SystemExit
+
+ def parse(self, tokens):
+ sets = [ [(1,0), (2,0)] ]
+ self.links = {}
+
+ if self.ruleschanged:
+ self.computeNull()
+ self.newrules = {}
+ self.new2old = {}
+ self.makeNewRules()
+ self.ruleschanged = 0
+ self.edges, self.cores = {}, {}
+ self.states = { 0: self.makeState0() }
+ self.makeState(0, self._BOF)
+
+ for i in xrange(len(tokens)):
+ sets.append([])
+
+ if sets[i] == []:
+ break
+ self.makeSet(tokens[i], sets, i)
+ else:
+ sets.append([])
+ self.makeSet(None, sets, len(tokens))
+
+ #_dump(tokens, sets, self.states)
+
+ finalitem = (self.finalState(tokens), 0)
+ if finalitem not in sets[-2]:
+ if len(tokens) > 0:
+ self.error(tokens[i-1], i, tokens)
+ else:
+ self.error(None)
+
+ return self.buildTree(self._START, finalitem,
+ tokens, len(sets)-2)
+
+ def isnullable(self, sym):
+ #
+ # For symbols in G_e only. If we weren't supporting 1.5,
+ # could just use sym.startswith().
+ #
+ return self._NULLABLE == sym[0:len(self._NULLABLE)]
+
+ def skip(self, (lhs, rhs), pos=0):
+ n = len(rhs)
+ while pos < n:
+ if not self.isnullable(rhs[pos]):
+ break
+ pos = pos + 1
+ return pos
+
+ def makeState(self, state, sym):
+ assert sym is not None
+ #
+ # Compute \epsilon-kernel state's core and see if
+ # it exists already.
+ #
+ kitems = []
+ for rule, pos in self.states[state].items:
+ lhs, rhs = rule
+ if rhs[pos:pos+1] == (sym,):
+ kitems.append((rule, self.skip(rule, pos+1)))
+ core = kitems
+
+ core.sort()
+ tcore = tuple(core)
+ if self.cores.has_key(tcore):
+ return self.cores[tcore]
+ #
+ # Nope, doesn't exist. Compute it and the associated
+ # \epsilon-nonkernel state together; we'll need it right away.
+ #
+ k = self.cores[tcore] = len(self.states)
+ K, NK = _State(k, kitems), _State(k+1, [])
+ self.states[k] = K
+ predicted = {}
+
+ edges = self.edges
+ rules = self.newrules
+ for X in K, NK:
+ worklist = X.items
+ for item in worklist:
+ rule, pos = item
+ lhs, rhs = rule
+ if pos == len(rhs):
+ X.complete.append(rule)
+ continue
+
+ nextSym = rhs[pos]
+ key = (X.stateno, nextSym)
+ if not rules.has_key(nextSym):
+ if not edges.has_key(key):
+ edges[key] = None
+ X.T.append(nextSym)
+ else:
+ edges[key] = None
+ if not predicted.has_key(nextSym):
+ predicted[nextSym] = 1
+ for prule in rules[nextSym]:
+ ppos = self.skip(prule)
+ new = (prule, ppos)
+ NK.items.append(new)
+ #
+ # Problem: we know K needs generating, but we
+ # don't yet know about NK. Can't commit anything
+ # regarding NK to self.edges until we're sure. Should
+ # we delay committing on both K and NK to avoid this
+ # hacky code? This creates other problems..
+ #
+ if X is K:
+ edges = {}
+
+ if NK.items == []:
+ return k
+
+ #
+ # Check for \epsilon-nonkernel's core. Unfortunately we
+ # need to know the entire set of predicted nonterminals
+ # to do this without accidentally duplicating states.
+ #
+ core = predicted.keys()
+ core.sort()
+ tcore = tuple(core)
+ if self.cores.has_key(tcore):
+ self.edges[(k, None)] = self.cores[tcore]
+ return k
+
+ nk = self.cores[tcore] = self.edges[(k, None)] = NK.stateno
+ self.edges.update(edges)
+ self.states[nk] = NK
+ return k
+
+ def goto(self, state, sym):
+ key = (state, sym)
+ if not self.edges.has_key(key):
+ #
+ # No transitions from state on sym.
+ #
+ return None
+
+ rv = self.edges[key]
+ if rv is None:
+ #
+ # Target state isn't generated yet. Remedy this.
+ #
+ rv = self.makeState(state, sym)
+ self.edges[key] = rv
+ return rv
+
+ def gotoT(self, state, t):
+ return [self.goto(state, t)]
+
+ def gotoST(self, state, st):
+ rv = []
+ for t in self.states[state].T:
+ if st == t:
+ rv.append(self.goto(state, t))
+ return rv
+
+ def add(self, set, item, i=None, predecessor=None, causal=None):
+ if predecessor is None:
+ if item not in set:
+ set.append(item)
+ else:
+ key = (item, i)
+ if item not in set:
+ self.links[key] = []
+ set.append(item)
+ self.links[key].append((predecessor, causal))
+
+ def makeSet(self, token, sets, i):
+ cur, next = sets[i], sets[i+1]
+
+ ttype = token is not None and self.typestring(token) or None
+ if ttype is not None:
+ fn, arg = self.gotoT, ttype
+ else:
+ fn, arg = self.gotoST, token
+
+ for item in cur:
+ ptr = (item, i)
+ state, parent = item
+ add = fn(state, arg)
+ for k in add:
+ if k is not None:
+ self.add(next, (k, parent), i+1, ptr)
+ nk = self.goto(k, None)
+ if nk is not None:
+ self.add(next, (nk, i+1))
+
+ if parent == i:
+ continue
+
+ for rule in self.states[state].complete:
+ lhs, rhs = rule
+ for pitem in sets[parent]:
+ pstate, pparent = pitem
+ k = self.goto(pstate, lhs)
+ if k is not None:
+ why = (item, i, rule)
+ pptr = (pitem, parent)
+ self.add(cur, (k, pparent),
+ i, pptr, why)
+ nk = self.goto(k, None)
+ if nk is not None:
+ self.add(cur, (nk, i))
+
+ def makeSet_fast(self, token, sets, i):
+ #
+ # Call *only* when the entire state machine has been built!
+ # It relies on self.edges being filled in completely, and
+ # then duplicates and inlines code to boost speed at the
+ # cost of extreme ugliness.
+ #
+ cur, next = sets[i], sets[i+1]
+ ttype = token is not None and self.typestring(token) or None
+
+ for item in cur:
+ ptr = (item, i)
+ state, parent = item
+ if ttype is not None:
+ k = self.edges.get((state, ttype), None)
+ if k is not None:
+ #self.add(next, (k, parent), i+1, ptr)
+ #INLINED --v
+ new = (k, parent)
+ key = (new, i+1)
+ if new not in next:
+ self.links[key] = []
+ next.append(new)
+ self.links[key].append((ptr, None))
+ #INLINED --^
+ #nk = self.goto(k, None)
+ nk = self.edges.get((k, None), None)
+ if nk is not None:
+ #self.add(next, (nk, i+1))
+ #INLINED --v
+ new = (nk, i+1)
+ if new not in next:
+ next.append(new)
+ #INLINED --^
+ else:
+ add = self.gotoST(state, token)
+ for k in add:
+ if k is not None:
+ self.add(next, (k, parent), i+1, ptr)
+ #nk = self.goto(k, None)
+ nk = self.edges.get((k, None), None)
+ if nk is not None:
+ self.add(next, (nk, i+1))
+
+ if parent == i:
+ continue
+
+ for rule in self.states[state].complete:
+ lhs, rhs = rule
+ for pitem in sets[parent]:
+ pstate, pparent = pitem
+ #k = self.goto(pstate, lhs)
+ k = self.edges.get((pstate, lhs), None)
+ if k is not None:
+ why = (item, i, rule)
+ pptr = (pitem, parent)
+ #self.add(cur, (k, pparent),
+ # i, pptr, why)
+ #INLINED --v
+ new = (k, pparent)
+ key = (new, i)
+ if new not in cur:
+ self.links[key] = []
+ cur.append(new)
+ self.links[key].append((pptr, why))
+ #INLINED --^
+ #nk = self.goto(k, None)
+ nk = self.edges.get((k, None), None)
+ if nk is not None:
+ #self.add(cur, (nk, i))
+ #INLINED --v
+ new = (nk, i)
+ if new not in cur:
+ cur.append(new)
+ #INLINED --^
+
+ def predecessor(self, key, causal):
+ for p, c in self.links[key]:
+ if c == causal:
+ return p
+ assert 0
+
+ def causal(self, key):
+ links = self.links[key]
+ if len(links) == 1:
+ return links[0][1]
+ choices = []
+ rule2cause = {}
+ for p, c in links:
+ rule = c[2]
+ choices.append(rule)
+ rule2cause[rule] = c
+ return rule2cause[self.ambiguity(choices)]
+
+ def deriveEpsilon(self, nt):
+ if len(self.newrules[nt]) > 1:
+ rule = self.ambiguity(self.newrules[nt])
+ else:
+ rule = self.newrules[nt][0]
+ #print rule
+
+ rhs = rule[1]
+ attr = [None] * len(rhs)
+
+ for i in range(len(rhs)-1, -1, -1):
+ attr[i] = self.deriveEpsilon(rhs[i])
+ return self.rule2func[self.new2old[rule]](attr)
+
+ def buildTree(self, nt, item, tokens, k):
+ state, parent = item
+
+ choices = []
+ for rule in self.states[state].complete:
+ if rule[0] == nt:
+ choices.append(rule)
+ rule = choices[0]
+ if len(choices) > 1:
+ rule = self.ambiguity(choices)
+ #print rule
+
+ rhs = rule[1]
+ attr = [None] * len(rhs)
+
+ for i in range(len(rhs)-1, -1, -1):
+ sym = rhs[i]
+ if not self.newrules.has_key(sym):
+ if sym != self._BOF:
+ attr[i] = tokens[k-1]
+ key = (item, k)
+ item, k = self.predecessor(key, None)
+ #elif self.isnullable(sym):
+ elif self._NULLABLE == sym[0:len(self._NULLABLE)]:
+ attr[i] = self.deriveEpsilon(sym)
+ else:
+ key = (item, k)
+ why = self.causal(key)
+ attr[i] = self.buildTree(sym, why[0],
+ tokens, why[1])
+ item, k = self.predecessor(key, why)
+ return self.rule2func[self.new2old[rule]](attr)
+
+ def ambiguity(self, rules):
+ #
+ # XXX - problem here and in collectRules() if the same rule
+ # appears in >1 method. Also undefined results if rules
+ # causing the ambiguity appear in the same method.
+ #
+ sortlist = []
+ name2index = {}
+ for i in range(len(rules)):
+ lhs, rhs = rule = rules[i]
+ name = self.rule2name[self.new2old[rule]]
+ sortlist.append((len(rhs), name))
+ name2index[name] = i
+ sortlist.sort()
+ list = map(lambda (a,b): b, sortlist)
+ return rules[name2index[self.resolve(list)]]
+
+ def resolve(self, list):
+ #
+ # Resolve ambiguity in favor of the shortest RHS.
+ # Since we walk the tree from the top down, this
+ # should effectively resolve in favor of a "shift".
+ #
+ return list[0]
+
+#
+# GenericASTBuilder automagically constructs a concrete/abstract syntax tree
+# for a given input. The extra argument is a class (not an instance!)
+# which supports the "__setslice__" and "__len__" methods.
+#
+# XXX - silently overrides any user code in methods.
+#
+
+class GenericASTBuilder(GenericParser):
+ def __init__(self, AST, start):
+ GenericParser.__init__(self, start)
+ self.AST = AST
+
+ def preprocess(self, rule, func):
+ rebind = lambda lhs, self=self: \
+ lambda args, lhs=lhs, self=self: \
+ self.buildASTNode(args, lhs)
+ lhs, rhs = rule
+ return rule, rebind(lhs)
+
+ def buildASTNode(self, args, lhs):
+ children = []
+ for arg in args:
+ if isinstance(arg, self.AST):
+ children.append(arg)
+ else:
+ children.append(self.terminal(arg))
+ return self.nonterminal(lhs, children)
+
+ def terminal(self, token): return token
+
+ def nonterminal(self, type, args):
+ rv = self.AST(type)
+ rv[:len(args)] = args
+ return rv
+
+#
+# GenericASTTraversal is a Visitor pattern according to Design Patterns. For
+# each node it attempts to invoke the method n_<node type>, falling
+# back onto the default() method if the n_* can't be found. The preorder
+# traversal also looks for an exit hook named n_<node type>_exit (no default
+# routine is called if it's not found). To prematurely halt traversal
+# of a subtree, call the prune() method -- this only makes sense for a
+# preorder traversal. Node type is determined via the typestring() method.
+#
+
+class GenericASTTraversalPruningException:
+ pass
+
+class GenericASTTraversal:
+ def __init__(self, ast):
+ self.ast = ast
+
+ def typestring(self, node):
+ return node.type
+
+ def prune(self):
+ raise GenericASTTraversalPruningException
+
+ def preorder(self, node=None):
+ if node is None:
+ node = self.ast
+
+ try:
+ name = 'n_' + self.typestring(node)
+ if hasattr(self, name):
+ func = getattr(self, name)
+ func(node)
+ else:
+ self.default(node)
+ except GenericASTTraversalPruningException:
+ return
+
+ for kid in node:
+ self.preorder(kid)
+
+ name = name + '_exit'
+ if hasattr(self, name):
+ func = getattr(self, name)
+ func(node)
+
+ def postorder(self, node=None):
+ if node is None:
+ node = self.ast
+
+ for kid in node:
+ self.postorder(kid)
+
+ name = 'n_' + self.typestring(node)
+ if hasattr(self, name):
+ func = getattr(self, name)
+ func(node)
+ else:
+ self.default(node)
+
+
+ def default(self, node):
+ pass
+
+#
+# GenericASTMatcher. AST nodes must have "__getitem__" and "__cmp__"
+# implemented.
+#
+# XXX - makes assumptions about how GenericParser walks the parse tree.
+#
+
+class GenericASTMatcher(GenericParser):
+ def __init__(self, start, ast):
+ GenericParser.__init__(self, start)
+ self.ast = ast
+
+ def preprocess(self, rule, func):
+ rebind = lambda func, self=self: \
+ lambda args, func=func, self=self: \
+ self.foundMatch(args, func)
+ lhs, rhs = rule
+ rhslist = list(rhs)
+ rhslist.reverse()
+
+ return (lhs, tuple(rhslist)), rebind(func)
+
+ def foundMatch(self, args, func):
+ func(args[-1])
+ return args[-1]
+
+ def match_r(self, node):
+ self.input.insert(0, node)
+ children = 0
+
+ for child in node:
+ if children == 0:
+ self.input.insert(0, '(')
+ children = children + 1
+ self.match_r(child)
+
+ if children > 0:
+ self.input.insert(0, ')')
+
+ def match(self, ast=None):
+ if ast is None:
+ ast = self.ast
+ self.input = []
+
+ self.match_r(ast)
+ self.parse(self.input)
+
+ def resolve(self, list):
+ #
+ # Resolve ambiguity in favor of the longest RHS.
+ #
+ return list[-1]
+
+def _dump(tokens, sets, states):
+ for i in range(len(sets)):
+ print 'set', i
+ for item in sets[i]:
+ print '\t', item
+ for (lhs, rhs), pos in states[item[0]].items:
+ print '\t\t', lhs, '::=',
+ print string.join(rhs[:pos]),
+ print '.',
+ print string.join(rhs[pos:])
+ if i < len(tokens):
+ print
+ print 'token', str(tokens[i])
+ print
diff --git a/tester/rt/report.py b/tester/rt/report.py
new file mode 100644
index 0000000..1aa1f35
--- /dev/null
+++ b/tester/rt/report.py
@@ -0,0 +1,185 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# RTEMS Testing Reports
+#
+
+import datetime
+import os
+import threading
+
+from rtemstoolkit import error
+from rtemstoolkit import log
+from rtemstoolkit import path
+
+class report(object):
+ '''RTEMS Testing report.'''
+
+ def __init__(self, total):
+ self.lock = threading.Lock()
+ self.total = total
+ self.total_len = len(str(total))
+ self.passed = 0
+ self.failed = 0
+ self.timeouts = 0
+ self.invalids = 0
+ self.invalid_tests = 0
+ self.results = {}
+ self.name_max_len = 0
+
+ def __str__(self):
+ msg = 'Passed: %*d%s' % (self.total_len, self.passed, os.linesep)
+ msg += 'Failed: %*d%s' % (self.total_len, self.failed, os.linesep)
+ msg += 'Timeouts: %*d%s' % (self.total_len, self.timeouts, os.linesep)
+ msg += 'Invalid: %*d%s' % (self.total_len, self.invalids, os.linesep)
+ return msg
+
+ def set_invalid_tests(self, invalid_tests):
+ self.invalid_tests = invalid_tests
+
+ def start(self, index, total, name, executable, bsp_arch, bsp):
+ header = '[%*d/%*d] p:%-*d f:%-*d t:%-*d i:%-*d | %s/%s: %s' % \
+ (len(str(total)), index,
+ len(str(total)), total,
+ len(str(total)), self.passed,
+ len(str(total)), self.failed,
+ len(str(total)), self.timeouts,
+ len(str(total)), self.invalids,
+ bsp_arch,
+ bsp,
+ path.basename(executable))
+ self.lock.acquire()
+ if name in self.results:
+ self.lock.release()
+ raise error.general('duplicate test: %s' % (name))
+ self.results[name] = { 'index': index,
+ 'bsp': bsp,
+ 'bsp_arch': bsp_arch,
+ 'exe': executable,
+ 'start': datetime.datetime.now(),
+ 'end': None,
+ 'result': None,
+ 'output': None,
+ 'header': header }
+
+ self.lock.release()
+ log.notice(header, stdout_only = True)
+
+ def end(self, name, output):
+ start = False
+ end = False
+ timeout = False
+ prefixed_output = []
+ for line in output:
+ if line[0] == ']':
+ if line[1].startswith('*** '):
+ if line[1][4:].startswith('END OF '):
+ end = True
+ if line[1][4:].startswith('TIMEOUT TIMEOUT'):
+ timeout = True
+ else:
+ start = True
+ prefixed_output += [line[0] + ' ' + line[1]]
+ self.lock.acquire()
+ if name not in self.results:
+ self.lock.release()
+ raise error.general('test report missing: %s' % (name))
+ if self.results[name]['end'] is not None:
+ self.lock.release()
+ raise error.general('test already finished: %s' % (name))
+ self.results[name]['end'] = datetime.datetime.now()
+ if start and end:
+ status = 'passed'
+ self.passed += 1
+ elif timeout:
+ status = 'timeout'
+ self.timeouts += 1
+ elif start:
+ if not end:
+ status = 'failed'
+ self.failed += 1
+ else:
+ if self.invalid_tests and path.basename(name) in self.invalid_tests:
+ status = 'passed'
+ self.passed += 1
+ else:
+ status = 'invalid'
+ self.invalids += 1
+ self.results[name]['result'] = status
+ self.results[name]['output'] = prefixed_output
+ if self.name_max_len < len(path.basename(name)):
+ self.name_max_len = len(path.basename(name))
+ self.lock.release()
+
+ def log(self, name, mode):
+ if mode != 'none':
+ self.lock.acquire()
+ if name not in self.results:
+ self.lock.release()
+ raise error.general('test report missing: %s' % (name))
+ result = self.results[name]['result']
+ time = self.results[name]['end'] - self.results[name]['start']
+ if mode != 'none':
+ header = self.results[name]['header']
+ if mode == 'all' or result != 'passed':
+ output = self.results[name]['output']
+ else:
+ output = None
+ self.lock.release()
+ if header:
+ log.output(header)
+ if output:
+ log.output(output)
+ if header:
+ log.output('Result: %-10s Time: %s' % (result, str(time)))
+
+ def summary(self):
+ def show_state(results, state, max_len):
+ for name in results:
+ if results[name]['result'] == state:
+ log.output(' %s' % (path.basename(name)))
+ log.output()
+ log.notice('Passed: %*d' % (self.total_len, self.passed))
+ log.notice('Failed: %*d' % (self.total_len, self.failed))
+ log.notice('Timeouts: %*d' % (self.total_len, self.timeouts))
+ log.notice('Invalid: %*d' % (self.total_len, self.invalids))
+ log.output('----------%s' % ('-' * self.total_len))
+ log.notice('Total: %*d' % (self.total_len, self.total))
+ log.output()
+ if self.failed:
+ log.output('Failures:')
+ show_state(self.results, 'failed', self.name_max_len)
+ if self.timeouts:
+ log.output('Timeouts:')
+ show_state(self.results, 'timeout', self.name_max_len)
+ if self.invalids:
+ log.output('Invalid:')
+ show_state(self.results, 'invalid', self.name_max_len)
diff --git a/tester/rt/stty.py b/tester/rt/stty.py
new file mode 100644
index 0000000..d059b40
--- /dev/null
+++ b/tester/rt/stty.py
@@ -0,0 +1,567 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# RTEMS Testing Consoles
+#
+
+import os
+import sys
+import termios
+
+from rtemstoolkit import error
+from rtemstoolkit import options
+from rtemstoolkit import path
+
+def save():
+ if not options.host_windows:
+ try:
+ sin = termios.tcgetattr(sys.stdin)
+ sout = termios.tcgetattr(sys.stdout)
+ serr = termios.tcgetattr(sys.stderr)
+ return sin, sout, serr
+ except:
+ pass
+ return None
+
+def restore(attributes):
+ if attributes is not None:
+ termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes[0])
+ termios.tcsetattr(sys.stdout, termios.TCSANOW, attributes[1])
+ termios.tcsetattr(sys.stderr, termios.TCSANOW, attributes[2])
+
+class tty:
+
+ def __init__(self, dev):
+ if options.host_windows:
+ raise error.general('termios not support on host')
+ self.dev = dev
+ self.default_attr = None
+ self.fd = None
+ self.if_on = False
+ if options.host_windows:
+ raise error.general('TTY consoles not supported on Windows.')
+ if not path.exists(dev):
+ raise error.general('dev not found: %s' % (dev))
+ try:
+ self.fd = open(dev, 'rw')
+ except IOError, ioe:
+ raise error.general('opening tty dev: %s: %s' % (dev, ioe))
+ except:
+ raise error.general('opening tty dev: %s: unknown' % (dev))
+ try:
+ self.default_attr = termios.tcgetattr(self.fd)
+ except:
+ raise error.general('cannot get termios attrs: %s' % (dev))
+ self.attr = self.default_attr
+
+ def __del__(self):
+ if self.fd and self.default_attr:
+ try:
+ self.fd.close()
+ except:
+ pass
+
+ def __str__(self):
+ def _input(attr):
+ s = ''
+ if attr & termios.IGNBRK:
+ s += ' IGNBRK'
+ if attr & termios.BRKINT:
+ s += ' BRKINT'
+ if attr & termios.IGNPAR:
+ s += ' IGNPAR'
+ if attr & termios.PARMRK:
+ s += ' PARMRK'
+ if attr & termios.INPCK:
+ s += ' INPCK'
+ if attr & termios.ISTRIP:
+ s += ' ISTRIP'
+ if attr & termios.INLCR:
+ s += ' INLCR'
+ if attr & termios.IGNCR:
+ s += ' IGNCR'
+ if attr & termios.IXON:
+ s += ' IXON'
+ if attr & termios.IXOFF:
+ s += ' IXOFF'
+ if attr & termios.IXANY:
+ s += ' IXANY'
+ if attr & termios.IMAXBEL:
+ s += ' IMAXBEL'
+ return s
+
+ def _output(attr):
+ s = ''
+ if attr & termios.OPOST:
+ s += ' OPOST'
+ if attr & termios.ONLCR:
+ s += ' ONLCR'
+ if attr & termios.OCRNL:
+ s += ' OCRNL'
+ if attr & termios.TABDLY:
+ s += ' TABDLY'
+ if attr & termios.TAB0:
+ s += ' TAB0'
+ if attr & termios.TAB3:
+ s += ' TAB3'
+ if attr & termios.ONOCR:
+ s += ' ONOCR'
+ if attr & termios.ONLRET:
+ s += ' ONLRET'
+ return s
+
+ def _control(attr):
+ s = ''
+ if (attr & termios.CSIZE) == termios.CS5:
+ s += ' CS5'
+ if (attr & termios.CSIZE) == termios.CS6:
+ s += ' CS6'
+ if (attr & termios.CSIZE) == termios.CS7:
+ s += ' CS7'
+ if (attr & termios.CSIZE) == termios.CS8:
+ s += ' CS8'
+ if attr & termios.CSTOPB:
+ s += ' CSTOPB'
+ if attr & termios.CREAD:
+ s += ' CREAD'
+ if attr & termios.PARENB:
+ s += ' PARENB'
+ if attr & termios.PARODD:
+ s += ' PARODD'
+ if attr & termios.HUPCL:
+ s += ' HUPCL'
+ if attr & termios.CLOCAL:
+ s += ' CLOCAL'
+ if attr & termios.CRTSCTS:
+ s += ' CRTSCTS'
+ return s
+
+ def _local(attr):
+ s = ''
+ if attr & termios.ECHOKE:
+ s += ' ECHOKE'
+ if attr & termios.ECHOE:
+ s += ' ECHOE'
+ if attr & termios.ECHO:
+ s += ' ECHO'
+ if attr & termios.ECHONL:
+ s += ' ECHONL'
+ if attr & termios.ECHOPRT:
+ s += ' ECHOPRT'
+ if attr & termios.ECHOCTL:
+ s += ' ECHOCTL'
+ if attr & termios.ISIG:
+ s += ' ISIG'
+ if attr & termios.ICANON:
+ s += ' ICANON'
+ if attr & termios.IEXTEN:
+ s += ' IEXTEN'
+ if attr & termios.TOSTOP:
+ s += ' TOSTOP'
+ if attr & termios.FLUSHO:
+ s += ' FLUSHO'
+ if attr & termios.PENDIN:
+ s += ' PENDIN'
+ if attr & termios.NOFLSH:
+ s += ' NOFLSH'
+ return s
+
+ def _baudrate(attr):
+ if attr == termios.B0:
+ s = 'B0'
+ elif attr == termios.B50:
+ s = 'B50'
+ elif attr == termios.B75:
+ s = 'B75'
+ elif attr == termios.B110:
+ s = 'B110'
+ elif attr == termios.B134:
+ s = 'B134'
+ elif attr == termios.B150:
+ s = 'B150'
+ elif attr == termios.B200:
+ s = 'B200'
+ elif attr == termios.B300:
+ s = 'B300'
+ elif attr == termios.B600:
+ s = 'B600'
+ elif attr == termios.B1800:
+ s = 'B1800'
+ elif attr == termios.B1200:
+ s = 'B1200'
+ elif attr == termios.B2400:
+ s = 'B2400'
+ elif attr == termios.B4800:
+ s = 'B4800'
+ elif attr == termios.B9600:
+ s = 'B9600'
+ elif attr == termios.B19200:
+ s = 'B19200'
+ elif attr == termios.B38400:
+ s = 'B38400'
+ elif attr == termios.B57600:
+ s = 'B57600'
+ elif attr == termios.B115200:
+ s = 'B115200'
+ elif attr == termios.B230400:
+ s = 'B230400'
+ elif attr == termios.B460800:
+ s = 'B460800'
+ else:
+ s = 'unknown'
+ return s
+
+ if self.attr is None:
+ return 'None'
+ s = 'iflag: %s' % (_input(self.attr[0]))
+ s += os.linesep + 'oflag: %s' % (_output(self.attr[1]))
+ s += os.linesep + 'cflag: %s' % (_control(self.attr[2]))
+ s += os.linesep + 'lflag: %s' % (_local(self.attr[3]))
+ s += os.linesep + 'ispeed: %s' % (_baudrate(self.attr[4]))
+ s += os.linesep + 'ospeed: %s' % (_baudrate(self.attr[5]))
+ return s
+
+ def _update(self):
+ self.off()
+ try:
+ termios.tcflush(self.fd, termios.TCIOFLUSH)
+ #attr = self.attr
+ #attr[0] = termios.IGNPAR;
+ #attr[1] = 0
+ #attr[2] = termios.CRTSCTS | termios.CS8 | termios.CREAD;
+ #attr[3] = 0
+ #attr[6][termios.VMIN] = 1
+ #attr[6][termios.VTIME] = 2
+ #termios.tcsetattr(self.fd, termios.TCSANOW, attr)
+ termios.tcsetattr(self.fd, termios.TCSANOW, self.attr)
+ termios.tcflush(self.fd, termios.TCIOFLUSH)
+ except:
+ raise
+ if self.is_on:
+ self.on()
+
+ def _baudrate_mask(self, flag):
+ if flag == 'B0':
+ mask = termios.B0
+ self.attr[5] = termios.B0
+ elif flag == 'B50':
+ mask = termios.B50
+ elif flag == 'B75':
+ mask = termios.B75
+ elif flag == 'B110':
+ mask = termios.B110
+ elif flag == 'B134':
+ mask = termios.B134
+ elif flag == 'B150':
+ mask = termios.B150
+ elif flag == 'B200':
+ mask = termios.B200
+ elif flag == 'B300':
+ mask = termios.B300
+ elif flag == 'B600':
+ mask = termios.B600
+ elif flag == 'B1800':
+ mask = termios.B1800
+ elif flag == 'B1200':
+ mask = termios.B1200
+ elif flag == 'B2400':
+ mask = termios.B2400
+ elif flag == 'B4800':
+ mask = termios.B4800
+ elif flag == 'B9600':
+ mask = termios.B9600
+ elif flag == 'B19200':
+ mask = termios.B19200
+ elif flag == 'B38400':
+ mask = termios.B38400
+ elif flag == 'B57600':
+ mask = termios.B57600
+ elif flag == 'B115200':
+ mask = termios.B115200
+ elif flag == 'B230400':
+ mask = termios.B230400
+ elif flag == 'B460800':
+ mask = termios.B460800
+ else:
+ mask = None
+ return mask
+
+ def _input_mask(self, flag):
+ if flag == 'IGNBRK':
+ mask = termios.IGNBRK
+ elif flag == 'BRKINT':
+ mask = termios.BRKINT
+ elif flag == 'IGNPAR':
+ mask = termios.IGNPAR
+ elif flag == 'PARMRK':
+ mask = termios.PARMRK
+ elif flag == 'INPCK':
+ mask = termios.INPCK
+ elif flag == 'ISTRIP':
+ mask = termios.ISTRIP
+ elif flag == 'INLCR':
+ mask = termios.INLCR
+ elif flag == 'IGNCR':
+ mask = termios.IGNCR
+ elif flag == 'IXON':
+ mask = termios.IXON
+ elif flag == 'IXOFF':
+ mask = termios.IXOFF
+ elif flag == 'IXANY':
+ mask = termios.IXANY
+ elif flag == 'IMAXBEL':
+ mask = termios.IMAXBEL
+ else:
+ mask = None
+ return mask
+
+ def _output_mask(self, flag):
+ if flag == 'OPOST':
+ mask = termios.OPOST
+ elif flag == 'ONLCR':
+ mask = termios.ONLCR
+ elif flag == 'OCRNL':
+ mask = termios.OCRNL
+ elif flag == 'TABDLY':
+ mask = termios.TABDLY
+ elif flag == 'TAB0':
+ mask = termios.TAB0
+ elif flag == 'TAB3':
+ mask = termios.TAB3
+ elif flag == 'ONOCR':
+ mask = termios.ONOCR
+ elif flag == 'ONLRET':
+ mask = termios.ONLRET
+ else:
+ mask = None
+ return mask
+
+ def _control_mask(self, flag):
+ if flag == 'CSTOPB':
+ mask = termios.CSTOPB
+ elif flag == 'CREAD':
+ mask = termios.CREAD
+ elif flag == 'PARENB':
+ mask = termios.PARENB
+ elif flag == 'PARODD':
+ mask = termios.PARODD
+ elif flag == 'HUPCL':
+ mask = termios.HUPCL
+ elif flag == 'CLOCAL':
+ mask = termios.CLOCAL
+ elif flag == 'CRTSCTS':
+ mask = termios.CRTSCTS
+ else:
+ mask = None
+ return mask
+
+ def _local_mask(self, flag):
+ if flag == 'ECHOKE':
+ mask = termios.ECHOKE
+ elif flag == 'ECHOE':
+ mask = termios.ECHOE
+ elif flag == 'ECHO':
+ mask = termios.ECHO
+ elif flag == 'ECHONL':
+ mask = termios.ECHONL
+ elif flag == 'ECHOPRT':
+ mask = termios.ECHOPRT
+ elif flag == 'ECHOCTL':
+ mask = termios.ECHOCTL
+ elif flag == 'ISIG':
+ mask = termios.ISIG
+ elif flag == 'ICANON':
+ mask = termios.ICANON
+ elif flag == 'IEXTEN':
+ mask = termios.IEXTEN
+ elif flag == 'TOSTOP':
+ mask = termios.TOSTOP
+ elif flag == 'FLUSHO':
+ mask = termios.FLUSHO
+ elif flag == 'PENDIN':
+ mask = termios.PENDIN
+ elif flag == 'NOFLSH':
+ mask = termios.NOFLSH
+ else:
+ mask = None
+ return mask
+
+ def _set(self, index, mask, state):
+ if state:
+ self.attr[index] = self.attr[index] | mask
+ else:
+ self.attr[index] = self.attr[index] & ~mask
+
+ def off(self):
+ if self.fd:
+ try:
+ termios.tcflow(self.fd, termios.TCOOFF)
+ except:
+ pass
+ try:
+ termios.tcflow(self.fd, termios.TCIOFF)
+ except:
+ pass
+ self.is_on = False
+
+ def on(self):
+ if self.fd:
+ try:
+ termios.tcflow(self.fd, termios.TCOON)
+ except:
+ pass
+ try:
+ termios.tcflow(self.fd, termios.TCION)
+ except:
+ pass
+ self.is_on = True
+
+ def baudrate(self, flag):
+ mask = self._baudrate_mask(flag)
+ if mask:
+ self.attr[4] = mask
+ self.attr[5] = mask
+ else:
+ raise error.general('invalid setting: %s' % (flag))
+ self._update()
+
+ def input(self, flag, on):
+ mask = self._input_mask(flag)
+ if mask is None:
+ raise error.general('invalid input flag: %s' % (flag))
+ self._set(0, mask, on)
+ self._update()
+
+ def output(self, flag, on):
+ mask = self._output_mask(flag)
+ if mask is None:
+ raise error.general('invalid output flag: %s' % (flag))
+ self._set(1, mask, on)
+ self._update()
+
+ def control(self, flag, on):
+ mask = self._control_mask(flag)
+ if mask is None:
+ raise error.general('invalid control flag: %s' % (flag))
+ self._set(2, mask, on)
+ self._update()
+
+ def local(self, flag, on):
+ mask = self._local_mask(flag)
+ if mask is None:
+ raise error.general('invalid local flag: %s' % (flag))
+ self._set(3, mask, on)
+ self._update()
+
+ def vmin(self, _vmin):
+ self.attr[6][termios.VMIN] = _vmin
+
+ def vtime(self, _vtime):
+ self.attr[6][termios.VTIME] = _vtime
+
+ def set(self, flags):
+ for f in flags.split(','):
+ if len(f) < 2:
+ raise error.general('invalid flag: %s' % (f))
+ if f[0] == '~':
+ on = False
+ flag = f[1:]
+ else:
+ on = True
+ flag = f
+ if f.startswith('VMIN'):
+ vs = f.split('=')
+ if len(vs) != 2:
+ raise error.general('invalid vmin flag: %s' % (f))
+ try:
+ _vmin = int(vs[1])
+ except:
+ raise error.general('invalid vmin flag: %s' % (f))
+ self.vmin(_vmin)
+ continue
+ if f.startswith('VTIME'):
+ vs = f.split('=')
+ if len(vs) != 2:
+ raise error.general('invalid vtime flag: %s' % (f))
+ try:
+ _vtime = int(vs[1])
+ except:
+ raise error.general('invalid vtime flag: %s' % (f))
+ self.vtime(_vtime)
+ continue
+ mask = self._baudrate_mask(flag)
+ if mask:
+ if not on:
+ raise error.general('baudrates are not flags: %s' % (f))
+ self.attr[4] = mask
+ self.attr[5] = mask
+ continue
+ mask = self._input_mask(flag)
+ if mask:
+ self._set(0, mask, on)
+ continue
+ mask = self._output_mask(flag)
+ if mask:
+ self._set(1, mask, on)
+ continue
+ mask = self._control_mask(flag)
+ if mask:
+ self._set(2, mask, on)
+ continue
+ mask = self._local_mask(flag)
+ if mask:
+ self._set(3, mask, on)
+ continue
+ raise error.general('unknown tty flag: %s' % (f))
+ self._update()
+
+if __name__ == "__main__":
+ if len(sys.argv) == 2:
+ t = tty(sys.argv[1])
+ t.baudrate('B115200')
+ t.input('BRKINT', False)
+ t.input('IGNBRK', True)
+ t.input('IGNCR', True)
+ t.local('ICANON', False)
+ t.local('ISIG', False)
+ t.local('IEXTEN', False)
+ t.local('ECHO', False)
+ t.control('CLOCAL', True)
+ t.control('CRTSCTS', False)
+ t.vmin(1)
+ t.vtime(2)
+ print t
+ t.set('B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS')
+ print t
+ t.on()
+ while True:
+ c = t.fd.read(1)
+ sys.stdout.write(c)
diff --git a/tester/rt/test.py b/tester/rt/test.py
new file mode 100644
index 0000000..15da4ee
--- /dev/null
+++ b/tester/rt/test.py
@@ -0,0 +1,304 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+import copy
+import datetime
+import os
+import sys
+import threading
+import time
+
+from rtemstoolkit import error
+from rtemstoolkit import log
+from rtemstoolkit import path
+
+import config
+import console
+import options
+import report
+import version
+
+def stacktraces():
+ import traceback
+ code = []
+ for threadId, stack in sys._current_frames().items():
+ code.append("\n# thread-id: %s" % threadId)
+ for filename, lineno, name, line in traceback.extract_stack(stack):
+ code.append('file: "%s", line %d, in %s' % (filename, lineno, name))
+ if line:
+ code.append(" %s" % (line.strip()))
+ return '\n'.join(code)
+
+class test(object):
+ def __init__(self, index, total, report, executable, rtems_tools, bsp, bsp_config, opts):
+ self.index = index
+ self.total = total
+ self.report = report
+ self.bsp = bsp
+ self.bsp_config = bsp_config
+ self.opts = copy.copy(opts)
+ self.opts.defaults['test_index'] = str(index)
+ self.opts.defaults['test_total'] = str(total)
+ self.opts.defaults['bsp'] = bsp
+ self.opts.defaults['bsp_arch'] = '%%{%s_arch}' % (bsp)
+ self.opts.defaults['bsp_opts'] = '%%{%s_opts}' % (bsp)
+ if not path.isfile(executable):
+ raise error.general('cannot find executable: %s' % (executable))
+ self.opts.defaults['test_executable'] = executable
+ if rtems_tools:
+ rtems_tools_bin = path.join(rtems_tools, 'bin')
+ if not path.isdir(rtems_tools_bin):
+ raise error.general('cannot find RTEMS tools path: %s' % (rtems_tools_bin))
+ self.opts.defaults['rtems_tools'] = rtems_tools_bin
+ self.config = config.file(report, bsp_config, self.opts)
+
+class test_run(object):
+ def __init__(self, index, total, report, executable, rtems_tools, bsp, bsp_config, opts):
+ self.test = None
+ self.result = None
+ self.start_time = None
+ self.end_time = None
+ self.index = copy.copy(index)
+ self.total = total
+ self.report = report
+ self.executable = copy.copy(executable)
+ self.rtems_tools = rtems_tools
+ self.bsp = bsp
+ self.bsp_config = bsp_config
+ self.opts = opts
+
+ def runner(self):
+ self.start_time = datetime.datetime.now()
+ try:
+ self.test = test(self.index, self.total, self.report,
+ self.executable, self.rtems_tools,
+ self.bsp, self.bsp_config,
+ self.opts)
+ except KeyboardInterrupt:
+ pass
+ except:
+ self.result = sys.exc_info()
+ self.end_time = datetime.datetime.now()
+
+ def run(self):
+ self.thread = threading.Thread(target = self.runner,
+ name = 'test[%s]' % path.basename(self.executable))
+ self.thread.start()
+
+ def is_alive(self):
+ return self.thread and self.thread.is_alive()
+
+ def reraise(self):
+ if self.result is not None:
+ raise self.result[0], self.result[1], self.result[2]
+
+def find_executables(paths):
+ executables = []
+ for p in paths:
+ if path.isfile(p):
+ executables += [p]
+ elif path.isdir(p):
+ for root, dirs, files in os.walk(p, followlinks = True):
+ for f in files:
+ if f.lower().endswith('.exe'):
+ executables += [path.join(root, f)]
+ return sorted(executables)
+
+def report_finished(reports, report_mode, reporting, finished, job_trace):
+ processing = True
+ while processing:
+ processing = False
+ reported = []
+ for tst in finished:
+ if tst not in reported and \
+ (reporting < 0 or tst.index == reporting):
+ if job_trace:
+ log.notice('}} %*d: %s: %s (%d)' % (len(str(tst.total)), tst.index,
+ path.basename(tst.executable),
+ 'reporting',
+ reporting))
+ processing = True
+ reports.log(tst.executable, report_mode)
+ reported += [tst]
+ reporting += 1
+ finished[:] = [t for t in finished if t not in reported]
+ if len(reported):
+ del reported[:]
+ if job_trace:
+ print '}} threading:', threading.active_count()
+ for t in threading.enumerate():
+ print '}} ', t.name
+ return reporting
+
+def _job_trace(tst, msg, total, exe, active, reporting):
+ s = ''
+ for a in active:
+ s += ' %d:%s' % (a.index, path.basename(a.executable))
+ log.notice('}} %*d: %s: %s (%d %d %d%s)' % (len(str(tst.total)), tst.index,
+ path.basename(tst.executable),
+ msg,
+ reporting, total, exe, s))
+
+def list_bsps(opts):
+ path_ = opts.defaults.expand('%%{_configdir}/bsps/*.mc')
+ bsps = path.collect_files(path_)
+ log.notice(' BSP List:')
+ for bsp in bsps:
+ log.notice(' %s' % (path.basename(bsp[:-3])))
+ raise error.exit()
+
+def run(command_path = None):
+ import sys
+ stdtty = console.save()
+ opts = None
+ try:
+ optargs = { '--rtems-tools': 'The path to the RTEMS tools',
+ '--rtems-bsp': 'The RTEMS BSP to run the test on',
+ '--report-mode': 'Reporting modes, failures (default),all,none',
+ '--list-bsps': 'List the supported BSPs',
+ '--debug-trace': 'Debug trace based on specific flags',
+ '--stacktrace': 'Dump a stack trace on a user termination (^C)' }
+ opts = options.load(sys.argv,
+ optargs = optargs,
+ command_path = command_path)
+ log.notice('RTEMS Testing - Tester, v%s' % (version.str()))
+ if opts.find_arg('--list-bsps'):
+ list_bsps(opts)
+ opts.log_info()
+ debug_trace = opts.find_arg('--debug-trace')
+ if debug_trace:
+ debug_trace = debug_trace[1]
+ else:
+ debug_trace = ''
+ opts.defaults['debug_trace'] = debug_trace
+ job_trace = 'jobs' in debug_trace.split(',')
+ rtems_tools = opts.find_arg('--rtems-tools')
+ if rtems_tools:
+ rtems_tools = rtems_tools[1]
+ bsp = opts.find_arg('--rtems-bsp')
+ if bsp is None:
+ raise error.general('no RTEMS BSP provided')
+ opts.defaults.load('%%{_configdir}/bsps/%s.mc' % (bsp[1]))
+ bsp = opts.defaults.get('%{bsp}')
+ if not bsp:
+ raise error.general('BSP definition (%{bsp}) not found in the global map')
+ bsp = bsp[2]
+ if not opts.defaults.set_read_map(bsp):
+ raise error.general('no BSP map found')
+ bsp_script = opts.defaults.get(bsp)
+ if not bsp_script:
+ raise error.general('BSP script not found: %s' % (bsp))
+ bsp_config = opts.defaults.expand(opts.defaults[bsp])
+ report_mode = opts.find_arg('--report-mode')
+ if report_mode:
+ if report_mode[1] != 'failures' and \
+ report_mode[1] != 'all' and \
+ report_mode[1] != 'none':
+ raise error.general('invalid report mode')
+ report_mode = report_mode[1]
+ else:
+ report_mode = 'failures'
+ executables = find_executables(opts.params())
+ if len(executables) == 0:
+ raise error.general('no executbles supplied')
+ start_time = datetime.datetime.now()
+ total = len(executables)
+ reports = report.report(total)
+ invalid_tests = opts.defaults['invalid_tests']
+ if invalid_tests:
+ reports.set_invalid_tests([l.strip() for l in invalid_tests.splitlines()])
+ reporting = 1
+ jobs = int(opts.jobs(opts.defaults['_ncpus']))
+ exe = 0
+ tests = []
+ finished = []
+ if jobs > len(executables):
+ jobs = len(executables)
+ while exe < total or len(tests) > 0:
+ if exe < total and len(tests) < jobs:
+ tst = test_run(exe + 1, total, reports,
+ executables[exe],
+ rtems_tools, bsp, bsp_config,
+ opts)
+ exe += 1
+ tests += [tst]
+ if job_trace:
+ _job_trace(tst, 'create',
+ total, exe, tests, reporting)
+ tst.run()
+ else:
+ dead = [t for t in tests if not t.is_alive()]
+ tests[:] = [t for t in tests if t not in dead]
+ for tst in dead:
+ if job_trace:
+ _job_trace(tst, 'dead',
+ total, exe, tests, reporting)
+ finished += [tst]
+ tst.reraise()
+ del dead
+ if len(tests) >= jobs or exe >= total:
+ time.sleep(0.250)
+ if len(finished):
+ reporting = report_finished(reports,
+ report_mode,
+ reporting,
+ finished,
+ job_trace)
+ finished_time = datetime.datetime.now()
+ reporting = report_finished(reports, report_mode,
+ reporting, finished, job_trace)
+ if reporting < total:
+ log.warning('finished jobs does match: %d' % (reporting))
+ report_finished(reports, report_mode, -1, finished, job_trace)
+ reports.summary()
+ end_time = datetime.datetime.now()
+ log.notice('Testing time: %s' % (str(end_time - start_time)))
+ except error.general, gerr:
+ print gerr
+ sys.exit(1)
+ except error.internal, ierr:
+ print ierr
+ sys.exit(1)
+ except error.exit, eerr:
+ sys.exit(2)
+ except KeyboardInterrupt:
+ if opts.find_arg('--stacktrace'):
+ print '}} dumping:', threading.active_count()
+ for t in threading.enumerate():
+ print '}} ', t.name
+ print stacktraces()
+ log.notice('abort: user terminated')
+ sys.exit(1)
+ finally:
+ console.restore(stdtty)
+ sys.exit(0)
+
+if __name__ == "__main__":
+ run()
diff --git a/tester/rt/version.py b/tester/rt/version.py
new file mode 100644
index 0000000..7c82de3
--- /dev/null
+++ b/tester/rt/version.py
@@ -0,0 +1,48 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Manage paths locally. The internally the path is in Unix or shell format and
+# we convert to the native format when performing operations at the Python
+# level. This allows macro expansion to work.
+#
+
+major = 0
+minor = 2
+revision = 0
+
+def str():
+ return '%d.%d.%d'% (major, minor, revision)
+
+if __name__ == '__main__':
+ print 'major = %d' % (major)
+ print 'minor = %d' % (minor)
+ print 'revision = %d' % (revision)
+ print 'Version: %s' % (str())
diff --git a/tester/rtems-test b/tester/rtems-test
new file mode 100755
index 0000000..53c81cd
--- /dev/null
+++ b/tester/rtems-test
@@ -0,0 +1,42 @@
+#! /usr/bin/env python
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2013 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+import sys, os
+base = os.path.dirname(os.path.abspath(sys.argv[0]))
+parent = os.path.dirname(base)
+sys.path = [base, parent] + sys.path
+
+try:
+ import rt.test
+ rt.test.run()
+except ImportError:
+ print >> sys.stderr, "Incorrect RTEMS Tools installation"
+ sys.exit(1)
diff --git a/tester/rtems/testing/bsps/mcf5235.mc b/tester/rtems/testing/bsps/mcf5235.mc
new file mode 100644
index 0000000..f95fffb
--- /dev/null
+++ b/tester/rtems/testing/bsps/mcf5235.mc
@@ -0,0 +1,63 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# The Xilinx Zync ZC706 board connected via OpenOCD and a JTAG pod. The console
+# is connected to a tty device.
+#
+[global]
+bsp: none, none, 'mcf5235'
+jobs: none, none, '1'
+
+[mcf5235]
+mcf5235: none, none, '%{_rtscripts}/gdb.cfg'
+mcf5235_arch: none, none, 'm68k'
+bsp_tty_dev: none, none, '/dev/cuaU2'
+bsp_tty_settings: none, none, 'B19200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,~CLOCAL,VMIN=1,VTIME=2'
+gdb_script: none, none, 'mcf5235_gdb_script'
+mcf5235_gdb_script: none, none, '''target remote | m68k-bdm-gdbserver pipe 003-005
+ thb *0xffe254c0
+ continue
+ load
+ b bsp_reset
+ continue'''
diff --git a/tester/rtems/testing/bsps/realview_pbx_a9_qemu.mc b/tester/rtems/testing/bsps/realview_pbx_a9_qemu.mc
new file mode 100644
index 0000000..5a748c7
--- /dev/null
+++ b/tester/rtems/testing/bsps/realview_pbx_a9_qemu.mc
@@ -0,0 +1,53 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# The Realview PBX A9 BSP.
+#
+[global]
+bsp: none, none, 'realview_pbx_a9_qemu'
+
+[realview_pbx_a9_qemu]
+realview_pbx_a9_qemu: none, none, '%{_rtscripts}/qemu.cfg'
+realview_pbx_a9_qemu_arch: none, none, 'arm'
+realview_pbx_a9_qemu_opts: none, none, '-no-reboot -serial /dev/null -serial mon:stdio -net none -nographic -M xilinx-zynq-a9 -m 256M'
diff --git a/tester/rtems/testing/bsps/sis-run.mc b/tester/rtems/testing/bsps/sis-run.mc
new file mode 100644
index 0000000..cbfcd27
--- /dev/null
+++ b/tester/rtems/testing/bsps/sis-run.mc
@@ -0,0 +1,54 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# The SIS BSP
+#
+[global]
+bsp: none, none, 'sis'
+
+[sis]
+sis: none, none, '%{_rtscripts}/run.cfg'
+sis_arch: none, none, 'sparc'
+bsp_run_cmd: none, none, '%{rtems_tools}/%{bsp_arch}-rtems%{rtems_version}-run'
+bsp_run_opts: none, none, '-a -nouartrx'
diff --git a/tester/rtems/testing/bsps/sis.mc b/tester/rtems/testing/bsps/sis.mc
new file mode 100644
index 0000000..ca84acd
--- /dev/null
+++ b/tester/rtems/testing/bsps/sis.mc
@@ -0,0 +1,56 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# The SIS BSP
+#
+[global]
+bsp: none, none, 'sis'
+
+[sis]
+sis: none, none, '%{_rtscripts}/gdb.cfg'
+sis_arch: none, none, 'sparc'
+gdb_script: none, none, 'sis_gdb_script'
+sis_gdb_script: none, none, '''target sim
+ load
+ run'''
diff --git a/tester/rtems/testing/bsps/xilinx_zynq_a9_qemu.mc b/tester/rtems/testing/bsps/xilinx_zynq_a9_qemu.mc
new file mode 100644
index 0000000..22c2a88
--- /dev/null
+++ b/tester/rtems/testing/bsps/xilinx_zynq_a9_qemu.mc
@@ -0,0 +1,54 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# The Xilinx Zynq A9 QEMU BSP
+#
+[global]
+bsp: none, none, 'xilinx_zynq_a9_qemu'
+
+[xilinx_zynq_a9_qemu]
+xilinx_zynq_a9_qemu: none, none, '%{_rtscripts}/run.cfg'
+xilinx_zynq_a9_qemu_arch: none, none, 'arm'
+bsp_run_cmd: none, none, 'qemu-system-arm'
+bsp_run_opts: none, none, '-no-reboot -serial null -serial mon:stdio -nographic -net none -M xilinx-zynq-a9 -m 256M -kernel'
diff --git a/tester/rtems/testing/bsps/xilinx_zynq_a9_qemu_smp.mc b/tester/rtems/testing/bsps/xilinx_zynq_a9_qemu_smp.mc
new file mode 100644
index 0000000..bdd2ce7
--- /dev/null
+++ b/tester/rtems/testing/bsps/xilinx_zynq_a9_qemu_smp.mc
@@ -0,0 +1,55 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# The Xilinx Zynq A9 QEMU BSP
+#
+[global]
+bsp: none, none, 'xilinx_zynq_a9_qemu'
+
+[xilinx_zynq_a9_qemu]
+xilinx_zynq_a9_qemu: none, none, '%{_rtscripts}/run.cfg'
+xilinx_zynq_a9_qemu_arch: none, none, 'arm'
+bsp_run_cmd: none, none, 'qemu-system-arm'
+bsp_run_opts: none, none, '-no-reboot -serial null -serial mon:stdio -nographic -net none -M xilinx-zynq-a9 -m 256M -smp cpus=2 -kernel'
+jobs: none, none, 'half'
diff --git a/tester/rtems/testing/bsps/xilinx_zynq_zc706.mc b/tester/rtems/testing/bsps/xilinx_zynq_zc706.mc
new file mode 100644
index 0000000..fc427ff
--- /dev/null
+++ b/tester/rtems/testing/bsps/xilinx_zynq_zc706.mc
@@ -0,0 +1,65 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# The Xilinx Zync ZC706 board connected via OpenOCD and a JTAG pod. The console
+# is connected to a tty device.
+#
+[global]
+bsp: none, none, 'xilinx_zynq_zc706'
+jobs: none, none, '1'
+
+[xilinx_zynq_zc706]
+xilinx_zynq_zc706: none, none, '%{_rtscripts}/gdb.cfg'
+xilinx_zynq_zc706_arch: none, none, 'arm'
+#bsp_tty_dev: none, none, '/dev/cuaU0'
+bsp_tty_dev: none, none, '/dev/cu.SLAB_USBtoUART'
+gdb_script: none, none, 'xilinx_zynq_zc706_gdb_script'
+xilinx_zynq_zc706_gdb_script: none, none, '''target remote kaka:3333
+mon load_image /home/chris/development/si/work/hydra/boot/xilinx-zynq-fsbl/build/arm-rtems4.11-xilinx_zynq_zc706/hydra-fsbl.elf 0 elf
+ mon resume 0
+ mon sleep 4000
+ mon halt
+ load
+ b bsp_reset
+ continue'''
diff --git a/tester/rtems/testing/console.cfg b/tester/rtems/testing/console.cfg
new file mode 100644
index 0000000..c936e5c
--- /dev/null
+++ b/tester/rtems/testing/console.cfg
@@ -0,0 +1,60 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Consoles
+#
+# The rtems-test command can use a number of consoles. This file
+# manages the BSP and user configuration of the console.
+#
+
+#
+# Backends can force the console to STDIO and igore any user settings.
+#
+%if %{defined console_stdio}
+ %if %{defined console_user_tty}
+ %warning command line TTY setting ignored
+ %endif
+ %console stdio
+%else
+ #
+ # Console is TTY.
+ #
+ %if %{defined bsp_tty_dev}
+ %define tty_dev %{bsp_tty_dev}
+ %define tty_defaults B115200,~BRKINT,IGNBRK,IGNCR,~ICANON,~ISIG,~IEXTEN,~ECHO,CLOCAL,~CRTSCTS,VMIN=1,VTIME=2
+ %if %{defined bsp_tty_settings}
+ %define tty_settings %{bsp_tty_settings}
+ %else
+ %define tty_settings %{tty_defaults}
+ %endif
+ %console tty %{tty_dev} %{tty_settings}
+ %endif
+%endif
diff --git a/tester/rtems/testing/defaults.mc b/tester/rtems/testing/defaults.mc
new file mode 100644
index 0000000..bf220f3
--- /dev/null
+++ b/tester/rtems/testing/defaults.mc
@@ -0,0 +1,127 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# Global defaults
+#
+[global]
+
+# Nothing
+nil: none, none, ''
+
+# Paths
+_topdir: dir, required, '%{_cwd}'
+_docdir: dir, none, '%{_defaultdocdir}'
+_tmppath: dir, none, '%{_topdir}/build/tmp'
+_tmproot: dir, none, '%{_tmppath}/rt/%{_bset}'
+_datadir: dir, none, '%{_prefix}/share'
+_defaultdocdir: dir, none, '%{_prefix}/share/doc'
+_exeext: none, none, ''
+_exec_prefix: dir, none, '%{_prefix}'
+_bindir: dir, none, '%{_exec_prefix}/bin'
+_sbindir: dir, none, '%{_exec_prefix}/sbin'
+_libexecdir: dir, none, '%{_exec_prefix}/libexec'
+_datarootdir: dir, none, '%{_prefix}/share'
+_datadir: dir, none, '%{_datarootdir}'
+_sysconfdir: dir, none, '%{_prefix}/etc'
+_sharedstatedir: dir, none, '%{_prefix}/com'
+_localstatedir: dir, none, '%{prefix}/var'
+_includedir: dir, none, '%{_prefix}/include'
+_lib: dir, none, 'lib'
+_libdir: dir, none, '%{_exec_prefix}/%{_lib}'
+_libexecdir: dir, none, '%{_exec_prefix}/libexec'
+_mandir: dir, none, '%{_datarootdir}/man'
+_infodir: dir, none, '%{_datarootdir}/info'
+_localedir: dir, none, '%{_datarootdir}/locale'
+_localedir: dir, none, '%{_datadir}/locale'
+_localstatedir: dir, none, '%{_prefix}/var'
+_prefix: dir, none, '%{_usr}'
+_usr: dir, none, '/usr/local'
+_usrsrc: dir, none, '%{_usr}/src'
+_var: dir, none, '/usr/local/var'
+_varrun: dir, none, '%{_var}/run'
+
+# Defaults, override in platform specific modules.
+__arch_install_post: exe, none, '%{nil}'
+__bash: exe, optional, '/bin/bash'
+__bzip2: exe, required, '/usr/bin/bzip2'
+__cat: exe, required, '/bin/cat'
+__chgrp: exe, required, '/usr/bin/chgrp'
+__chmod: exe, required, '/bin/chmod'
+__chown: exe, required, '/usr/sbin/chown'
+__cp: exe, required, '/bin/cp'
+__git: exe, required, '/usr/bin/git'
+__grep: exe, required, '/usr/bin/grep'
+__gzip: exe, required, '/usr/bin/gzip'
+__id: exe, required, '/usr/bin/id'
+__id_u: exe, none, '%{__id} -u'
+__ln_s: exe, none, 'ln -s'
+__make: exe, required, 'make'
+__mkdir: exe, required, '/bin/mkdir'
+__mkdir_p: exe, none, '/bin/mkdir -p'
+__mv: exe, required, '/bin/mv'
+__patch_bin: exe, required, '/usr/bin/patch'
+__patch_opts: none, none, '%{nil}'
+__patch: exe, none, '%{__patch_bin} %{__patch_opts}'
+__svn: exe, optional, '/usr/bin/svn'
+__rm: exe, required, '/bin/rm'
+__rmfile: exe, none, '%{__rm} -f'
+__rmdir: exe, none, '%{__rm} -rf'
+__sed: exe, required, '/usr/bin/sed'
+__sh: exe, required, '/bin/sh'
+__tar: exe, required, '/usr/bin/tar'
+__tar_extract: exe, none, '%{__tar} -xvvf'
+__touch: exe, required, '/usr/bin/touch'
+__unzip: exe, required, '/usr/bin/unzip'
+__xz: exe, required, '/usr/bin/xz'
+
+# Default settings
+_target: none, none, '%{nil}'
+
+# Paths
+_rtbase: none, none, '%{_rtdir}'
+_rttesting: none, none, '%{_rtbase}/rtems/testing'
+_configdir: none, none, '%{_rtbase}/config:%{_rttesting}'
+
+# Include the testing macros.
+%include %{_rttesting}/testing.mc
diff --git a/tester/rtems/testing/gdb.cfg b/tester/rtems/testing/gdb.cfg
new file mode 100644
index 0000000..b680dba
--- /dev/null
+++ b/tester/rtems/testing/gdb.cfg
@@ -0,0 +1,60 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Run
+#
+# Use a run command to run the executable. The run command is a GDB based
+# simulator that is packaged as a single command that executes the program.
+#
+
+%include %{_configdir}/base.cfg
+%include %{_configdir}/checks.cfg
+
+#
+# Console.
+#
+%include %{_configdir}/console.cfg
+
+#
+# RTEMS version
+#
+%include %{_rtdir}/rtems/version.cfg
+
+#
+# GDB executable
+#
+%define gdb_cmd %{rtems_tools}/%{bsp_arch}-rtems%{rtems_version}-gdb
+
+#
+# GDB, pass the GDB command, the text executable and the macro label
+# for the script.
+#
+%gdb %{gdb_cmd} %{test_executable} %{gdb_script}
diff --git a/tester/rtems/testing/qemu.cfg b/tester/rtems/testing/qemu.cfg
new file mode 100644
index 0000000..e15f058
--- /dev/null
+++ b/tester/rtems/testing/qemu.cfg
@@ -0,0 +1,60 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# QEMU
+#
+# Use a qemu command to run the executable in the qemu simulator.
+#
+
+%include %{_configdir}/base.cfg
+%include %{_configdir}/checks.cfg
+
+#
+# Console.
+#
+%define console_stdio
+%include %{_configdir}/console.cfg
+
+#
+# RTEMS version
+#
+%include %{_rtdir}/rtems/version.cfg
+
+#
+# Qemu executable
+#
+%define qemu_cmd qemu-system-%{bsp_arch}
+%define qemu_opts %{bsp_opts}
+
+#
+# Executable
+#
+%execute %{qemu_cmd} %{qemu_opts} -kernel %{test_executable}
diff --git a/tester/rtems/testing/run.cfg b/tester/rtems/testing/run.cfg
new file mode 100644
index 0000000..f7b21d7
--- /dev/null
+++ b/tester/rtems/testing/run.cfg
@@ -0,0 +1,70 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# Run
+#
+# Use a run command to run the executable. The run command is a GDB based
+# simulator that is packaged as a single command that executes the program.
+#
+
+%include %{_configdir}/base.cfg
+%include %{_configdir}/checks.cfg
+
+#
+# Console.
+#
+%define console_stdio
+%include %{_configdir}/console.cfg
+
+#
+# RTEMS version
+#
+%include %{_rtdir}/rtems/version.cfg
+
+#
+# Run executable.
+#
+%ifn %{defined bsp_run_cmd}
+ %error No BSP run command provied.
+%endif
+%ifn %{defined bsp_run_opts}
+ %define bsp_run_opts %{nil}
+%endif
+%define run_cmd %{bsp_run_cmd}
+%define run_opts %{bsp_run_opts}
+
+#
+# Executable
+#
+%ifn %{defined test_executable_opts}
+ %define test_executable_opts %{nil}
+%endif
+%execute %{run_cmd} %{run_opts} %{test_executable} %{test_executable_opts}
diff --git a/tester/rtems/testing/testing.mc b/tester/rtems/testing/testing.mc
new file mode 100644
index 0000000..77f8419
--- /dev/null
+++ b/tester/rtems/testing/testing.mc
@@ -0,0 +1,57 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+# key: type, attribute, value
+# type : none, dir, exe, triplet
+# attribute: none, required, optional
+# value : 'single line', '''multi line'''
+#
+
+#
+# Global defaults
+#
+[global]
+
+# Paths
+_rtbase: none, none, '%{_rtdir}'
+_rtscripts: none, none, '%{_rtbase}/rtems/testing'
+
+# Defaults
+timeout: none, none, '180'
+
+# Tests detected as invalid that are valid
+invalid_tests: none, none, '''minimum.exe'''
diff --git a/tester/rtems/version.cfg b/tester/rtems/version.cfg
new file mode 100644
index 0000000..46f9939
--- /dev/null
+++ b/tester/rtems/version.cfg
@@ -0,0 +1,35 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj@rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# RTEMS Version
+#
+
+%define rtems_version 4.11