diff --git a/GUI/LoadingDialog.py b/GUI/LoadingDialog.py index 13e4fd9a..5efff741 100644 --- a/GUI/LoadingDialog.py +++ b/GUI/LoadingDialog.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'LoadingDialog.ui' # -# Created: Wed Dec 7 19:30:07 2016 +# Created: Tue Feb 21 22:38:30 2017 # by: PyQt5 UI code generator 5.2.1 # # WARNING! All changes made in this file will be lost! @@ -12,9 +12,9 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(195, 40) - self.gridLayout = QtWidgets.QGridLayout(Dialog) - self.gridLayout.setObjectName("gridLayout") + Dialog.resize(208, 89) + self.gridLayout_2 = QtWidgets.QGridLayout(Dialog) + self.gridLayout_2.setObjectName("gridLayout_2") self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) @@ -34,7 +34,20 @@ def setupUi(self, Dialog): self.horizontalLayout.addWidget(self.label_StatusText) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) - self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.widget_Cancel = QtWidgets.QWidget(Dialog) + self.widget_Cancel.setObjectName("widget_Cancel") + self.gridLayout = QtWidgets.QGridLayout(self.widget_Cancel) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setObjectName("gridLayout") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem2, 0, 0, 1, 1) + self.pushButton_Cancel = QtWidgets.QPushButton(self.widget_Cancel) + self.pushButton_Cancel.setObjectName("pushButton_Cancel") + self.gridLayout.addWidget(self.pushButton_Cancel, 0, 1, 1, 1) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem3, 0, 2, 1, 1) + self.gridLayout_2.addWidget(self.widget_Cancel, 1, 0, 1, 1) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) @@ -43,4 +56,5 @@ def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.label_StatusText.setText(_translate("Dialog", "Processing")) + self.pushButton_Cancel.setText(_translate("Dialog", "Cancel")) diff --git a/GUI/LoadingDialog.ui b/GUI/LoadingDialog.ui index 9e92c0ac..0f6ad516 100644 --- a/GUI/LoadingDialog.ui +++ b/GUI/LoadingDialog.ui @@ -6,14 +6,14 @@ 0 0 - 195 - 40 + 208 + 89 Dialog - + @@ -67,6 +67,45 @@ + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + diff --git a/PINCE.py b/PINCE.py index 6643c52b..75f17f98 100644 --- a/PINCE.py +++ b/PINCE.py @@ -845,6 +845,7 @@ def __init__(self, parent=None): # Check refresh_table method of FunctionsInfoWidgetForm for exemplary usage self.background_thread = self.BackgroundThread() self.background_thread.output_ready.connect(self.accept) + self.pushButton_Cancel.clicked.connect(self.cancel_thread) pince_directory = SysUtils.get_current_script_directory() self.movie = QMovie(pince_directory + "/media/LoadingDialog/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) @@ -853,6 +854,11 @@ def __init__(self, parent=None): self.movie.setSpeed(100) self.movie.start() + # This function only cancels the last command sent + # Override this if you want to do dangerous stuff like, God forbid, background_thread.terminate() + def cancel_thread(self): + GDB_Engine.cancel_last_command() + def exec_(self): self.background_thread.start() super(LoadingDialogForm, self).exec_() diff --git a/libPINCE/GDB_Engine.py b/libPINCE/GDB_Engine.py index 6d329f45..52c4f61d 100644 --- a/libPINCE/GDB_Engine.py +++ b/libPINCE/GDB_Engine.py @@ -111,9 +111,21 @@ # See gdb_async_condition's docstrings gdb_async_output = "" +#:doc:cancel_send_command +# A boolean value. Used to cancel the last gdb command sent +# Use the function cancel_last_command to make use of this variable +# Return value of the current send_command call will be an empty string +cancel_send_command = False + # The comments next to the regular expressions shows the expected gdb output, hope it helps to the future developers +def cancel_last_command(): + """Cancels the last gdb command sent""" + global cancel_send_command + cancel_send_command = True + + def send_command(command, control=False, cli_output=False, send_with_file=False, file_contents_send=None, recv_with_file=False): """Issues the command sent, raises an exception if the inferior is running or no inferior has been selected @@ -147,6 +159,7 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, """ global child global gdb_output + global cancel_send_command with lock_send_command: time0 = time() if not gdb_initialized: @@ -178,11 +191,17 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, if not control: while gdb_output is "": sleep(type_defs.CONST_TIME.GDB_INPUT_SLEEP) - if not control: - if recv_with_file or cli_output: - output = pickle.load(open(recv_file, "rb")) + if cancel_send_command: + break + if not cancel_send_command: + if recv_with_file or cli_output: + output = pickle.load(open(recv_file, "rb")) + else: + output = gdb_output else: - output = gdb_output + output = "" + child.sendcontrol("c") + cancel_send_command = False else: output = "" if type(output) == str: @@ -302,7 +321,7 @@ def wait_for_stop(timeout=1): def interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): - """Interrupt the inferior, can be also used to cancel the current gdb command + """Interrupt the inferior Args: interrupt_reason (int): Just changes the global variable stop_reason. Can be a member of type_defs.STOP_REASON @@ -348,6 +367,7 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): global referenced_jumps_dict global referenced_calls_dict global gdb_output + global cancel_send_command detach() # Temporary IPC_PATH, this little hack is needed because send_command requires a valid IPC_PATH @@ -360,6 +380,7 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): referenced_jumps_dict.clear() referenced_calls_dict.clear() gdb_output = "" + cancel_send_command = False libpince_dir = SysUtils.get_libpince_directory() child = pexpect.spawn('sudo LC_NUMERIC=C ' + gdb_path + ' --interpreter=mi', cwd=libpince_dir,