--- a/DebugClients/Python/DebugClientBase.py Sun Aug 16 12:24:28 2015 +0200 +++ b/DebugClients/Python/DebugClientBase.py Sun Aug 16 13:47:44 2015 +0200 @@ -17,6 +17,8 @@ import imp import re import atexit +import signal +import inspect import DebugProtocol @@ -521,6 +523,7 @@ # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception + self.__interceptSignals() # clear all old breakpoints, they'll get set after we # have started @@ -566,6 +569,7 @@ # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception + self.__interceptSignals() self.mainThread.tracePython = 0 @@ -578,7 +582,7 @@ res = exc.code atexit._run_exitfuncs() self.writestream.flush() - self.progTerminated(res) + self.progTerminated(res, exit=True) return if cmd == DebugProtocol.RequestCoverage: @@ -597,6 +601,7 @@ # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception + self.__interceptSignals() # generate a coverage object self.cover = coverage( @@ -619,7 +624,7 @@ self.cover.stop() self.cover.save() self.writestream.flush() - self.progTerminated(res) + self.progTerminated(res, exit=True) return if cmd == DebugProtocol.RequestProfile: @@ -639,6 +644,7 @@ # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception + self.__interceptSignals() # generate a profile object self.prof = PyProfile.PyProfile(sys.argv[0]) @@ -656,7 +662,7 @@ atexit._run_exitfuncs() self.prof.save() self.writestream.flush() - self.progTerminated(res) + self.progTerminated(res, exit=True) return if cmd == DebugProtocol.RequestShutdown: @@ -849,6 +855,7 @@ # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception + self.__interceptSignals() try: import unittest @@ -1158,6 +1165,61 @@ @param exctb traceback for the exception """ self.mainThread.user_exception(None, (exctype, excval, exctb), 1) + + def __interceptSignals(self): + """ + Private method to intercept common signals. + """ + for signum in [ + signal.SIGABRT, # abnormal termination + signal.SIGFPE, # floating point exception + signal.SIGILL, # illegal instruction + signal.SIGSEGV, # segmentation violation + ]: + signal.signal(signum, self.__signalHandler) + + def __signalHandler(self, signalNumber, stackFrame): + """ + Private method to handle signals. + + @param signalNumber number of the signal to be handled + @type int + @param stack frame current stack frame + @type frame object + """ + if signalNumber == signal.SIGABRT: + message = "Abnormal Termination" + elif signalNumber == signal.SIGFPE: + message = "Floating Point Exception" + elif signalNumber == signal.SIGILL: + message = "Illegal Instruction" + elif signalNumber == signal.SIGSEGV: + message = "Segmentation Violation" + else: + message = "Unknown Signal '%d'" % signalNumber + + filename = self.absPath(stackFrame) + + linenr = stackFrame.f_lineno + ffunc = stackFrame.f_code.co_name + + if ffunc == '?': + ffunc = '' + + if ffunc and not ffunc.startswith("<"): + argInfo = inspect.getargvalues(stackFrame) + try: + fargs = inspect.formatargvalues( + argInfo.args, argInfo.varargs, + argInfo.keywords, argInfo.locals) + except Exception: + fargs = "" + else: + fargs = "" + + siglist = [message, [filename, linenr, ffunc, fargs]] + + self.write("%s%s" % (DebugProtocol.ResponseSignal, str(siglist))) def absPath(self, fn): """ @@ -1232,11 +1294,13 @@ """ return self.running - def progTerminated(self, status): + def progTerminated(self, status, exit=False): """ Public method to tell the debugger that the program has terminated. - @param status the return status + @param status return status + @param exit flag indicating to perform a sys.exit() + @type bool """ if status is None: status = 0 @@ -1250,6 +1314,8 @@ self.set_quit() self.running = None self.write('%s%d\n' % (DebugProtocol.ResponseExit, status)) + if exit: + sys.exit(status) # reset coding self.__coding = self.defaultCoding @@ -1891,6 +1957,7 @@ # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception + self.__interceptSignals() # now start debugging if enableTrace: @@ -1948,6 +2015,7 @@ # set the system exception handling function to ensure, that # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception + self.__interceptSignals() # This will eventually enter a local event loop. # Note the use of backquotes to cause a repr of self.running. The