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 = []
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