Пример #1
0
 def __clear(self):
     self.buffer = ''
     self.pending = {} # Pending commands
     
     self.__varnames = {} # Variable names pending
     self.__varname_idx = 0
     
     self.token = 1    # Command token (increments on each command
     self.breakpoints = BreakpointTable(self)
     self.locals = []
     self.vars = GDBVarModel(self)
     self.stack = GDBStackModel(self)
     self.registers = GDBRegisterModel(self)
     self.__lexer = GDBMILexer.GDBMILexer(None)
     self.__parser = GDBMIParser.GDBMIParser(None)
     self.__deleted = []
Пример #2
0
class GDB(wx.EvtHandler):

    def __init__(self, cmd="arm-elf-gdb -n -q -i mi", mi_log=None, console_log=None, target_log=None, log_log=None):
        wx.EvtHandler.__init__(self)
        self.attached = False
        self.state = STOPPED
        
        # Console streams
        self.mi_log = mi_log
        self.console_log = console_log
        self.target_log = target_log
        self.log_log = log_log

        # Parser for GDBMI commands
        self.cmd_string = cmd
        
        self.__clear()
        
    def start(self):
        self.__clear()
        self.subprocess = util.Process(self.cmd_string, start=self.on_start, stdout=self.on_stdout, end=self.on_end)
        self.data_list_register_names()
        #self.cmd('-gdb-set target-async on')
        
    def __clear(self):
        self.buffer = ''
        self.pending = {} # Pending commands
        
        self.__varnames = {} # Variable names pending
        self.__varname_idx = 0
        
        self.token = 1    # Command token (increments on each command
        self.breakpoints = BreakpointTable(self)
        self.locals = []
        self.vars = GDBVarModel(self)
        self.stack = GDBStackModel(self)
        self.registers = GDBRegisterModel(self)
        self.__lexer = GDBMILexer.GDBMILexer(None)
        self.__parser = GDBMIParser.GDBMIParser(None)
        self.__deleted = []
       
    def update(self):
        self.__update_breakpoints()
        self.stack_list_frames()
        self.stack_list_locals()
        self.var_update()
        self.data_list_register_values()

    def parse(self, string):
        '''
        Parse a SINGLE gdb-mi response, returning a GDBMIResponse object
        '''
        self.__parser.gdbmi_error = None
        stream = antlr3.ANTLRStringStream(unicode(string))
        self.__lexer.setCharStream(stream)
        tokens = antlr3.CommonTokenStream(self.__lexer)
        self.__parser.setTokenStream(tokens)
        output = self.__parser.output().response
        if self.__parser.gdbmi_error:
            msg = self.__parser.gdbmi_error.strip() + " : '" + string.strip() + "'\n"
            logging.getLogger('errors').error(msg)
        return output

    @property
    def running(self):
        return self.state == RUNNING
    
    def __console_log(self, txt):
        if self.console_log:
            self.console_log.log(logging.INFO,txt )

    def __target_log(self, txt):
        if self.target_log:
            self.target_log.log(logging.INFO, txt)
    
    def __log_log(self, txt):
        if self.log_log:
            self.log_log.log(logging.INFO, txt )
   
    def __mi_log(self, txt):
        if self.mi_log:
            self.mi_log.log(logging.INFO, txt)

    def on_start(self):
        self.attached = True
        self.post_event(GDBEvent(EVT_GDB_STARTED, self))
    
    def on_end(self):
        self.attached = False
        self.post_event(GDBEvent(EVT_GDB_FINISHED, self))

    def on_stdout(self, line):
        self.__mi_log(line)
        #self.buffer += line
        if line.strip() != '(gdb)':
            response = self.parse(line)
            #wx.CallAfter(self.handle_response, response)
            self.handle_response(response)
            self.buffer = ''
    
    def __on_running(self, record):
        self.state = RUNNING
        self.post_event(GDBEvent(EVT_GDB_RUNNING, self, data=record))
    
    def __on_stopped(self, record):
        self.state = STOPPED
        self.post_event(GDBEvent(EVT_GDB_STOPPED, self, data=record))
        self.update()
        
    def __on_error(self, command, record):
        # We make some corrections to the debugger state based on feedback from error messages
        if "while target is running" in record.msg: 
            self.__on_running(record)
        elif "while target is stopped" in record.msg or "not executing" in record.msg or "not running" in record.msg:
            print "stopping due to ", record.msg
            self.__on_stopped(record)
        elif "connection closed" in record.msg:
            print "The GDB connection was closed unexpectedly"
            self.on_end()
        self.post_event(GDBEvent(EVT_GDB_ERROR, self, data=record.msg))
   
    
    def handle_response(self, response):
        # Deal with the console streams in the response
        for txt in response.console:
            self.__console_log(txt)
        for txt in response.target:
            self.__target_log(txt)
        for txt in response.log:
            self.__log_log(txt)

        results = (response.result, response.exc, response.status, response.notify)
        for result in results:
            command = ''
            if result != None: 
                if result.token:
                    # Call any function setup to be called as a result of this.... result.
                    if result.token in self.pending:
                        command, callback, internal_callback = self.pending[result.token]
                        if callable(internal_callback):
                            print "GDB Calling %s" % function_name(internal_callback)
                            internal_callback(result)
                        if callable(callback):
                            print "GDB Calling %s"  % function_name(callback)
                            callback(result)
                        
                # Post an event on error
                if result.cls == 'error':
                    self.__on_error(command, result)
                elif result.cls == 'stopped':
                    self.__on_stopped(result)
                elif result.cls == 'running':
                    self.__on_running(result)
                else:
                    pass
                    #self.post_event(GDBEvent(EVT_GDB_UPDATE, self, data=result))
        
    def __update_breakpoints(self, data=None):
        self.__cmd('-break-list\n', self.__process_breakpoint_update)
    def __process_breakpoint_update(self, data):
        if hasattr(data, 'BreakpointTable'):
            self.breakpoints.clear()
            for item in data.BreakpointTable.body:
                item = item.get('bkpt', None)
                if item:
                    number = int(item['number'])
                    address = int(item['addr'], 16)
                    fullname = item.get('fullname', '<Unknown File>')
                    file = item.get('file', '<Unknown File>')
                    enabled = True if (item['enabled'].upper() == 'Y' or item['enabled'] == '1') else False
                    line = int(item.get('line', -1))
                    bp = Breakpoint(number, fullname, file, line, enabled=enabled, address=address)
                    self.breakpoints[number] = bp
            self.post_event(GDBEvent(EVT_GDB_UPDATE_BREAKPOINTS, self, data=self.breakpoints))
                        
    def post_event(self, evt):
        #print "Posting %s" % evt
        #wx.PostEvent(self, evt)
        #wx.CallAfter(wx.PostEvent, self, evt)
        self.AddPendingEvent(evt)
        
    def __send(self, data):
        self.__mi_log(data)
        self.subprocess.stdin.write(data)

    def __cmd(self, cmd, callback=None, internal_callback=None):
        if cmd[-1] != '\n':
            cmd += '\n'
        if callback or internal_callback:
            self.pending[self.token] = (cmd.strip(), callback, internal_callback)
            tok = self.token
            self.token += 1
            self.__send(str(tok) + cmd)
        else:
            self.__send(cmd)

    # Utility Stuff
    def command(self, cmd, callback=None):
        self.__cmd('-interpreter-exec console "%s"' % cmd, callback)
   
    def cmd(self, cmd, callback=None):
        self.__cmd(cmd, callback)
    
    def __clear_condition(self, condition, data):
        condition.acquire()
        condition.notify()
        condition.release()
        
    def __dummy(self, data): pass
        
    def __blocking_frameselect(self, frame):
        self.thing = False
        cv = threading.Condition(threading.RLock())
        try: frame = int(frame)
        except: frame = 0
        self.__cmd('-stack-select-frame %d' % int(frame), internal_callback = functools.partial(self.__clear_condition, cv), callback=self.__dummy)
        cv.acquire()
