source: rtems-tools/tester/rt/gdb.py @ 9600c39

4.104.115
Last change on this file since 9600c39 was 9600c39, checked in by Chris Johns <chrisj@…>, on 02/08/15 at 07:14:16

Fixes to the run the waf built tests when installed.

  • Property mode set to 100644
File size: 10.7 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013-2014 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# 1. Redistributions of source code must retain the above copyright notice,
12# this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# RTEMS Testing GDB Interface
33#
34
35import os
36import Queue
37import sys
38import termios
39import threading
40
41from rtemstoolkit import error
42from rtemstoolkit import execute
43from rtemstoolkit import options
44from rtemstoolkit import path
45
46import console
47import pygdb
48
49#
50# The MI parser needs a global lock. It has global objects.
51#
52mi_lock = threading.Lock()
53
54class gdb(object):
55    '''RTEMS Testing GDB base.'''
56
57    def __init__(self, bsp_arch, bsp, trace = False, mi_trace = False):
58        self.trace = trace
59        self.mi_trace = mi_trace
60        self.lock_trace = False
61        self.lock = threading.RLock()
62        self.script = None
63        self.script_line = 0
64        self.bsp = bsp
65        self.bsp_arch = bsp_arch
66        self.output = None
67        self.gdb_console = None
68        self.input = Queue.Queue()
69        self.commands = Queue.Queue()
70        self.process = None
71        self.state = {}
72        self.running = False
73        self.breakpoints = {}
74        self.output = None
75        self.output_buffer = ''
76        self.lc = 0
77
78    def _lock(self, msg):
79        if self.lock_trace:
80            print '|[   LOCK:%s ]|' % (msg)
81        self.lock.acquire()
82
83    def _unlock(self, msg):
84        if self.lock_trace:
85            print '|] UNLOCK:%s [|' % (msg)
86        self.lock.release()
87
88    def _mi_lock(self):
89        mi_lock.acquire()
90
91    def _mi_unlock(self):
92        mi_lock.release()
93
94    def _put(self, text):
95        if self.trace:
96            print ')))', text
97        self.commands.put(text)
98
99    def _input_commands(self):
100        if self.commands.empty():
101            return False
102        try:
103            if self.trace:
104                print '... input empty ', self.input.empty()
105            if self.input.empty():
106                line = self.commands.get(block = False)
107                if self.trace:
108                    print '+++', line
109                self.input.put(line)
110        except:
111            pass
112        return True
113
114    def _reader(self, line):
115        self._lock('_reader')
116        if self.trace:
117            print '<<<', line
118        try:
119            self.lc += 1
120            if line.startswith('(gdb)'):
121                if self.trace:
122                    print '^^^ (gdb)'
123                if not self._input_commands():
124                    self.gdb_expect()
125                    self._input_commands()
126            else:
127                self.gdb_parse(line)
128        finally:
129            self._unlock('_reader')
130
131    def _writer(self):
132        try:
133            try:
134                self._lock('_open')
135                try:
136                    if self.process is None:
137                        return None
138                finally:
139                    self._unlock('_open')
140                line = self.input.get(timeout = 0.5)
141                if self.trace:
142                    print '>>> input: queue=%d' % (self.input.qsize()), line
143            except Queue.Empty:
144                return True
145            if line is None:
146                return None
147            return line + os.linesep
148        except:
149            if self.trace:
150                print 'writer exception'
151            pass
152        if self.trace:
153            print 'writer closing'
154        return False
155
156    def _timeout(self):
157        self._lock('_timeout')
158        try:
159            if self.output:
160                self.output('*** TIMEOUT TIMEOUT')
161                self._gdb_quit(backtrace = True)
162        finally:
163            self._unlock('_timeout')
164
165    def _cleanup(self, proc):
166        self._lock('_cleanup')
167        try:
168            self._put(None)
169        finally:
170            self._unlock('_cleanup')
171
172    def _gdb_quit(self, backtrace = False):
173        self._lock('_gdb_quit')
174        try:
175            self._put('-exec-interrupt')
176            if backtrace:
177                self._put('bt')
178            self._put('quit')
179            self._put('None')
180            if self.script:
181                self.script_line = len(self.script)
182        finally:
183            self._unlock('_gdb_quit')
184
185    def open(self, command, executable,
186             output, gdb_console, script = None, tty = None,
187             timeout = 300):
188        self._lock('_open')
189        try:
190            cmds = execute.arg_list(command) + ['-i=mi',
191                                                '--nx',
192                                                '--quiet']
193            if tty:
194                cmds += ['--tty=%s' % tty]
195            if executable:
196                cmds += [executable]
197            self.output = output
198            self.gdb_console = gdb_console
199            self.script = script
200            self.running = False
201            self.process = execute.execute(output = self._reader,
202                                           input = self._writer,
203                                           cleanup = self._cleanup)
204        finally:
205            self._unlock('_open')
206        try:
207            self.gdb_console('gdb: %s' % (' '.join(cmds)))
208            ec, proc = self.process.open(cmds, timeout = (timeout, self._timeout))
209            if self.trace:
210                print 'gdb done', ec
211            if ec > 0:
212                raise error.general('gdb exec: %s: %s' % (cmds[0], os.strerror(ec)))
213        except:
214            raise
215        self._lock('_open')
216        try:
217            self.process = None
218        finally:
219            self._unlock('_open')
220
221    def gdb_expect(self):
222        if self.trace:
223            print '}}} gdb-expect'
224        if self.process and not self.running and self.script is not None:
225            if self.script_line == len(self.script):
226                self._put(None)
227            else:
228                if self.script_line == 0:
229                    self._put('-gdb-set confirm no')
230                    self._put('-data-list-register-names')
231                line = self.script[self.script_line]
232                self.script_line += 1
233                self._put(line)
234        else:
235            self._put(line)
236
237    def gdb_parse(self, lines):
238        try:
239            self._mi_lock()
240            try:
241                if self.mi_trace:
242                    print 'mi-data:', lines
243                rec = pygdb.mi_parser.process(lines)
244            finally:
245                self._mi_unlock()
246            if self.mi_trace:
247                print 'mi-rec:', rec
248            if rec.record_type == 'result':
249                if rec.type == 'result':
250                    if rec.class_ == 'error':
251                        self._gdb_quit()
252                    elif 'register_names' in dir(rec.result):
253                        self.register_names = rec.result.register_names
254                    elif 'register_values' in dir(rec.result):
255                        self.register_values = rec.result.register_values
256                elif rec.type == 'exec':
257                    if rec.class_ == 'running':
258                        if self.trace:
259                            print '*** running'
260                        self._put('')
261                        self.running = True
262                    elif rec.class_ == 'stopped':
263                        if self.trace:
264                            print '*** stopped'
265                        self.running = False
266                        #self._put('-data-list-register-values')
267                elif rec.type == 'breakpoint':
268                    if rec.class_ == 'breakpoint-created':
269                        self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
270                    elif rec.class_ == 'breakpoint-modified':
271                        self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
272                    elif rec.class_ == 'breakpoint-deleted':
273                        if rec.result.id in self.breakpoints:
274                            del self.breakpoints[rec.result.id]
275            elif rec.record_type == 'error':
276                self._gdb_quit()
277            elif rec.record_type == 'stream':
278                if rec.type == 'console' or rec.type == 'log':
279                    for line in rec.value.splitlines():
280                        self.gdb_console(line)
281                if rec.type == 'target':
282                    self.output_buffer += rec.value
283                    last_lf = self.output_buffer.rfind('\n')
284                    if last_lf >= 0:
285                        lines = self.output_buffer[:last_lf]
286                        if self.trace:
287                            print '/// console output'
288                        for line in lines.splitlines():
289                            self.output(line)
290                        self.output_buffer = self.output_buffer[last_lf + 1:]
291        except:
292            if self.trace:
293                print '/// console output'
294            for line in lines.splitlines():
295                self.output(line)
296
297if __name__ == "__main__":
298    stdtty = console.save()
299    try:
300        def output(text):
301            print ']', text
302        def gdb_console(text):
303            print '>', text
304        script = ['target sim']
305        if len(sys.argv) > 1:
306            executable = sys.argv[1]
307            script += ['load',
308                       'run',
309                       'info reg',
310                       '-stack-list-frames',
311                       '-stack-list-arguments --all-values']
312        else:
313            executable = None
314        script += ['quit']
315        g = gdb('sparc', 'sis', mi_trace = True)
316        g.open('sparc-rtems4.11-gdb', executable, output, gdb_console, script)
317    except:
318        console.restore(stdtty)
319        raise
320    finally:
321        console.restore(stdtty)
Note: See TracBrowser for help on using the repository browser.