source: rtems-tools/tester/rt/gdb.py @ 4001a74

4.11
Last change on this file since 4001a74 was 4001a74, checked in by Chris Johns <chrisj@…>, on 03/02/16 at 09:54:06

Update rtems-tool to support Python 2 and 3.

Add solaris and netbsd.

Close #2619.

  • Property mode set to 100644
File size: 10.8 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013-2016 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
35from __future__ import print_function
36
37import os
38import sys
39import termios
40import threading
41
42try:
43    import queue
44except ImportError:
45    import Queue
46    queue = Queue
47
48from rtemstoolkit import error
49from rtemstoolkit import execute
50from rtemstoolkit import options
51from rtemstoolkit import path
52
53from . import console
54from . import pygdb
55
56#
57# The MI parser needs a global lock. It has global objects.
58#
59mi_lock = threading.Lock()
60
61class gdb(object):
62    '''RTEMS Testing GDB base.'''
63
64    def __init__(self, bsp_arch, bsp, trace = False, mi_trace = False):
65        self.trace = trace
66        self.mi_trace = mi_trace
67        self.lock_trace = False
68        self.lock = threading.RLock()
69        self.script = None
70        self.script_line = 0
71        self.bsp = bsp
72        self.bsp_arch = bsp_arch
73        self.output = None
74        self.gdb_console = None
75        self.input = queue.Queue()
76        self.commands = queue.Queue()
77        self.process = None
78        self.state = {}
79        self.running = False
80        self.breakpoints = {}
81        self.output = None
82        self.output_buffer = ''
83        self.lc = 0
84
85    def _lock(self, msg):
86        if self.lock_trace:
87            print('|[   LOCK:%s ]|' % (msg))
88        self.lock.acquire()
89
90    def _unlock(self, msg):
91        if self.lock_trace:
92            print('|] UNLOCK:%s [|' % (msg))
93        self.lock.release()
94
95    def _mi_lock(self):
96        mi_lock.acquire()
97
98    def _mi_unlock(self):
99        mi_lock.release()
100
101    def _put(self, text):
102        if self.trace:
103            print(')))', text)
104        self.commands.put(text)
105
106    def _input_commands(self):
107        if self.commands.empty():
108            return False
109        try:
110            if self.trace:
111                print('... input empty ', self.input.empty())
112            if self.input.empty():
113                line = self.commands.get(block = False)
114                if self.trace:
115                    print('+++', line)
116                self.input.put(line)
117        except:
118            pass
119        return True
120
121    def _reader(self, line):
122        self._lock('_reader')
123        if self.trace:
124            print('<<<', line)
125        try:
126            self.lc += 1
127            if line.startswith('(gdb)'):
128                if self.trace:
129                    print('^^^ (gdb)')
130                if not self._input_commands():
131                    self.gdb_expect()
132                    self._input_commands()
133            else:
134                self.gdb_parse(line)
135        finally:
136            self._unlock('_reader')
137
138    def _writer(self):
139        try:
140            try:
141                self._lock('_open')
142                try:
143                    if self.process is None:
144                        return None
145                finally:
146                    self._unlock('_open')
147                line = self.input.get(timeout = 0.5)
148                if self.trace:
149                    print('>>> input: queue=%d' % (self.input.qsize()), line)
150            except queue.Empty:
151                return True
152            if line is None:
153                return None
154            return line + os.linesep
155        except:
156            if self.trace:
157                print('writer exception')
158            pass
159        if self.trace:
160            print('writer closing')
161        return False
162
163    def _timeout(self):
164        self._lock('_timeout')
165        try:
166            if self.output:
167                self.output('*** TIMEOUT TIMEOUT')
168                self._gdb_quit(backtrace = True)
169        finally:
170            self._unlock('_timeout')
171
172    def _cleanup(self, proc):
173        self._lock('_cleanup')
174        try:
175            self._put(None)
176        finally:
177            self._unlock('_cleanup')
178
179    def _gdb_quit(self, backtrace = False):
180        self._lock('_gdb_quit')
181        try:
182            self._put('-exec-interrupt')
183            if backtrace:
184                self._put('bt')
185            self._put('quit')
186            self._put('None')
187            if self.script:
188                self.script_line = len(self.script)
189        finally:
190            self._unlock('_gdb_quit')
191
192    def open(self, command, executable,
193             output, gdb_console, script = None, tty = None,
194             timeout = 300):
195        self._lock('_open')
196        try:
197            cmds = execute.arg_list(command) + ['-i=mi',
198                                                '--nx',
199                                                '--quiet']
200            if tty:
201                cmds += ['--tty=%s' % tty]
202            if executable:
203                cmds += [executable]
204            self.output = output
205            self.gdb_console = gdb_console
206            self.script = script
207            self.running = False
208            self.process = execute.execute(output = self._reader,
209                                           input = self._writer,
210                                           cleanup = self._cleanup)
211        finally:
212            self._unlock('_open')
213        try:
214            self.gdb_console('gdb: %s' % (' '.join(cmds)))
215            ec, proc = self.process.open(cmds, timeout = (timeout, self._timeout))
216            if self.trace:
217                print('gdb done', ec)
218            if ec > 0:
219                raise error.general('gdb exec: %s: %s' % (cmds[0], os.strerror(ec)))
220        except:
221            raise
222        self._lock('_open')
223        try:
224            self.process = None
225        finally:
226            self._unlock('_open')
227
228    def gdb_expect(self):
229        if self.trace:
230            print('}}} gdb-expect')
231        if self.process and not self.running and self.script is not None:
232            if self.script_line == len(self.script):
233                self._put(None)
234            else:
235                if self.script_line == 0:
236                    self._put('-gdb-set confirm no')
237                    self._put('-data-list-register-names')
238                line = self.script[self.script_line]
239                self.script_line += 1
240                self._put(line)
241        else:
242            self._put(line)
243
244    def gdb_parse(self, lines):
245        try:
246            self._mi_lock()
247            try:
248                if self.mi_trace:
249                    print('mi-data:', lines)
250                rec = pygdb.mi_parser.process(lines)
251            finally:
252                self._mi_unlock()
253            if self.mi_trace:
254                print('mi-rec:', rec)
255            if rec.record_type == 'result':
256                if rec.type == 'result':
257                    if rec.class_ == 'error':
258                        self._gdb_quit()
259                    elif 'register_names' in dir(rec.result):
260                        self.register_names = rec.result.register_names
261                    elif 'register_values' in dir(rec.result):
262                        self.register_values = rec.result.register_values
263                elif rec.type == 'exec':
264                    if rec.class_ == 'running':
265                        if self.trace:
266                            print('*** running')
267                        self._put('')
268                        self.running = True
269                    elif rec.class_ == 'stopped':
270                        if self.trace:
271                            print('*** stopped')
272                        self.running = False
273                        #self._put('-data-list-register-values')
274                elif rec.type == 'breakpoint':
275                    if rec.class_ == 'breakpoint-created':
276                        self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
277                    elif rec.class_ == 'breakpoint-modified':
278                        self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
279                    elif rec.class_ == 'breakpoint-deleted':
280                        if rec.result.id in self.breakpoints:
281                            del self.breakpoints[rec.result.id]
282            elif rec.record_type == 'error':
283                self._gdb_quit()
284            elif rec.record_type == 'stream':
285                if rec.type == 'console' or rec.type == 'log':
286                    for line in rec.value.splitlines():
287                        self.gdb_console(line)
288                if rec.type == 'target':
289                    self.output_buffer += rec.value
290                    last_lf = self.output_buffer.rfind('\n')
291                    if last_lf >= 0:
292                        lines = self.output_buffer[:last_lf]
293                        if self.trace:
294                            print('/// console output')
295                        for line in lines.splitlines():
296                            self.output(line)
297                        self.output_buffer = self.output_buffer[last_lf + 1:]
298        except:
299            if self.trace:
300                print('/// console output')
301            for line in lines.splitlines():
302                self.output(line)
303
304if __name__ == "__main__":
305    stdtty = console.save()
306    try:
307        def output(text):
308            print(']', text)
309        def gdb_console(text):
310            print('>', text)
311        script = ['target sim']
312        if len(sys.argv) > 1:
313            executable = sys.argv[1]
314            script += ['load',
315                       'run',
316                       'info reg',
317                       '-stack-list-frames',
318                       '-stack-list-arguments --all-values']
319        else:
320            executable = None
321        script += ['quit']
322        g = gdb('sparc', 'sis', mi_trace = True)
323        g.open('sparc-rtems4.11-gdb', executable, output, gdb_console, script)
324    except:
325        console.restore(stdtty)
326        raise
327    finally:
328        console.restore(stdtty)
Note: See TracBrowser for help on using the repository browser.