#        cv.wait() # TODO FIX THIS!
        cv.release()
        
    def stack_list_frames(self, callback=None):
        self.__cmd('-stack-list-frames', internal_callback=self.__on_stack_list_frames, callback=callback)
    def __on_stack_list_frames(self, data):
        if hasattr(data, 'stack'):
            self.stack.clear()
            frames = sorted([item['frame'] for item in data.stack], cmp=lambda x,y : cmp(int(x['level']), int(y['level'])))
            for frame in frames:
                level = int(frame['level'])
                addr = int(frame['addr'], 16)
                func = frame.get('func', '')
                fullname = frame.get('fullname', '')
                line = int(frame.get('line', -1))
                self.stack.add_frame(level, addr, func,  fullname, line)
            self.post_event(GDBEvent(EVT_GDB_UPDATE_STACK, self, data=self.stack))

    def var_create(self, expression, floating=False, frame=0, callback=None, name=None):
        if floating:
            frame = "@"

        if not floating:
            self.__blocking_frameselect(frame)
        if frame == 0:
            frame = "*"

        name = name or "cvar%d" % self.__varname_idx # We keep our own names so we can track expressions
        self.__varname_idx += 1
        self.__cmd('-var-create %s %s %s' % (name, frame, expression), callback=callback, internal_callback = functools.partial(self.__on_var_created, expression, frame))
        return name
    
    def __on_var_created(self, expression, frame, data):
        # Created variable info
        try:
            type = Type.parse(data.type)
            numchild = int(data.numchild)
            name = data.name
            value = [] if numchild else data.value
            # Update the model and notify
            self.vars.add(name, Variable(name, expression, type, children=numchild, data=value, frame=frame))
            self.post_event(GDBEvent(EVT_GDB_UPDATE_VARS, self, data=[name]))
        except Exception, e:
            print "Exception creating variable: %s" % e
            print data