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

4.105
Last change on this file since 6f8b07c was 6f8b07c, checked in by Chris Johns <chrisj@…>, on 03/14/16 at 03:59:11

rtemstoolkit: Fix execute's writer thread to not eval() the input.

The conversion to Python3 added an eval() call which is wrong.

Fix the spelling in execute.

Fix labels in the tester gdb locking.

Check the debug-trace arguments.

Close #2642.

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