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

5
Last change on this file since 087be8c was ab57e79, checked in by Chris Johns <chrisj@…>, on 04/24/17 at 23:32:18

rtems-test: Fix gdb bug.

  • Property mode set to 100644
File size: 11.2 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 kill(self):
235        self._lock('_open')
236        try:
237            if self.process:
238                self.process.kill()
239            self.process = None
240        finally:
241            self._unlock('_open')
242
243    def gdb_expect(self):
244        if self.trace:
245            print('}}} gdb-expect')
246        if self.process and not self.running and self.script is not None:
247            if self.script_line == len(self.script):
248                self._put(None)
249            else:
250                if self.script_line == 0:
251                    self._put('-gdb-set confirm no')
252                    self._put('-data-list-register-names')
253                line = self.script[self.script_line]
254                self.script_line += 1
255                self._put(line)
256
257    def gdb_parse(self, lines):
258        try:
259            self._mi_lock()
260            try:
261                if self.mi_trace:
262                    print('mi-data:', lines)
263                rec = pygdb.mi_parser.process(lines)
264            finally:
265                self._mi_unlock()
266            if self.mi_trace:
267                print('mi-rec:', rec)
268            if rec.record_type == 'result':
269                if rec.type == 'result':
270                    if rec.class_ == 'error':
271                        self._gdb_quit()
272                    elif 'register_names' in dir(rec.result):
273                        self.register_names = rec.result.register_names
274                    elif 'register_values' in dir(rec.result):
275                        self.register_values = rec.result.register_values
276                elif rec.type == 'exec':
277                    if rec.class_ == 'running':
278                        if self.trace:
279                            print('*** running')
280                        self._put('')
281                        self.running = True
282                    elif rec.class_ == 'stopped':
283                        if self.trace:
284                            print('*** stopped')
285                        self.running = False
286                        #self._put('-data-list-register-values')
287                elif rec.type == 'breakpoint':
288                    if rec.class_ == 'breakpoint-created':
289                        self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
290                    elif rec.class_ == 'breakpoint-modified':
291                        self.breakpoints[rec.result.bkpt.number] = rec.result.bkpt
292                    elif rec.class_ == 'breakpoint-deleted':
293                        if rec.result.id in self.breakpoints:
294                            del self.breakpoints[rec.result.id]
295            elif rec.record_type == 'error':
296                self._gdb_quit()
297            elif rec.record_type == 'stream':
298                if rec.type == 'console' or rec.type == 'log':
299                    for line in rec.value.splitlines():
300                        self.gdb_console(line)
301                if rec.type == 'target':
302                    self.output_buffer += rec.value
303                    last_lf = self.output_buffer.rfind('\n')
304                    if last_lf >= 0:
305                        lines = self.output_buffer[:last_lf]
306                        if self.trace:
307                            print('/// console output')
308                        for line in lines.splitlines():
309                            self.output(line)
310                        self.output_buffer = self.output_buffer[last_lf + 1:]
311        except:
312            if self.trace:
313                print('/// console output')
314            for line in lines.splitlines():
315                self.output(line)
316
317if __name__ == "__main__":
318    stdtty = console.save()
319    try:
320        def output(text):
321            print(']', text)
322        def gdb_console(text):
323            print('>', text)
324        script = ['target sim']
325        if len(sys.argv) > 1:
326            executable = sys.argv[1]
327            script += ['load',
328                       'run',
329                       'info reg',
330                       '-stack-list-frames',
331                       '-stack-list-arguments --all-values']
332        else:
333            executable = None
334        script += ['quit']
335        g = gdb('sparc', 'sis', mi_trace = True)
336        g.open('sparc-rtems4.11-gdb', executable, output, gdb_console, script)
337    except:
338        console.restore(stdtty)
339        raise
340    finally:
341        console.restore(stdtty)
Note: See TracBrowser for help on using the repository browser.