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

5
Last change on this file since e058db0 was e058db0, checked in by Chris Johns <chrisj@…>, on 11/07/18 at 03:55:20

python: Provide support to select a valid python version.

  • Update imports after wrapping the code.
  • Fix python3 issues.
  • Fix config path issues for in repo and install runs.

Closes #3537

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