def cmd_rnext(self, arg): """Reverse a next command.""" if not self.ron: debug("You are not in reversible mode. You can enable it with 'ron'.") return if dbg.mode == 'post_mortem': self.cmd_rstep(arg) if dbg.ic > dbg.current_timeline.get_max_ic(): dbg.current_timeline.set_max_ic(dbg.ic) if dbg.ic == 0: self.dbgcom.send_message("At the beginning of the program. Can't step back.") #debug("At the beginning of the program. Can't step back") return nextic = self.rnext_ic.get(dbg.ic, dbg.ic-1) bpic = self.bpmanager.findprecedingbreakpointic() nextic = max(nextic, bpic) s = self.findsnapshot(nextic) if s == None: debug("No snapshot made. Can't step back") return self.mp.activateic(s.id, nextic) raise EpdbExit()
def _remote_invoke(self, method, args, kargs): self.conn.send(pickle.dumps((self.objref, method, args, kargs))) t,r = pickle.loads(self.conn.recv()) if t == 'RET': return r elif t == 'EXC': raise r else: debug('Unknown return value')
def quit(self): try: self.debuggee.send('end ' + str(os.getpid())) done = self.debuggee.recv() if done != 'done': log.debug("Something went wrong during shutdown") except: log.debug("Warning shutting down of snapshot server failed") if self.shareddict_created: shareddict.shutdown(self.dir)
def recv_quitdone(self): #try: msg = self.msging.recv() #except: # log.debug("Broken connection. Assume Quit") # self.quitted = True if msg == 'quitdone': self.quitted = True else: log.debug("Error received: " + repr(msg) + "instead of quitdone")
def cmd_next(self, arg): if self.is_postmortem: self.dbgcom.send_message("You are at the end of the program. You cant go forward.") self.dbgcom.send_finished() return if dbg.mode == 'redo': nextd = dbg.current_timeline.get_next() nextic = nextd.get(dbg.ic, "empty") bpic = self.bpmanager.findnextbreakpointic() if nextic == "empty": # There is no function call in the current line -> same as stepping s = self.findsnapshot(dbg.ic+1) nextic = dbg.ic + 1 elif nextic is None and bpic == -1: # The next command has to switch to normal mode at some point # Use the highest available snapshot s = self.findsnapshot(dbg.current_timeline.get_max_ic()) if s.ic <= dbg.ic: self.set_next(self.curframe) self.running_mode = 'next' return 1 else: self.mp.activatenext(s.id, self.nocalls) raise EpdbExit() else: # The next ends in the current timeline and no mode switch is needed. debug("no modeswitch next") if nextic is None: nextic = bpic elif bpic == -1: pass else: nextic = min(nextic, bpic) s = self.findsnapshot(nextic) #s = self.findsnapshot(dbg.ic+1) if s == None: debug("No snapshot made. This shouldn't be") return if s.ic <= dbg.ic: self.set_next(self.curframe) self.running_mode = 'next' return 1 else: self.mp.activateic(s.id, nextic) raise EpdbExit() else: self.command_running_start_time = time.time() #epdblib.basedebugger.BaseDebugger.set_next(self,self.curframe) self.set_next(self.curframe) return 1
def checkline(self, filename, lineno): """Check whether specified line seems to be executable. Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank line or EOF). Warning: testing is not comprehensive. """ line = linecache.getline(filename, lineno, self.curframe.f_globals) if not line: return 0 line = line.strip() # Don't allow setting breakpoint at a blank line if (not line or (line[0] == '#') or (line[:3] == '"""') or line[:3] == "'''"): debug('*** Blank or comment') return 0 return lineno
def cmd_switch_timeline(self, arg): """Switch to another timeline""" try: timeline = dbg.timelines.get(arg) except: debug("Timeline '", arg, "' doesn't exist", sep='') return dbg.current_timeline.deactivate(dbg.ic) ic = timeline.get_ic() dbg.timelines.set_current_timeline(timeline.get_name()) self.dbgcom.send_timeline_switched(timeline.get_name()) dbg.current_timeline = timeline s = self.findsnapshot(ic) self.mp.activateic(s.id, ic) raise EpdbExit()
def post_mortem(t=None): # handling the default if t is None: # sys.exc_info() returns (type, value, traceback) if an exception is # being handled, otherwise it returns None t = sys.exc_info()[2] if t is None: raise ValueError("A valid traceback must be passed if no " "exception is being handled") p = Epdb() p.reset() debug('post-mortem interaction') frame = sys._current_frames()[_thread.get_ident()] debug("Post mortem wit frame:", frame) p.interaction(frame, t)
def cmd_rcontinue(self, arg): """Continues in backward direction""" if not self.ron: debug("You are not in reversible mode. You can enable it with 'ron'.") return if dbg.ic > dbg.current_timeline.get_max_ic(): dbg.current_timeline.set_max_ic(dbg.ic) if dbg.ic == 0: self.dbgcom.send_message("At the beginning of the program. Can't step back.") return highestic = self.bpmanager.findprecedingbreakpointic() s = self.findsnapshot(highestic) if s == None: debug("No snapshot made. Can't step back") return self.mp.activateic(s.id, highestic) raise EpdbExit()
def cmd_activate_snapshot(self, arg): """activate the snapshot with the given id""" if not self.ron: debug("You are not in reversible mode. You can enable it with 'ron'.") return if dbg.ic > dbg.current_timeline.get_max_ic(): dbg.current_timeline.set_max_ic(dbg.ic) snapshots = dbg.current_timeline.get_snapshots() for sid in snapshots: s = self.snapshots[sid] if s.id == int(arg): break else: debug("Snapshot not found in timeline") return self.mp.activateic(s.id, self.snapshots[sid].ic) raise EpdbExit()
def cmd_rstep(self, arg): """Steps one step backwards""" if not self.ron: debug("You are not in reversible mode. You can enable it with 'ron'.") return if dbg.ic > dbg.current_timeline.get_max_ic(): dbg.current_timeline.set_max_ic(dbg.ic) if dbg.ic == 0: self.dbgcom.send_message("At the beginning of the program. Can't step back.") return s = self.findsnapshot(dbg.ic-1) if s == None: debug("No snapshot made. Can't step back") return self.dbgcom.send_debugmessage("Activate ic {0}".format(dbg.ic)) self.mp.activateic(s.id, dbg.ic - 1) raise EpdbExit()
def client(): con = connect('/tmp/shareddict') txt = input() while txt != 'exit': s = txt.split() s += [''] * (3-len(s)) command, idx, value = s if command == 'set': con.send(pickle.dumps(('__setitem__', (idx, value), {}))) t,r = pickle.loads(con.recv()) elif command == 'get': con.send(pickle.dumps(('__getitem__', (idx), {}))) t,r = pickle.loads(con.recv()) if t == 'RET': debug(r) elif t == 'EXC': raise r else: debug('Unknown return value') txt = input() con.close()
def cmd_clear(self, arg): """Three possibilities, tried in this order: clear -> clear all breaks, ask for confirmation clear file:lineno -> clear all breaks at file:lineno clear bpno bpno ... -> clear breakpoints by number""" #from epdblib.breakpoint import Breakpoint if not arg: try: reply = input('Clear all breaks? ') except EOFError: reply = 'no' reply = reply.strip().lower() if reply in ('y', 'yes'): self.manager.clear_all_breaks() return if ':' in arg: # Make sure it works for "clear C:\foo\bar.py:12" i = arg.rfind(':') filename = arg[:i] arg = arg[i+1:] try: lineno = int(arg) except ValueError: err = "Invalid line number (%s)" % arg else: err = self.clear_break(filename, lineno) if err: debug('***', err) return numberlist = arg.split() for i in numberlist: try: i = int(i) except ValueError: #print('Breakpoint index %r is not a number' % i, file=self.stdout) continue # TODO don't directly access the bpmanager if not (0 <= i < len(self.bpmanager.bpbynumber)): debug('No breakpoint numbered', i) continue err = self.clear_bpbynumber(i) if err: debug('***', err) else: self.dbgcom.send_clear_success(i)
def server(self): max_id = 0 p = select.poll() p.register(self.controller.sock, select.POLLIN | select.POLLPRI) p.register(self.sp_sock, select.POLLIN | select.POLLPRI) quitrecvinitiated = False while True: list = p.poll(200) if list == []: if self.do_quit: #log.debug("not quitted " + str(notquitted)) if not quitrecvinitiated: for sc in self.snapshot_connections: p.register(sc.fileno(), select.POLLIN | select.POLLPRI) quitrecvinitiated = True notquitted = [ s.quitted for s in self.snapshot_connections if s.quitted == False ] if notquitted == []: self.controller.send("done") self.clear_tmp_file() return #sys.exit(0) for fd, ev in list: # Controller Code if fd == self.controller.sock.fileno(): line = self.controller.recv() words = line.rstrip().split(" ") cmd = str(words[0]) if cmd == "end": mainpid = int(words[1]) notquitted = [ s.quitted for s in self.snapshot_connections if s.quitted == False ] for i, conn in enumerate(self.snapshot_connections): try: conn.send_quit(mainpid) except: import traceback exctype, exc, tb = sys.exc_info() print(exctype, exc) #print("Exception:", exc.message) traceback.print_tb(tb) self.do_quit = True elif cmd == 'connect': arg = words[1] self.controller.send("Connected " + arg) elif cmd == 'showlist': log.debug('ID InstructionNr PSnapshot') log.debug('----------------------------') for s in self.snapshot_connections: log.debug("{0} {1}".format(s.id, s.ic)) log.debug('Number of snapshots: %d' % len(self.snapshot_connections)) self.controller.send('ok') elif cmd == 'activate': ssid = int(words[1]) steps = int(words[2]) for s in self.snapshot_connections: if s.id == ssid: ss = s break ss = self.snapshot_connections[ssid] ss.activate(steps) elif cmd == 'activateic': ssid = int(words[1]) ic = int(words[2]) for s in self.snapshot_connections: if s.id == ssid: ss = s break ss = self.snapshot_connections[ssid] ss.activateic(ic) elif cmd == 'activatenext': ssid = int(words[1]) nocalls = int(words[2]) for s in self.snapshot_connections: if s.id == ssid: ss = s break ss = self.snapshot_connections[ssid] ss.activatenext(nocalls) elif cmd == 'activatecontinue': ssid = int(words[1]) for s in self.snapshot_connections: if s.id == ssid: ss = s break ss = self.snapshot_connections[ssid] ss.activatecontinue() else: log.debug(cmd) # New Savepoint/Debuggee Connection elif fd == self.sp_sock.fileno(): conn, addr = self.sp_sock.accept() msging = Messaging(conn) msg = msging.recv().split() type = msg[0] if type == 'snapshot': arg1 = msg[1] ic = int(arg1) ss = SnapshotConnection(msging, max_id, ic) self.snapshot_connections.append(ss) msging.send('ok {0}'.format(max_id)) max_id += 1 if self.do_quit: ss.send_quit() else: log.info("Critical Error") # Message from snapshot elif fd in [s.fileno() for s in self.snapshot_connections]: ss_conn = [ s for s in self.snapshot_connections if fd == s.fileno() ][0] ss_conn.recv_quitdone() else: for conn in self.snapshot_connections: if fd == conn.msging.sock.fileno(): conn.respond() break else: log.info('Unknown fd: %s' % fd) self.clear_tmp_file() #sys.exit(0) return
def cmd_nde(self, arg): """Shows the current nde. Debugging only.""" debug('nde:', dbg.nde)
def quit(self): self.msging.send('close') done = self.msging.recv() if done != 'done': log.debug("Error")
def main(): try: epdb, mainpyfile = parse_args(sys.argv) except UsageException as e: usage(e.msg) except HelpException as e: help() sys.exit(0) if not os.path.exists(mainpyfile): print('Error:', mainpyfile, 'does not exist') sys.exit(1) # Replace epdb's dir with script's dir in front of module search path. sys.path[0] = os.path.dirname(mainpyfile) while 1: try: #epdb.ic = 0 dbg.ic = 0 epdb._runscript(mainpyfile) if epdb._user_requested_quit: break break #print("The program finished and will be restarted") #print("The program has finished", dbg.ic) #raise EpdbPostMortem() ##epdb.interaction(None, None) except pdb.Restart: print("Restarting", mainpyfile, "with arguments:") print("\t" + " ".join(sys.argv[1:])) # Deactivating automatic restart temporarily TODO break except SystemExit: traceback.print_exc() print("Uncaught exception. Entering post mortem debugging") print("Running 'cont' or 'step' will restart the program") t = sys.exc_info()[2] frame = sys._current_frames()[_thread.get_ident()] debug("SystemExit exception. Frame:", frame) epdb.interaction(frame, t) except epdblib.debugger.EpdbExit: break except bdb.BdbQuit: debug('BdbQuit caught - Shutting servers down') break except snapshotting.ControllerExit: debug('ControllerExit caught') break except snapshotting.SnapshotExit: break except epdblib.debugger.EpdbPostMortem: t = sys.exc_info()[2] print("Traceback:", t) traceback.print_tb(t) epdb.mp.quit() break except: traceback.print_exc() print("Uncaught exception. Entering post mortem debugging") #print("Running 'cont' or 'step' will restart the program") frame = sys._current_frames()[_thread.get_ident()] t = sys.exc_info()[2] epdb.interaction(frame, t)
def cmd_ic(self, arg): """Shows the current instruction count""" debug('The instruction count is:', dbg.ic)
def server(sockdir=None, sockfile='shareddict.sock', dofork=False, exitatclose=True, resources=[], resource_paths=[]): if sockdir == None: socketdirectory = tempfile.mkdtemp(prefix="epdb-shareddict-") else: socketdirectory = sockdir sockaddr = os.path.join(socketdirectory, sockfile) bplist = ServerDict() # weird naming, but conforming to bdb bpbynumber = ServerList() bpbynumber.append(None) breaks = ServerDict() snapshots = ServerDict() resources_dict = {} managers_dict = {} nde_dict = {} ude_dict = {} # TODO rnext_dict and rcontinue_dict is likely not needed # In rnext the position for the rnext command to jump to is saved # It is filled in user_return rnext_dict = {} # In rcontinue for every executed line number a list of instruction counts # that have executed them is saved. This is needed for reverse continue rcontinue_dict = {} next_dict = {} continue_dict = {} timelines = ServerTimelines(snapshots, nde_dict, ude_dict, next_dict, continue_dict, resources_dict, managers_dict ) server = listen(sockaddr) if dofork: sdpid = os.fork() # TODO dofork returns when the server shutdowns? if not sdpid: return sdpid initialize_resources(resources, resource_paths) do_quit = False connectiondict = {} poll = select.epoll() poll.register(server.sock, select.EPOLLIN|select.EPOLLPRI|select.EPOLLHUP) while not do_quit: list = poll.poll(100) for fileno, event in list: if fileno == server.sock.fileno(): newconnection = server.accept() connectiondict[newconnection.sock.fileno()] = newconnection poll.register(newconnection.sock, select.EPOLLIN|select.EPOLLPRI|select.EPOLLHUP) else: try: if event | select.EPOLLIN: conn = connectiondict[fileno] bstream = conn.recv() try: objref,method,args,kargs = pickle.loads(bstream) m = re.match('^resources\.(?P<timeline>[^.]*)\.(?P<type>[^.]*)\.(?P<location>[^.]*)$', objref) #manager_match = re.match('^managers\.(?P<timeline>[^.]*)\.(?P<type>[^.]*)\.(?P<location>[^.]*)$', objref) #debug('matching done') #if objref == 'nde': # r = getattr(nde, method)(*args, **kargs) if objref == 'bplist': r = getattr(bplist, method)(*args, **kargs) elif objref == 'bpbynumber': r = getattr(bpbynumber, method)(*args, **kargs) elif objref == 'breaks': r = getattr(breaks, method)(*args, **kargs) elif objref == 'snapshots': r = getattr(snapshots, method)(*args, **kargs) elif objref == 'timelines': r = getattr(timelines, method)(*args, **kargs) elif objref.startswith('timeline.'): id = '.'.join(objref.split('.')[1:]) r = getattr(timelines._get(id), method)(*args, **kargs) elif objref.startswith('nde.'): id = '.'.join(objref.split('.')[1:]) r = getattr(nde_dict[id], method)(*args, **kargs) elif objref.startswith('ude.'): id = '.'.join(objref.split('.')[1:]) r = getattr(ude_dict[id], method)(*args, **kargs) elif objref.startswith('rnext.'): id = '.'.join(objref.split('.')[1:]) r = getattr(rnext_dict[id], method)(*args, **kargs) elif objref.startswith('rcontinue.'): id = '.'.join(objref.split('.')[1:]) r = getattr(rcontinue_dict[id], method)(*args, **kargs) elif objref.startswith('next.'): id = '.'.join(objref.split('.')[1:]) r = getattr(next_dict[id], method)(*args, **kargs) elif objref.startswith('continue.'): id = '.'.join(objref.split('.')[1:]) r = getattr(continue_dict[id], method)(*args, **kargs) #elif manager_match: # timeline = m.group('timeline') # typ = m.group('type') # location = str(base64.b64decode(bytes(m.group('location'), 'utf-8')), 'utf-8') # r = getattr(managers_dict[timeline][(typ, location)], method)(*args, **kargs) #elif objref.startswith('managers.'): # id = '.'.join(objref.split('.')[1:]) # r = getattr(managers_dict[id], method)(*args, **kargs) elif m: timeline = m.group('timeline') typ = m.group('type') location = str(base64.b64decode(bytes(m.group('location'), 'utf-8')), 'utf-8') r = getattr(resources_dict[timeline][(typ, location)], method)(*args, **kargs) elif objref.startswith('resources.'): id = '.'.join(objref.split('.')[1:]) r = getattr(resources_dict[id], method)(*args, **kargs) elif objref == 'control': r = None if method == 'shutdown': for c in connectiondict.values(): if c != conn: c.close() conn.send(b'done') conn.close() do_quit = True except Exception as e: #traceback.print_exc() conn.send(pickle.dumps(('EXC', e))) else: conn.send(pickle.dumps(('RET', r))) if event | select.EPOLLHUP: pass elif event == select.EPOLLPRI: pass else: debug('Server: Unknown event') except socket.error: poll.unregister(fileno) server.close() if sockdir == None: # delete tempdir if it was created os.unlink(tempdir) if exitatclose: sys.exit(0)
def show(self): debug("Show values") for k in self.timelines.keys(): debug(self.timelines[k].name)
def cmd_mode(self, arg): """Shows the current mode.""" if self.is_postmortem: debug("mode: postmortem", dbg.mode) else: debug("mode: ", dbg.mode)
def cmd_continued(self, arg): continued = dbg.current_timeline.get_continue() debug('continued: ', continued)
def cmd_return(self, arg): debug("Return not implemented yet for epdb")
def block(self): self.activated = True while True: msg = self.msging.recv() args = msg.split() cmd = args[0] if cmd == "close": mainpid = int(args[1]) if mainpid in dbg.cpids: # The main pid will be closed after # after the quit confirmation dbg.cpids.remove(mainpid) mainpids = [mainpid] else: mainpids = [] while dbg.cpids != []: (pid, status) = os.wait() idx = dbg.cpids.index(pid) del dbg.cpids[idx] self.msging.send('quitdone') while mainpids != []: mainpid = mainpids.pop() (pid, status) = os.wait() time.sleep(0.5) # TODO some better synchronization needed raise SnapshotExit() if cmd == "run": steps = int(args[1]) rpid = os.fork() if rpid: dbg.cpids.append(rpid) else: log.debug("") del dbg.cpids[:] self.activation_type = "step_forward" self.step_forward = steps dbg.current_timeline = dbg.timelines.get_current_timeline() dbg.nde = dbg.current_timeline.get_nde() #dbg.undod = dbg.current_timeline.get_ude() break if cmd == "runic": ic = int(args[1]) rpid = os.fork() if rpid: dbg.cpids.append(rpid) else: del dbg.cpids[:] self.activation_type = "stop_at_ic" self.stop_at_ic = ic dbg.current_timeline = dbg.timelines.get_current_timeline() dbg.nde = dbg.current_timeline.get_nde() #dbg.undod = dbg.current_timeline.get_ude() break elif cmd == "runnext": # Run until a given nocalls is reached nocalls = int(args[1]) rpid = os.fork() if rpid: dbg.cpids.append(rpid) else: del dbg.cpids[:] #self.step_forward = steps self.activation_type = "stopatnocalls" self.nocalls = nocalls dbg.current_timeline = dbg.timelines.get_current_timeline() dbg.nde = dbg.current_timeline.get_nde() #dbg.undod = dbg.current_timeline.get_ude() break elif cmd == "runcontinue": # Run until a given nocalls is reached rpid = os.fork() if rpid: dbg.cpids.append(rpid) else: del dbg.cpids[:] #self.step_forward = steps self.activation_type = "continue" dbg.current_timeline = dbg.timelines.get_current_timeline() dbg.nde = dbg.current_timeline.get_nde() #dbg.undod = dbg.current_timeline.get_ude() break
def cmd_break(self, arg, temporary = 0): if not arg: if self.breaks: # There's at least one self.bpmanager.show() return # parse arguments; comma has lowest precedence # and cannot occur in filename filename = None lineno = None cond = None comma = arg.find(',') if comma > 0: # parse stuff after comma: "condition" cond = arg[comma+1:].lstrip() arg = arg[:comma].rstrip() # parse stuff before comma: [filename:]lineno | function colon = arg.rfind(':') funcname = None if colon >= 0: filename = arg[:colon].rstrip() f = self.lookupmodule(filename) if not f: debug('*** ', repr(filename), end=' ') debug('not found from sys.path') self.dbgcom.send_break_nosucess(filename, lineno, repr(filename)+" not found") return else: filename = f arg = arg[colon+1:].lstrip() try: lineno = int(arg) except ValueError: debug('*** Bad lineno:', arg) self.dbgcom.send_break_nosucess(filename, lineno, "Bad lineno") return else: # no colon; can be lineno or function try: lineno = int(arg) except ValueError: try: func = eval(arg, self.curframe.f_globals, self.curframe_locals) except: func = arg try: if hasattr(func, '__func__'): func = func.__func__ code = func.__code__ #use co_name to identify the bkpt (function names #could be aliased, but co_name is invariant) funcname = code.co_name lineno = code.co_firstlineno filename = code.co_filename except: # last thing to try (ok, filename, ln) = self.lineinfo(arg) if not ok: reason = "The specified object " + repr(arg) + \ "is not a function or was not found along sys.path." self.dbgcom.send_break_nosucess(filename, lineno, reason) return funcname = ok # ok contains a function name lineno = int(ln) if not filename: filename = self.defaultFile() # Check for reasonable breakpoint line = self.checkline(filename, lineno) if line: # now set the break point err = self.set_break(filename, line, temporary, cond, funcname) if err: self.dbgcom.send_break_nosucess(filename, lineno, "Error: " + str(err)) else: bp = self.get_breaks(filename, line)[-1] self.dbgcom.send_break_success(bp.number, bp.file, bp.line)