From 481721299ffd0bd3a6c6116015429e6f7c0d4bd7 Mon Sep 17 00:00:00 2001 From: Berk Ozler Date: Mon, 21 Mar 2022 01:55:58 +0200 Subject: [PATCH 001/487] Fixed hardcoded black text color for dark themes --- GUI/CustomLabels/FlagRegisterLabel.py | 2 +- GUI/CustomLabels/RegisterLabel.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GUI/CustomLabels/FlagRegisterLabel.py b/GUI/CustomLabels/FlagRegisterLabel.py index 5dbbb03b..0d772a5b 100644 --- a/GUI/CustomLabels/FlagRegisterLabel.py +++ b/GUI/CustomLabels/FlagRegisterLabel.py @@ -31,7 +31,7 @@ def set_value(self, value): if old != new: self.setStyleSheet("color: red") else: - self.setStyleSheet("color: black") + self.setStyleSheet("") self.setText(new) def enterEvent(self, QEvent): diff --git a/GUI/CustomLabels/RegisterLabel.py b/GUI/CustomLabels/RegisterLabel.py index 8e8b04c9..107b35d9 100644 --- a/GUI/CustomLabels/RegisterLabel.py +++ b/GUI/CustomLabels/RegisterLabel.py @@ -32,7 +32,7 @@ def set_value(self, value): if old != new: self.setStyleSheet("color: red") else: - self.setStyleSheet("color: black") + self.setStyleSheet("") self.setText(new) def enterEvent(self, QEvent): From 404c5efb206ee87dfb7533cedc77b9d615a6825e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 3 Apr 2022 21:30:33 +0300 Subject: [PATCH 002/487] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6706fb20..204c347a 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ If you like to uninstall PINCE, just delete this folder, almost everything is in ***Notes:*** - GDB enhancements (peda, pwndbg, etc) that use a global gdbinit file might cause PINCE to misfunction at times. Please disable them or use them locally before starting PINCE - If you are having problems with your default gdb version, you can use the `install_gdb.sh` script to install another version locally. Read the comments in it for more information +- Check #116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` # Running PINCE Just run ```sh PINCE.sh``` in the PINCE directory From 462d3509e8282285df91decc78fffdd8d8738e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 25 Apr 2022 19:39:57 +0300 Subject: [PATCH 003/487] Add option to ignore multiple signals --- GUI/HandleSignalsDialog.py | 62 ++++++++++++++++++++++++ GUI/HandleSignalsDialog.ui | 99 ++++++++++++++++++++++++++++++++++++++ GUI/SettingsDialog.py | 21 +++++--- GUI/SettingsDialog.ui | 27 +++++++++-- PINCE.py | 93 +++++++++++++++++++++++++++-------- libpince/GDB_Engine.py | 39 ++++++++------- 6 files changed, 287 insertions(+), 54 deletions(-) create mode 100644 GUI/HandleSignalsDialog.py create mode 100644 GUI/HandleSignalsDialog.ui diff --git a/GUI/HandleSignalsDialog.py b/GUI/HandleSignalsDialog.py new file mode 100644 index 00000000..2993bf1b --- /dev/null +++ b/GUI/HandleSignalsDialog.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'HandleSignalsDialog.ui' +# +# Created by: PyQt5 UI code generator 5.14.1 +# +# WARNING! All changes made in this file will be lost! + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(268, 244) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.tableWidget_Signals = QtWidgets.QTableWidget(Dialog) + self.tableWidget_Signals.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableWidget_Signals.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.tableWidget_Signals.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Signals.setObjectName("tableWidget_Signals") + self.tableWidget_Signals.setColumnCount(2) + self.tableWidget_Signals.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Signals.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Signals.setHorizontalHeaderItem(1, item) + self.tableWidget_Signals.horizontalHeader().setStretchLastSection(True) + self.tableWidget_Signals.verticalHeader().setVisible(False) + self.tableWidget_Signals.verticalHeader().setDefaultSectionSize(16) + self.tableWidget_Signals.verticalHeader().setMinimumSectionSize(16) + self.gridLayout.addWidget(self.tableWidget_Signals, 0, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Handle Signals")) + item = self.tableWidget_Signals.horizontalHeaderItem(0) + item.setText(_translate("Dialog", "Signal")) + item = self.tableWidget_Signals.horizontalHeaderItem(1) + item.setText(_translate("Dialog", "Ignore")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + Dialog = QtWidgets.QDialog() + ui = Ui_Dialog() + ui.setupUi(Dialog) + Dialog.show() + sys.exit(app.exec_()) diff --git a/GUI/HandleSignalsDialog.ui b/GUI/HandleSignalsDialog.ui new file mode 100644 index 00000000..9a39bc0c --- /dev/null +++ b/GUI/HandleSignalsDialog.ui @@ -0,0 +1,99 @@ + + + Dialog + + + + 0 + 0 + 268 + 244 + + + + Handle Signals + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + 16 + + + 16 + + + + Signal + + + + + Ignore + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index b04b2b20..a0941713 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -295,11 +295,16 @@ def setupUi(self, Dialog): self.checkBox_GDBLogging = QtWidgets.QCheckBox(self.page_5) self.checkBox_GDBLogging.setObjectName("checkBox_GDBLogging") self.verticalLayout_11.addWidget(self.checkBox_GDBLogging) - self.checkBox_IgnoreSegfault = QtWidgets.QCheckBox(self.page_5) - self.checkBox_IgnoreSegfault.setObjectName("checkBox_IgnoreSegfault") - self.verticalLayout_11.addWidget(self.checkBox_IgnoreSegfault) - spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout_11.addItem(spacerItem12) + self.horizontalLayout_16 = QtWidgets.QHBoxLayout() + self.horizontalLayout_16.setObjectName("horizontalLayout_16") + self.pushButton_HandleSignals = QtWidgets.QPushButton(self.page_5) + self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") + self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) + spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_16.addItem(spacerItem12) + self.verticalLayout_11.addLayout(self.horizontalLayout_16) + spacerItem13 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_11.addItem(spacerItem13) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) self.horizontalLayout_2.addWidget(self.stackedWidget) @@ -309,8 +314,8 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem13) + spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem14) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) @@ -370,7 +375,7 @@ def retranslateUi(self, Dialog): self.label_6.setText(_translate("Dialog", "Instructions shown per scroll")) self.label_7.setText(_translate("Dialog", "GDB Path")) self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) - self.checkBox_IgnoreSegfault.setText(_translate("Dialog", "Ignore segfault signal")) + self.pushButton_HandleSignals.setText(_translate("Dialog", "Handle Signals")) self.pushButton_ResetSettings.setText(_translate("Dialog", "Reset Settings")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index a29aff97..ebea30ee 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -635,11 +635,28 @@ Patterns at former positions have higher priority if regex is off - - - Ignore segfault signal - - + + + + + Handle Signals + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + diff --git a/PINCE.py b/PINCE.py index b7e3ae87..d039ab9c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -22,7 +22,7 @@ QKeyEvent, QRegExpValidator from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, \ QShortcut, QKeySequenceEdit, QTabWidget, QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, \ - QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox + QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, \ QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegExp, QRunnable, QThreadPool, pyqtSlot from time import sleep, time @@ -39,6 +39,7 @@ from GUI.InputDialog import Ui_Dialog as InputDialog from GUI.TextEditDialog import Ui_Dialog as TextEditDialog from GUI.SettingsDialog import Ui_Dialog as SettingsDialog +from GUI.HandleSignalsDialog import Ui_Dialog as HandleSignalsDialog from GUI.ConsoleWidget import Ui_Form as ConsoleWidget from GUI.AboutWidget import Ui_TabWidget as AboutWidget @@ -71,7 +72,7 @@ instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "master-20" # Increase version by one if you change settings. Format: branch_name-version +current_settings_version = "master-21" # Increase version by one if you change settings. Format: branch_name-version update_table = bool table_update_interval = int FreezeInterval = int @@ -107,7 +108,9 @@ def get_hotkeys(): instructions_per_scroll = int gdb_path = str gdb_logging = bool -ignore_sigsegv = bool + +ignored_signals = str +signal_list = ["SIGUSR1", "SIGPWR", "SIGSEGV"] # represents the index of columns in breakpoint table BREAK_NUM_COL = 0 @@ -360,14 +363,14 @@ def __init__(self): self.settings.clear() self.set_default_settings() try: - GDB_Engine.init_gdb(gdb_path, ignore_sigsegv) + GDB_Engine.init_gdb(gdb_path) except pexpect.EOF: text = "Unable to initialize GDB\n" \ "You might want to reinstall GDB or use the system GDB\n" \ "To change the current GDB path, check Settings->Debug" InputDialogForm(item_list=[(text, None)], buttons=[QDialogButtonBox.Ok]).exec_() else: - GDB_Engine.set_logging(gdb_logging) + self.apply_after_init() # this should be changed, only works if you use the current directory, fails if you for example install it to some place like bin libscanmem_path = os.path.join(os.getcwd(), "libpince", "libscanmem", "libscanmem.so") self.backend = Scanmem(libscanmem_path) @@ -466,13 +469,26 @@ def set_default_settings(self): self.settings.beginGroup("Debug") self.settings.setValue("gdb_path", type_defs.PATHS.GDB_PATH) self.settings.setValue("gdb_logging", False) - self.settings.setValue("ignore_sigsegv", False) + self.settings.setValue("ignored_signals", "1,1,0") self.settings.endGroup() self.settings.beginGroup("Misc") self.settings.setValue("version", current_settings_version) self.settings.endGroup() self.apply_settings() + def apply_after_init(self): + global gdb_logging + global ignored_signals + + gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) + ignored_signals = self.settings.value("Debug/ignored_signals", type=str) + GDB_Engine.set_logging(gdb_logging) + for index, ignore_status in enumerate(ignored_signals.split(",")): + if ignore_status == "1": + GDB_Engine.ignore_signal(signal_list[index]) + else: + GDB_Engine.unignore_signal(signal_list[index]) + def apply_settings(self): global update_table global table_update_interval @@ -486,8 +502,6 @@ def apply_settings(self): global bring_disassemble_to_front global instructions_per_scroll global gdb_path - global gdb_logging - global ignore_sigsegv global FreezeInterval update_table = self.settings.value("General/auto_update_address_table", type=bool) @@ -512,11 +526,8 @@ def apply_settings(self): bring_disassemble_to_front = self.settings.value("Disassemble/bring_disassemble_to_front", type=bool) instructions_per_scroll = self.settings.value("Disassemble/instructions_per_scroll", type=int) gdb_path = self.settings.value("Debug/gdb_path", type=str) - gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) - ignore_sigsegv = self.settings.value("Debug/ignore_sigsegv", type=bool) if GDB_Engine.gdb_initialized: - GDB_Engine.set_logging(gdb_logging) - GDB_Engine.ignore_segfault(ignore_sigsegv) + self.apply_after_init() # Check if any process should be attached to automatically # Patterns at former positions have higher priority if regex is off @@ -1094,9 +1105,9 @@ def pushButton_Save_clicked(self): # Returns: a bool value indicates whether the operation succeeded. def attach_to_pid(self, pid): - attach_result = GDB_Engine.attach(pid, gdb_path, ignore_sigsegv) + attach_result = GDB_Engine.attach(pid, gdb_path) if attach_result[0] == type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL: - GDB_Engine.set_logging(gdb_logging) + self.apply_after_init() self.backend.send_command("pid {}".format(pid)) self.on_new_process() @@ -1111,8 +1122,8 @@ def attach_to_pid(self, pid): # Returns: a bool value indicates whether the operation succeeded. def create_new_process(self, file_path, args, ld_preload_path): - if GDB_Engine.create_process(file_path, args, ld_preload_path, ignore_sigsegv): - GDB_Engine.set_logging(gdb_logging) + if GDB_Engine.create_process(file_path, args, ld_preload_path): + self.apply_after_init() self.on_new_process() return True else: @@ -1150,8 +1161,8 @@ def copy_to_address_table(self): def on_inferior_exit(self): if GDB_Engine.currentpid == -1: self.on_status_running() - GDB_Engine.init_gdb(gdb_path, ignore_sigsegv) - GDB_Engine.set_logging(gdb_logging) + GDB_Engine.init_gdb(gdb_path) + self.apply_after_init() self.label_SelectedProcess.setText("No Process Selected") def on_status_detached(self): @@ -1799,6 +1810,7 @@ class SettingsDialogForm(QDialog, SettingsDialog): def __init__(self, set_default_settings_func, parent=None): super().__init__(parent=parent) self.setupUi(self) + self.settings = QSettings() self.set_default_settings = set_default_settings_func self.hotkey_to_value = {} # Dict[str:str]-->Dict[Hotkey.name:settings_value] @@ -1816,6 +1828,8 @@ def __init__(self, set_default_settings_func, parent=None): self.checkBox_AutoUpdateAddressTable.stateChanged.connect(self.checkBox_AutoUpdateAddressTable_state_changed) self.checkBox_AutoAttachRegex.stateChanged.connect(self.checkBox_AutoAttachRegex_state_changed) self.checkBox_AutoAttachRegex_state_changed() + self.pushButton_HandleSignals.clicked.connect(self.pushButton_HandleSignals_clicked) + self.handle_signals_data = None self.config_gui() def accept(self): @@ -1891,11 +1905,10 @@ def accept(self): GDB_Engine.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) - self.settings.setValue("Debug/ignore_sigsegv", self.checkBox_IgnoreSegfault.isChecked()) + self.settings.setValue("Debug/ignored_signals", ",".join(self.handle_signals_data)) super(SettingsDialogForm, self).accept() def config_gui(self): - self.settings = QSettings() self.checkBox_AutoUpdateAddressTable.setChecked( self.settings.value("General/auto_update_address_table", type=bool)) self.lineEdit_UpdateInterval.setText( @@ -1933,7 +1946,6 @@ def config_gui(self): str(self.settings.value("Disassemble/instructions_per_scroll", type=int))) self.lineEdit_GDBPath.setText(str(self.settings.value("Debug/gdb_path", type=str))) self.checkBox_GDBLogging.setChecked(self.settings.value("Debug/gdb_logging", type=bool)) - self.checkBox_IgnoreSegfault.setChecked(self.settings.value("Debug/ignore_sigsegv", type=bool)) def change_display(self, index): self.stackedWidget.setCurrentIndex(index) @@ -1958,6 +1970,7 @@ def pushButton_ResetSettings_clicked(self): confirm_dialog = InputDialogForm(item_list=[("This will reset to the default settings\nProceed?",)]) if confirm_dialog.exec_(): self.set_default_settings() + self.handle_signals_data = None self.config_gui() def checkBox_AutoUpdateAddressTable_state_changed(self): @@ -1983,6 +1996,44 @@ def pushButton_GDBPath_clicked(self): if file_path: self.lineEdit_GDBPath.setText(file_path) + def pushButton_HandleSignals_clicked(self): + if self.handle_signals_data is None: + self.handle_signals_data = self.settings.value("Debug/ignored_signals", type=str).split(",") + signal_dialog = HandleSignalsDialogForm(self.handle_signals_data) + if signal_dialog.exec_(): + self.handle_signals_data = signal_dialog.get_values() + + +class HandleSignalsDialogForm(QDialog, HandleSignalsDialog): + def __init__(self, signal_data, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + self.tableWidget_Signals.setRowCount(len(signal_list)) + for index, state in enumerate(signal_data): + self.tableWidget_Signals.setItem(index, 0, QTableWidgetItem(signal_list[index])) + widget = QWidget() + checkbox = QCheckBox() + layout = QHBoxLayout(widget) + layout.addWidget(checkbox) + layout.setAlignment(Qt.AlignCenter) + layout.setContentsMargins(0, 0, 0, 0) + self.tableWidget_Signals.setCellWidget(index, 1, widget) + if state == "1": + checkbox.setCheckState(Qt.Checked) + else: + checkbox.setCheckState(Qt.Unchecked) + + def get_values(self): + final_state = [] + for index in range(len(signal_list)): + widget = self.tableWidget_Signals.cellWidget(index, 1) + checkbox = widget.findChild(QCheckBox) + if checkbox.checkState() == Qt.Checked: + final_state.append("1") + else: + final_state.append("0") + return final_state + class ConsoleWidgetForm(QWidget, ConsoleWidget): def __init__(self, parent=None): diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index d8a947bb..9109437e 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -464,25 +464,31 @@ def execute_till_return(): #:tag:Debug -def ignore_segfault(ignore): - """Handle the SIGSEGV signal +def ignore_signal(signal_name): + """Ignores the given signal Args: - ignore (bool): Ignores SIGSEGV if True, stops the process otherwise + signal_name (str): Name of the ignored signal """ - if ignore: - send_command("handle SIGSEGV nostop noprint") - else: - send_command("handle SIGSEGV stop print") + send_command("handle " + signal_name + " nostop noprint") + + +#:tag:Debug +def unignore_signal(signal_name): + """Unignores the given signal + + Args: + signal_name (str): Name of the unignored signal + """ + send_command("handle " + signal_name + " stop print") #:tag:GDBCommunication -def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH, ignore_sigsegv=False): +def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): r"""Spawns gdb and initializes/resets some of the global variables Args: gdb_path (str): Path of the gdb binary - ignore_sigsegv (bool): Ignores SIGSEGV signal if True Note: Calling init_gdb() will reset the current session @@ -520,7 +526,6 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH, ignore_sigsegv=False): set_logging(False) send_command("source " + SysUtils.get_user_path(type_defs.USER_PATHS.GDBINIT_PATH)) SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_PATH)) - ignore_segfault(ignore_sigsegv) #:tag:GDBCommunication @@ -562,13 +567,12 @@ def init_referenced_dicts(pid): #:tag:Debug -def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH, ignore_sigsegv=False): +def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): r"""Attaches gdb to the target and initializes some of the global variables Args: pid (int,str): PID of the process that'll be attached to gdb_path (str): Path of the gdb binary - ignore_sigsegv (bool): Ignores SIGSEGV signal if True Returns: tuple: (A member of type_defs.ATTACH_RESULT, result_message) @@ -595,9 +599,7 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH, ignore_sigsegv=False): print(error_message) return attach_result, error_message if currentpid != -1 or not gdb_initialized: - init_gdb(gdb_path, ignore_sigsegv) - else: - ignore_segfault(ignore_sigsegv) + init_gdb(gdb_path) global inferior_arch global mem_file currentpid = pid @@ -617,7 +619,7 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH, ignore_sigsegv=False): #:tag:Debug -def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs.PATHS.GDB_PATH, ignore_sigsegv=False): +def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs.PATHS.GDB_PATH): r"""Creates a new process for debugging and initializes some of the global variables Current process will be detached even if the create_process call fails Make sure to save your data before calling this monstrosity @@ -627,7 +629,6 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs args (str): Arguments of the inferior, optional ld_preload_path (str): Path of the preloaded .so file, optional gdb_path (str): Path of the gdb binary - ignore_sigsegv (bool): Ignores SIGSEGV signal if True Returns: bool: True if the process has been created successfully, False otherwise @@ -639,9 +640,7 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs global inferior_arch global mem_file if currentpid != -1 or not gdb_initialized: - init_gdb(gdb_path, ignore_sigsegv) - else: - ignore_segfault(ignore_sigsegv) + init_gdb(gdb_path) output = send_command("file " + process_path) if common_regexes.gdb_error.search(output): print("An error occurred while trying to create process from the file at " + process_path) From 2744a1bcb987e2503b3283c951888902f5ac8d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 25 Apr 2022 19:55:38 +0300 Subject: [PATCH 004/487] Remove redundant code --- GUI/CustomLabels/FlagRegisterLabel.py | 2 +- PINCE.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/GUI/CustomLabels/FlagRegisterLabel.py b/GUI/CustomLabels/FlagRegisterLabel.py index 0d772a5b..f08980f5 100644 --- a/GUI/CustomLabels/FlagRegisterLabel.py +++ b/GUI/CustomLabels/FlagRegisterLabel.py @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtWidgets import QLabel, QMessageBox +from PyQt5.QtWidgets import QLabel from PyQt5.QtGui import QCursor from PyQt5.QtCore import Qt from libpince import GDB_Engine diff --git a/PINCE.py b/PINCE.py index d039ab9c..99e0ad0d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1802,9 +1802,6 @@ def keyPressEvent(self, QKeyEvent): else: super(TextEditDialogForm, self).keyPressEvent(QKeyEvent) - def accept(self): - super(TextEditDialogForm, self).accept() - class SettingsDialogForm(QDialog, SettingsDialog): def __init__(self, set_default_settings_func, parent=None): From 515f6dfa0226f7ffb49fb48a3b2e28c07758d181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 26 Apr 2022 15:32:58 +0300 Subject: [PATCH 005/487] Remove temporary_execution_bool --- PINCE.py | 5 ++--- libpince/GDB_Engine.py | 10 ---------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/PINCE.py b/PINCE.py index 99e0ad0d..f646b19d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -308,10 +308,9 @@ def run(self): while True: with GDB_Engine.status_changed_condition: GDB_Engine.status_changed_condition.wait() - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_STOPPED and GDB_Engine.temporary_execution_bool != True: - print("execute condition: " + str(GDB_Engine.temporary_execution_bool)) + if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: self.process_stopped.emit() - elif GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING and GDB_Engine.temporary_execution_bool != True: + elif GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: self.process_running.emit() diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 9109437e..d9e5f694 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -82,12 +82,6 @@ # See PINCE's AwaitProcessExit class for an example process_exited_condition = Condition() -#:tag:bool -#:doc: -# Bool for telling CheckInferiorStatus if it's a "real" pause or just for a split -# second that it will continue very soon, used in execute_with_temporary_interruption -temporary_execution_bool = False - #:tag:ConditionsLocks #:doc: # This condition is notified if gdb starts to wait for the prompt output @@ -351,8 +345,6 @@ def execute_func_temporary_interruption(func, *args, **kwargs): Returns: ???: Result of the given function. Return type depends on the given function """ - global temporary_execution_bool - temporary_execution_bool = True old_status = inferior_status if old_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: ___internal_interrupt_inferior(type_defs.STOP_REASON.PAUSE) @@ -432,8 +424,6 @@ def interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): interrupt_reason (int): Just changes the global variable stop_reason. Can be a member of type_defs.STOP_REASON """ global stop_reason - global temporary_execution_bool - temporary_execution_bool = False send_command("c", control=True) wait_for_stop() stop_reason = interrupt_reason From 6bfaa9fbd80b0b0db0b836c2e7bc17d5c503ec77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 4 Jun 2022 23:23:47 +0300 Subject: [PATCH 006/487] Set elide to ElideNone in HexView and AsciiView --- GUI/MemoryViewerWindow.py | 12 ++---------- GUI/MemoryViewerWindow.ui | 12 ++++++++++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 476bbd8f..d907871e 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -608,6 +608,7 @@ def setupUi(self, MainWindow_MemoryView): self.line_5.setObjectName("line_5") self.horizontalLayout_5.addWidget(self.line_5) self.tableView_HexView_Hex = QHexView(self.scrollAreaWidgetContents_2) + self.tableView_HexView_Hex.setTextElideMode(QtCore.Qt.ElideNone) self.tableView_HexView_Hex.setObjectName("tableView_HexView_Hex") self.horizontalLayout_5.addWidget(self.tableView_HexView_Hex) self.line_4 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) @@ -616,6 +617,7 @@ def setupUi(self, MainWindow_MemoryView): self.line_4.setObjectName("line_4") self.horizontalLayout_5.addWidget(self.line_4) self.tableView_HexView_Ascii = QAsciiView(self.scrollAreaWidgetContents_2) + self.tableView_HexView_Ascii.setTextElideMode(QtCore.Qt.ElideNone) self.tableView_HexView_Ascii.setObjectName("tableView_HexView_Ascii") self.horizontalLayout_5.addWidget(self.tableView_HexView_Ascii) spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) @@ -908,13 +910,3 @@ def retranslateUi(self, MainWindow_MemoryView): from GUI.CustomLabels.RegisterLabel import QRegisterLabel from GUI.CustomTableViews.AsciiView import QAsciiView from GUI.CustomTableViews.HexView import QHexView - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - MainWindow_MemoryView = QtWidgets.QMainWindow() - ui = Ui_MainWindow_MemoryView() - ui.setupUi(MainWindow_MemoryView) - MainWindow_MemoryView.show() - sys.exit(app.exec_()) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index c0af65b4..3da9283a 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -1322,7 +1322,11 @@ - + + + Qt::ElideNone + + @@ -1332,7 +1336,11 @@ - + + + Qt::ElideNone + + From 536d18261c43f3fa385562ac7e062253a27a061a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 1 Jul 2022 18:36:47 +0300 Subject: [PATCH 007/487] Implement decreased/increased by N --- GUI/MainWindow.py | 68 +++++++++----------- GUI/MainWindow.ui | 145 +++++++++++++++++++++++------------------- PINCE.py | 15 ++++- libpince/type_defs.py | 18 ++++-- 4 files changed, 130 insertions(+), 116 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 6cdd8b57..4d4c55fb 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -13,7 +13,7 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(768, 659) + MainWindow.resize(678, 636) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) @@ -169,75 +169,78 @@ def setupUi(self, MainWindow): self.pushButton_UndoScan.setObjectName("pushButton_UndoScan") self.horizontalLayout_6.addWidget(self.pushButton_UndoScan) self.verticalLayout_5.addLayout(self.horizontalLayout_6) - self.horizontalLayout_7 = QtWidgets.QHBoxLayout() + self.widget_Scan = QtWidgets.QWidget(self.QWidget_Toolbox) + self.widget_Scan.setObjectName("widget_Scan") + self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.widget_Scan) + self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_7.setObjectName("horizontalLayout_7") - self.widget = QtWidgets.QWidget(self.QWidget_Toolbox) + self.widget_3 = QtWidgets.QWidget(self.widget_Scan) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) - self.widget.setSizePolicy(sizePolicy) - self.widget.setObjectName("widget") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget) + sizePolicy.setHeightForWidth(self.widget_3.sizePolicy().hasHeightForWidth()) + self.widget_3.setSizePolicy(sizePolicy) + self.widget_3.setObjectName("widget_3") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget_3) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(0) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.radioButton_Bits = QtWidgets.QRadioButton(self.widget) + self.radioButton_Bits = QtWidgets.QRadioButton(self.widget_3) self.radioButton_Bits.setObjectName("radioButton_Bits") self.verticalLayout_2.addWidget(self.radioButton_Bits) - self.radioButton_Decimal = QtWidgets.QRadioButton(self.widget) + self.radioButton_Decimal = QtWidgets.QRadioButton(self.widget_3) self.radioButton_Decimal.setObjectName("radioButton_Decimal") self.verticalLayout_2.addWidget(self.radioButton_Decimal) - self.checkBox_Hex = QtWidgets.QCheckBox(self.widget) + self.checkBox_Hex = QtWidgets.QCheckBox(self.widget_3) self.checkBox_Hex.setObjectName("checkBox_Hex") self.verticalLayout_2.addWidget(self.checkBox_Hex) - self.horizontalLayout_7.addWidget(self.widget) - self.lineEdit_Scan = QtWidgets.QLineEdit(self.QWidget_Toolbox) + self.horizontalLayout_7.addWidget(self.widget_3) + self.lineEdit_Scan = QtWidgets.QLineEdit(self.widget_Scan) self.lineEdit_Scan.setObjectName("lineEdit_Scan") self.horizontalLayout_7.addWidget(self.lineEdit_Scan) - self.label_Between = QtWidgets.QLabel(self.QWidget_Toolbox) + self.label_Between = QtWidgets.QLabel(self.widget_Scan) self.label_Between.setObjectName("label_Between") self.horizontalLayout_7.addWidget(self.label_Between) - self.lineEdit_Scan2 = QtWidgets.QLineEdit(self.QWidget_Toolbox) + self.lineEdit_Scan2 = QtWidgets.QLineEdit(self.widget_Scan) self.lineEdit_Scan2.setObjectName("lineEdit_Scan2") self.horizontalLayout_7.addWidget(self.lineEdit_Scan2) - self.verticalLayout_5.addLayout(self.horizontalLayout_7) + self.verticalLayout_5.addWidget(self.widget_Scan) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.widget1 = QtWidgets.QWidget(self.QWidget_Toolbox) - self.widget1.setObjectName("widget1") - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.widget1) + self.widget = QtWidgets.QWidget(self.QWidget_Toolbox) + self.widget.setObjectName("widget") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.widget) self.verticalLayout_4.setObjectName("verticalLayout_4") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.label = QtWidgets.QLabel(self.widget1) + self.label = QtWidgets.QLabel(self.widget) self.label.setObjectName("label") self.horizontalLayout_2.addWidget(self.label) - self.comboBox_ScanType = QtWidgets.QComboBox(self.widget1) + self.comboBox_ScanType = QtWidgets.QComboBox(self.widget) self.comboBox_ScanType.setObjectName("comboBox_ScanType") self.horizontalLayout_2.addWidget(self.comboBox_ScanType) self.verticalLayout_4.addLayout(self.horizontalLayout_2) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.label_2 = QtWidgets.QLabel(self.widget1) + self.label_2 = QtWidgets.QLabel(self.widget) self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) - self.comboBox_ValueType = QtWidgets.QComboBox(self.widget1) + self.comboBox_ValueType = QtWidgets.QComboBox(self.widget) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout.addWidget(self.comboBox_ValueType) self.verticalLayout_4.addLayout(self.horizontalLayout) self.horizontalLayout_10 = QtWidgets.QHBoxLayout() self.horizontalLayout_10.setObjectName("horizontalLayout_10") - self.label_ScanScope = QtWidgets.QLabel(self.widget1) + self.label_ScanScope = QtWidgets.QLabel(self.widget) self.label_ScanScope.setObjectName("label_ScanScope") self.horizontalLayout_10.addWidget(self.label_ScanScope) - self.comboBox_ScanScope = QtWidgets.QComboBox(self.widget1) + self.comboBox_ScanScope = QtWidgets.QComboBox(self.widget) self.comboBox_ScanScope.setObjectName("comboBox_ScanScope") self.horizontalLayout_10.addWidget(self.comboBox_ScanScope) self.verticalLayout_4.addLayout(self.horizontalLayout_10) spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout_4.addItem(spacerItem4) - self.horizontalLayout_4.addWidget(self.widget1) + self.horizontalLayout_4.addWidget(self.widget) self.widget_2 = QtWidgets.QWidget(self.QWidget_Toolbox) self.widget_2.setObjectName("widget_2") self.verticalLayout = QtWidgets.QVBoxLayout(self.widget_2) @@ -275,14 +278,11 @@ def setupUi(self, MainWindow): self.verticalLayout.addLayout(self.verticalLayout_3) self.horizontalLayout_4.addWidget(self.widget_2) self.verticalLayout_5.addLayout(self.horizontalLayout_4) - self.horizontalLayout_3 = QtWidgets.QHBoxLayout() - self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.verticalLayout_5.addLayout(self.horizontalLayout_3) self.horizontalLayout_9.addWidget(self.QWidget_Toolbox) self.gridLayout.addLayout(self.horizontalLayout_9, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 768, 30)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 30)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) @@ -340,13 +340,3 @@ def retranslateUi(self, MainWindow): self.checkBox_CaseSensitive.setText(_translate("MainWindow", "Case Sensitive")) self.checkBox_Unrandomizer.setToolTip(_translate("MainWindow", "Not currently supported")) self.checkBox_Unrandomizer.setText(_translate("MainWindow", "Unrandomizer")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - MainWindow = QtWidgets.QMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 5da5736e..edd5cb88 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -6,8 +6,8 @@ 0 0 - 768 - 659 + 678 + 636 @@ -396,69 +396,83 @@ - - - - - - 0 - 0 - - - - - 0 - - - 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + - - 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + B&its + + + + + + + &Decimal + + + + + + + Hex + + + + + + + + + + + + + <-> - - 0 - - - 0 - - - - - B&its - - - - - - - &Decimal - - - - - - - Hex - - - - - - - - - - - - - <-> - - - - - - - + + + + + + + @@ -641,9 +655,6 @@ - - - @@ -656,7 +667,7 @@ 0 0 - 768 + 678 30 diff --git a/PINCE.py b/PINCE.py index f646b19d..1a1a47a8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -906,6 +906,12 @@ def pushButton_NewFirstScan_clicked(self): self.comboBox_ScanType_init() def comboBox_ScanType_current_index_changed(self): + hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, + type_defs.SCAN_TYPE.UNCHANGED, type_defs.SCAN_TYPE.UNKNOWN] + if self.comboBox_ScanType.currentData(Qt.UserRole) in hidden_types: + self.widget_Scan.setEnabled(False) + else: + self.widget_Scan.setEnabled(True) if self.comboBox_ScanType.currentData(Qt.UserRole) == type_defs.SCAN_TYPE.BETWEEN: self.label_Between.setVisible(True) self.lineEdit_Scan2.setVisible(True) @@ -920,9 +926,10 @@ def comboBox_ScanType_init(self): items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.LESS, type_defs.SCAN_TYPE.MORE, type_defs.SCAN_TYPE.BETWEEN, type_defs.SCAN_TYPE.UNKNOWN] else: - items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, - type_defs.SCAN_TYPE.LESS, type_defs.SCAN_TYPE.MORE, type_defs.SCAN_TYPE.BETWEEN, - type_defs.SCAN_TYPE.CHANGED, type_defs.SCAN_TYPE.UNCHANGED] + items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.INCREASED_BY, + type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.DECREASED_BY, type_defs.SCAN_TYPE.LESS, + type_defs.SCAN_TYPE.MORE, type_defs.SCAN_TYPE.BETWEEN, type_defs.SCAN_TYPE.CHANGED, + type_defs.SCAN_TYPE.UNCHANGED] old_index = 0 for index, type_index in enumerate(items): if current_type == type_index: @@ -977,6 +984,8 @@ def validate_search(self, search_for, search_for2): if type_index == type_defs.SCAN_TYPE.BETWEEN: return search_for + ".." + search_for2 cmp_symbols = { + type_defs.SCAN_TYPE.INCREASED_BY: "+", + type_defs.SCAN_TYPE.DECREASED_BY: "-", type_defs.SCAN_TYPE.LESS: "<", type_defs.SCAN_TYPE.MORE: ">" } diff --git a/libpince/type_defs.py b/libpince/type_defs.py index df4160e9..29c2f507 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -202,20 +202,24 @@ def has_length(value_index): class SCAN_TYPE: EXACT = 0 INCREASED = 1 - DECREASED = 2 - LESS = 3 - MORE = 4 - BETWEEN = 5 - CHANGED = 6 - UNCHANGED = 7 - UNKNOWN = 8 + INCREASED_BY = 2 + DECREASED = 3 + DECREASED_BY = 4 + LESS = 5 + MORE = 6 + BETWEEN = 7 + CHANGED = 8 + UNCHANGED = 9 + UNKNOWN = 10 # Represents the texts at indexes in combobox scan_type_to_text_dict = collections.OrderedDict([ (SCAN_TYPE.EXACT, "Exact Scan"), (SCAN_TYPE.INCREASED, "Increased"), + (SCAN_TYPE.INCREASED_BY, "Increased by"), (SCAN_TYPE.DECREASED, "Decreased"), + (SCAN_TYPE.DECREASED_BY, "Decreased by"), (SCAN_TYPE.LESS, "Less Than"), (SCAN_TYPE.MORE, "More Than"), (SCAN_TYPE.BETWEEN, "Between"), From eaa85c379b8ded09939f76c1a2b66b61ef092a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 2 Jul 2022 20:01:01 +0300 Subject: [PATCH 008/487] Update scanmem submodule --- scanmem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scanmem b/scanmem index 3a7f1199..ac32e5d7 160000 --- a/scanmem +++ b/scanmem @@ -1 +1 @@ -Subproject commit 3a7f11991b9794a16e9dc0fe01b2ec34027312fa +Subproject commit ac32e5d7d7429ec2123c5ff63559bc9ad37b4f09 From c9c6b9bd2ffe9a6ade35bfc64e7511b5486c52ca Mon Sep 17 00:00:00 2001 From: Berk Ozler Date: Sun, 3 Jul 2022 19:48:17 +0300 Subject: [PATCH 009/487] Add nop out instructions feature --- GUI/InstructionsRestoreWidget.py | 47 ++++++++++++++++++ GUI/InstructionsRestoreWidget.ui | 59 +++++++++++++++++++++++ GUI/MemoryViewerWindow.py | 9 +++- GUI/MemoryViewerWindow.ui | 6 +++ PINCE.py | 81 ++++++++++++++++++++++++++++++++ libpince/GDB_Engine.py | 57 ++++++++++++++++++++++ 6 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 GUI/InstructionsRestoreWidget.py create mode 100644 GUI/InstructionsRestoreWidget.ui diff --git a/GUI/InstructionsRestoreWidget.py b/GUI/InstructionsRestoreWidget.py new file mode 100644 index 00000000..02d84405 --- /dev/null +++ b/GUI/InstructionsRestoreWidget.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'InstructionsRestoreWidget.ui' +# +# Created by: PyQt5 UI code generator 5.15.7 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(684, 539) + self.gridLayout = QtWidgets.QGridLayout(Form) + self.gridLayout.setObjectName("gridLayout") + self.tableWidget_Instructions = QtWidgets.QTableWidget(Form) + self.tableWidget_Instructions.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableWidget_Instructions.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.tableWidget_Instructions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Instructions.setObjectName("tableWidget_Instructions") + self.tableWidget_Instructions.setColumnCount(2) + self.tableWidget_Instructions.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Instructions.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Instructions.setHorizontalHeaderItem(1, item) + self.tableWidget_Instructions.horizontalHeader().setStretchLastSection(True) + self.tableWidget_Instructions.verticalHeader().setVisible(False) + self.tableWidget_Instructions.verticalHeader().setDefaultSectionSize(16) + self.tableWidget_Instructions.verticalHeader().setMinimumSectionSize(16) + self.gridLayout.addWidget(self.tableWidget_Instructions, 0, 0, 1, 1) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Restore Instructions")) + self.tableWidget_Instructions.setSortingEnabled(True) + item = self.tableWidget_Instructions.horizontalHeaderItem(0) + item.setText(_translate("Form", "Address")) + item = self.tableWidget_Instructions.horizontalHeaderItem(1) + item.setText(_translate("Form", "Original Instruction")) diff --git a/GUI/InstructionsRestoreWidget.ui b/GUI/InstructionsRestoreWidget.ui new file mode 100644 index 00000000..427fbc5e --- /dev/null +++ b/GUI/InstructionsRestoreWidget.ui @@ -0,0 +1,59 @@ + + + Form + + + + 0 + 0 + 684 + 539 + + + + Restore Instructions + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + false + + + 16 + + + 16 + + + + Address + + + + + Original Instruction + + + + + + + + + diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index d907871e..5b16a0c1 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -2,9 +2,10 @@ # Form implementation generated from reading ui file 'MemoryViewerWindow.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt5 UI code generator 5.15.7 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets @@ -766,12 +767,15 @@ def setupUi(self, MainWindow_MemoryView): self.actionReferenced_Calls.setObjectName("actionReferenced_Calls") self.actionToggle_Attach = QtWidgets.QAction(MainWindow_MemoryView) self.actionToggle_Attach.setObjectName("actionToggle_Attach") + self.actionRestore_Instructions = QtWidgets.QAction(MainWindow_MemoryView) + self.actionRestore_Instructions.setObjectName("actionRestore_Instructions") self.menuView.addAction(self.actionBookmarks) self.menuView.addAction(self.actionStackTrace_Info) self.menuView.addAction(self.actionBreakpoints) self.menuView.addAction(self.actionFunctions) self.menuView.addAction(self.actionGDB_Log_File) self.menuView.addAction(self.actionMemory_Regions) + self.menuView.addAction(self.actionRestore_Instructions) self.menuView.addSeparator() self.menuView.addAction(self.actionReferenced_Strings) self.menuView.addAction(self.actionReferenced_Calls) @@ -906,6 +910,7 @@ def retranslateUi(self, MainWindow_MemoryView): self.actionReferenced_Strings.setText(_translate("MainWindow_MemoryView", "R&eferenced Strings")) self.actionReferenced_Calls.setText(_translate("MainWindow_MemoryView", "Referenced &Calls")) self.actionToggle_Attach.setText(_translate("MainWindow_MemoryView", "To&ggle Attach")) + self.actionRestore_Instructions.setText(_translate("MainWindow_MemoryView", "Restore Instructions")) from GUI.CustomLabels.FlagRegisterLabel import QFlagRegisterLabel from GUI.CustomLabels.RegisterLabel import QRegisterLabel from GUI.CustomTableViews.AsciiView import QAsciiView diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 3da9283a..c3a176fb 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -1560,6 +1560,7 @@ + @@ -1717,6 +1718,11 @@ To&ggle Attach + + + Restore Instructions + + diff --git a/PINCE.py b/PINCE.py index 1a1a47a8..a132a1aa 100755 --- a/PINCE.py +++ b/PINCE.py @@ -64,6 +64,7 @@ from GUI.ReferencedStringsWidget import Ui_Form as ReferencedStringsWidget from GUI.ReferencedCallsWidget import Ui_Form as ReferencedCallsWidget from GUI.ExamineReferrersWidget import Ui_Form as ExamineReferrersWidget +from GUI.InstructionsRestoreWidget import Ui_Form as InstructionsRestoreWidget from GUI.CustomAbstractTableModels.HexModel import QHexModel from GUI.CustomAbstractTableModels.AsciiModel import QAsciiModel @@ -112,6 +113,10 @@ def get_hotkeys(): ignored_signals = str signal_list = ["SIGUSR1", "SIGPWR", "SIGSEGV"] +# represents the index of columns in instructions restore table +INSTR_ADDR_COL = 0 +INSTR_AOB_COL = 1 + # represents the index of columns in breakpoint table BREAK_NUM_COL = 0 BREAK_TYPE_COL = 1 @@ -2267,6 +2272,7 @@ def initialize_view_context_menu(self): self.actionFunctions.triggered.connect(self.actionFunctions_triggered) self.actionGDB_Log_File.triggered.connect(self.actionGDB_Log_File_triggered) self.actionMemory_Regions.triggered.connect(self.actionMemory_Regions_triggered) + self.actionRestore_Instructions.triggered.connect(self.actionRestore_Instructions_triggered) self.actionReferenced_Strings.triggered.connect(self.actionReferenced_Strings_triggered) self.actionReferenced_Calls.triggered.connect(self.actionReferenced_Calls_triggered) @@ -2430,6 +2436,15 @@ def set_address(self): GDB_Engine.set_convenience_variable("pc", current_address) self.refresh_disassemble_view() + def nop_instruction(self): + selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() + current_address = SysUtils.extract_address(current_address_text) + current_address_int = int(current_address, 16) + array_of_bytes = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text().split() + GDB_Engine.nop_instruction(current_address_int, array_of_bytes) + self.refresh_disassemble_view() + @GDB_Engine.execute_with_temporary_interruption def toggle_breakpoint(self): selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) @@ -3230,6 +3245,9 @@ def copy_all_columns(row): if not GDB_Engine.check_address_in_breakpoints(current_address_int): GuiUtils.delete_menu_entries(menu, [add_condition]) menu.addSeparator() + if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() != '90': + nop_instruction = menu.addAction("Replace instruction with NOPs") + menu.addSeparator() track_breakpoint = menu.addAction("Find out which addresses this instruction accesses") trace_instructions = menu.addAction("Break and trace instructions[Ctrl+T]") dissect_region = menu.addAction("Dissect this region[Ctrl+D]") @@ -3256,6 +3274,7 @@ def copy_all_columns(row): change_comment: lambda: self.change_bookmark_comment(current_address_int), toggle_breakpoint: self.toggle_breakpoint, add_condition: lambda: self.add_breakpoint_condition(current_address_int), + nop_instruction: self.nop_instruction, track_breakpoint: self.exec_track_breakpoint_dialog, trace_instructions: self.exec_trace_instructions_dialog, dissect_region: self.dissect_current_region, @@ -3368,6 +3387,10 @@ def actionMemory_Regions_triggered(self): memory_regions_widget = MemoryRegionsWidgetForm(self) memory_regions_widget.show() + def actionRestore_Instructions_triggered(self): + restore_instructions_widget = InstructionsRestoreWidgetForm(self) + restore_instructions_widget.show() + def actionReferenced_Strings_triggered(self): ref_str_widget = ReferencedStringsWidgetForm(self) ref_str_widget.show() @@ -3573,6 +3596,64 @@ def update_frame_info(self, index): self.textBrowser_Info.setText(frame_info) +class InstructionsRestoreWidgetForm(QWidget, InstructionsRestoreWidget): + def __init__(self, parent=None): + super().__init__() + self.setupUi(self) + self.parent = lambda: parent + global instances + instances.append(self) + GuiUtils.center(self) + self.setWindowFlags(Qt.Window) + self.refresh() + self.tableWidget_Instructions.contextMenuEvent = self.tableWidget_Instructions_context_menu_event + + def tableWidget_Instructions_context_menu_event(self, event): + selected_row = GuiUtils.get_current_row(self.tableWidget_Instructions) + if selected_row != -1: + selected_address_text = self.tableWidget_Instructions.item(selected_row, INSTR_ADDR_COL).text() + selected_address = SysUtils.extract_address(selected_address_text) + selected_address_int = int(selected_address, 16) + bytes_to_restore = self.tableWidget_Instructions.item(selected_row, INSTR_AOB_COL).text().split() + else: + selected_address_int = None + bytes_to_restore = None + + if selected_address_int is not None: + menu = QMenu() + restore_instruction = menu.addAction("Restore this instruction") + + font_size = self.tableWidget_Instructions.font().pointSize() + menu.setStyleSheet("font-size: " + str(font_size) + "pt;") + action = menu.exec_(event.globalPos()) + actions = { + restore_instruction: lambda: GDB_Engine.restore_instruction(selected_address_int, bytes_to_restore), + } + try: + actions[action]() + except KeyError: + pass + if action != -1 and action is not None: + self.refresh_all() + + def refresh(self): + noped_instructions = GDB_Engine.get_noped_instructions() + self.tableWidget_Instructions.setRowCount(len(noped_instructions)) + for row, (address, aob) in enumerate(noped_instructions.items()): + self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) + self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(' '.join(aob))) + self.tableWidget_Instructions.resizeColumnsToContents() + self.tableWidget_Instructions.horizontalHeader().setStretchLastSection(True) + + def refresh_all(self): + self.parent().refresh_hex_view() + self.parent().refresh_disassemble_view() + self.refresh() + + def closeEvent(self, QCloseEvent): + global instances + instances.remove(self) + class BreakpointInfoWidgetForm(QTabWidget, BreakpointInfoWidget): def __init__(self, parent=None): super().__init__() diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index d9e5f694..f6ba61f1 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -55,6 +55,12 @@ # Format: {address1:on_hit1, address2:on_hit2, ...} breakpoint_on_hit_dict = {} +#:tag:GDBInformation +#:doc: +# A dictionary. Holds address and aob of instructions that were nop'ed out +# Format: {address1:orig_instruction1_aob, address2:orig_instruction2_aob, ...} +noped_instructions_dict = {} + #:tag:GDBInformation #:doc: # If an action such as deletion or condition modification happens in one of the breakpoints in a list, others in the @@ -1319,6 +1325,57 @@ def hex_dump(address, offset): return hex_byte_list +#:tag:MemoryRW +def get_noped_instructions(): + """Returns currently NOP'ed out instructions + + Returns: + dict: A dictionary where the key is the start address of instruction and value is the aob before NOP'ing + + """ + global noped_instructions_dict + return noped_instructions_dict + + +#:tag:MemoryRW +def nop_instruction(start_address, array_of_bytes): + """Replaces an instruction's opcodes with NOPs + + Args: + start_address (int): Self-explanatory + array_of_bytes (list): List of strings that contain the bytes of the instruction + + Returns: + None + """ + global noped_instructions_dict + noped_instructions_dict[start_address] = array_of_bytes + + for i in range(0, len(array_of_bytes)): + current_address = start_address + i + send_command("set *(unsigned char*)" + str(current_address) + " = 0x90") + + +#:tag:MemoryRW +def restore_instruction(start_address, array_of_bytes): + """Restores a NOP'ed out instruction to it's original opcodes + + Args: + start_address (int): Self-explanatory + array_of_bytes (list): List of strings that contain the bytes of the instruction before NOP'ing + + Returns: + None + """ + global noped_instructions_dict + noped_instructions_dict.pop(start_address) + + current_address = start_address + for byte in array_of_bytes: + send_command("set *(unsigned char*)" + str(current_address) + " = 0x" + byte) + current_address = current_address + 1 + + #:tag:BreakWatchpoints def get_breakpoint_info(): """Returns current breakpoint/watchpoint list From 2accfd806ce60101de4e106416b98b850e78aceb Mon Sep 17 00:00:00 2001 From: Berk Ozler Date: Sun, 3 Jul 2022 22:59:45 +0300 Subject: [PATCH 010/487] Changed nop/restore instructions to use write_memory --- PINCE.py | 8 +++----- libpince/GDB_Engine.py | 18 ++++++------------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/PINCE.py b/PINCE.py index a132a1aa..5c96ce5d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2441,7 +2441,7 @@ def nop_instruction(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_address_int = int(current_address, 16) - array_of_bytes = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text().split() + array_of_bytes = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() GDB_Engine.nop_instruction(current_address_int, array_of_bytes) self.refresh_disassemble_view() @@ -3614,10 +3614,8 @@ def tableWidget_Instructions_context_menu_event(self, event): selected_address_text = self.tableWidget_Instructions.item(selected_row, INSTR_ADDR_COL).text() selected_address = SysUtils.extract_address(selected_address_text) selected_address_int = int(selected_address, 16) - bytes_to_restore = self.tableWidget_Instructions.item(selected_row, INSTR_AOB_COL).text().split() else: selected_address_int = None - bytes_to_restore = None if selected_address_int is not None: menu = QMenu() @@ -3627,7 +3625,7 @@ def tableWidget_Instructions_context_menu_event(self, event): menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec_(event.globalPos()) actions = { - restore_instruction: lambda: GDB_Engine.restore_instruction(selected_address_int, bytes_to_restore), + restore_instruction: lambda: GDB_Engine.restore_instruction(selected_address_int) } try: actions[action]() @@ -3641,7 +3639,7 @@ def refresh(self): self.tableWidget_Instructions.setRowCount(len(noped_instructions)) for row, (address, aob) in enumerate(noped_instructions.items()): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) - self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(' '.join(aob))) + self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) self.tableWidget_Instructions.resizeColumnsToContents() self.tableWidget_Instructions.horizontalHeader().setStretchLastSection(True) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index f6ba61f1..b637c797 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -1343,7 +1343,7 @@ def nop_instruction(start_address, array_of_bytes): Args: start_address (int): Self-explanatory - array_of_bytes (list): List of strings that contain the bytes of the instruction + array_of_bytes (str): String that contains the bytes of the instruction Returns: None @@ -1351,29 +1351,23 @@ def nop_instruction(start_address, array_of_bytes): global noped_instructions_dict noped_instructions_dict[start_address] = array_of_bytes - for i in range(0, len(array_of_bytes)): - current_address = start_address + i - send_command("set *(unsigned char*)" + str(current_address) + " = 0x90") + nop_aob = '90 ' * len(array_of_bytes.split()) + write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, nop_aob) #:tag:MemoryRW -def restore_instruction(start_address, array_of_bytes): +def restore_instruction(start_address): """Restores a NOP'ed out instruction to it's original opcodes Args: start_address (int): Self-explanatory - array_of_bytes (list): List of strings that contain the bytes of the instruction before NOP'ing Returns: None """ global noped_instructions_dict - noped_instructions_dict.pop(start_address) - - current_address = start_address - for byte in array_of_bytes: - send_command("set *(unsigned char*)" + str(current_address) + " = 0x" + byte) - current_address = current_address + 1 + array_of_bytes = noped_instructions_dict.pop(start_address) + write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, array_of_bytes) #:tag:BreakWatchpoints From d821c52a302f57642f0ba0439557285e777bb679 Mon Sep 17 00:00:00 2001 From: Berk Ozler Date: Mon, 4 Jul 2022 01:23:25 +0300 Subject: [PATCH 011/487] Fix column stretch issues --- PINCE.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 5c96ce5d..5a43a9f1 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3605,6 +3605,7 @@ def __init__(self, parent=None): instances.append(self) GuiUtils.center(self) self.setWindowFlags(Qt.Window) + self.tableWidget_Instructions.horizontalHeader().setStretchLastSection(True) self.refresh() self.tableWidget_Instructions.contextMenuEvent = self.tableWidget_Instructions_context_menu_event @@ -3640,8 +3641,8 @@ def refresh(self): for row, (address, aob) in enumerate(noped_instructions.items()): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) - self.tableWidget_Instructions.resizeColumnsToContents() - self.tableWidget_Instructions.horizontalHeader().setStretchLastSection(True) + if len(noped_instructions) != 0: + self.tableWidget_Instructions.resizeColumnsToContents() def refresh_all(self): self.parent().refresh_hex_view() From d85253c2367c7fcbc7450c7f54efcf327879afac Mon Sep 17 00:00:00 2001 From: Ali Koca Date: Mon, 4 Jul 2022 08:22:10 +0300 Subject: [PATCH 012/487] Github username fix ... --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 204c347a..6485e107 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run GPLv3+. See COPYING file for details # Contact Information -Korcan Karaokçu([korcankaraokcu](https://github.com/cagriulas)) +Korcan Karaokçu([korcankaraokcu](https://github.com/korcankaraokcu)) Çağrı Ulaş([cagriulas](https://github.com/cagriulas)) Jakob Kreuze([TsarFox](https://github.com/TsarFox)) Gibus From 5c8a52b57a6cfab829e815385d10866c24c6ac64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 4 Jul 2022 22:09:02 +0300 Subject: [PATCH 013/487] Implement GuiUtils.resize_to_contents --- PINCE.py | 34 +++++++++++----------------------- libpince/GuiUtils.py | 13 +++++++++++++ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/PINCE.py b/PINCE.py index 5a43a9f1..42999bcf 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2792,7 +2792,6 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his jmp_dict.close() call_dict.close() self.handle_colours(row_colour) - self.tableWidget_Disassemble.horizontalHeader().setStretchLastSection(True) # We append the old record to travel history as last action because we wouldn't like to see unnecessary # addresses in travel history if any error occurs while displaying the next location @@ -3605,7 +3604,6 @@ def __init__(self, parent=None): instances.append(self) GuiUtils.center(self) self.setWindowFlags(Qt.Window) - self.tableWidget_Instructions.horizontalHeader().setStretchLastSection(True) self.refresh() self.tableWidget_Instructions.contextMenuEvent = self.tableWidget_Instructions_context_menu_event @@ -3641,8 +3639,7 @@ def refresh(self): for row, (address, aob) in enumerate(noped_instructions.items()): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) - if len(noped_instructions) != 0: - self.tableWidget_Instructions.resizeColumnsToContents() + GuiUtils.resize_to_contents(self.tableWidget_Instructions) def refresh_all(self): self.parent().refresh_hex_view() @@ -3653,6 +3650,7 @@ def closeEvent(self, QCloseEvent): global instances instances.remove(self) + class BreakpointInfoWidgetForm(QTabWidget, BreakpointInfoWidget): def __init__(self, parent=None): super().__init__() @@ -3684,8 +3682,7 @@ def refresh(self): self.tableWidget_BreakpointInfo.setItem(row, BREAK_ON_HIT_COL, QTableWidgetItem(item.on_hit)) self.tableWidget_BreakpointInfo.setItem(row, BREAK_HIT_COUNT_COL, QTableWidgetItem(item.hit_count)) self.tableWidget_BreakpointInfo.setItem(row, BREAK_COND_COL, QTableWidgetItem(item.condition)) - self.tableWidget_BreakpointInfo.resizeColumnsToContents() - self.tableWidget_BreakpointInfo.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_BreakpointInfo) self.textBrowser_BreakpointInfo.clear() self.textBrowser_BreakpointInfo.setText(GDB_Engine.send_command("info break", cli_output=True)) @@ -3836,9 +3833,7 @@ def __init__(self, address, length, watchpoint_type, parent=None): def update_list(self): info = GDB_Engine.get_track_watchpoint_info(self.breakpoints) - if not info: - return - if self.info == info: + if not info or self.info == info: return self.info = info self.tableWidget_Opcodes.setRowCount(0) @@ -3846,8 +3841,7 @@ def update_list(self): for row, key in enumerate(info): self.tableWidget_Opcodes.setItem(row, TRACK_WATCHPOINT_COUNT_COL, QTableWidgetItem(str(info[key][0]))) self.tableWidget_Opcodes.setItem(row, TRACK_WATCHPOINT_ADDR_COL, QTableWidgetItem(info[key][1])) - self.tableWidget_Opcodes.resizeColumnsToContents() - self.tableWidget_Opcodes.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_Opcodes) self.tableWidget_Opcodes.selectRow(self.last_selected_row) def tableWidget_Opcodes_current_changed(self, QModelIndex_current): @@ -3957,8 +3951,7 @@ def update_list(self): self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_ADDR_COL, QTableWidgetItem(address)) self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_SOURCE_COL, QTableWidgetItem("[" + register_expression + "]")) - self.tableWidget_TrackInfo.resizeColumnsToContents() - self.tableWidget_TrackInfo.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_TrackInfo) self.tableWidget_TrackInfo.selectRow(self.last_selected_row) def update_values(self): @@ -3971,8 +3964,7 @@ def update_values(self): for row, value in enumerate(value_list): value = "" if value is None else str(value) self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_VALUE_COL, QTableWidgetItem(value)) - self.tableWidget_TrackInfo.resizeColumnsToContents() - self.tableWidget_TrackInfo.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_TrackInfo) self.tableWidget_TrackInfo.selectRow(self.last_selected_row) def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): @@ -4257,8 +4249,7 @@ def apply_data(self, output): self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_ADDR_COL, address_item) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_SYMBOL_COL, QTableWidgetItem(item[1])) self.tableWidget_SymbolInfo.setSortingEnabled(True) - self.tableWidget_SymbolInfo.resizeColumnsToContents() - self.tableWidget_SymbolInfo.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_SymbolInfo) def tableWidget_SymbolInfo_current_changed(self, QModelIndex_current): self.textBrowser_AddressInfo.clear() @@ -4564,8 +4555,7 @@ def fill_resource_table(self): self.tableWidget_ResourceTable.setItem(row, LIBPINCE_REFERENCE_VALUE_COL, table_widget_item_value) self.tableWidget_ResourceTable.setSortingEnabled(True) self.tableWidget_ResourceTable.sortByColumn(LIBPINCE_REFERENCE_ITEM_COL, Qt.AscendingOrder) - self.tableWidget_ResourceTable.resizeColumnsToContents() - self.tableWidget_ResourceTable.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_ResourceTable) def pushButton_TextDown_clicked(self): if self.found_count == 0: @@ -4834,8 +4824,7 @@ def refresh_table(self): self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_ANON_COL, QTableWidgetItem(hex(region.anonymous))) self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_SWAP_COL, QTableWidgetItem(hex(region.swap))) - self.tableWidget_MemoryRegions.resizeColumnsToContents() - self.tableWidget_MemoryRegions.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_MemoryRegions) def tableWidget_MemoryRegions_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -4957,8 +4946,7 @@ def show_memory_regions(self): for row, region in enumerate(executable_regions): self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_ADDR_COL, QTableWidgetItem(region.addr)) self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_PATH_COL, QTableWidgetItem(region.path)) - self.tableWidget_ExecutableMemoryRegions.resizeColumnsToContents() - self.tableWidget_ExecutableMemoryRegions.horizontalHeader().setStretchLastSection(True) + GuiUtils.resize_to_contents(self.tableWidget_ExecutableMemoryRegions) def scan_finished(self): self.init_pre_scan_gui() diff --git a/libpince/GuiUtils.py b/libpince/GuiUtils.py index dfee4781..d7502f1b 100644 --- a/libpince/GuiUtils.py +++ b/libpince/GuiUtils.py @@ -77,6 +77,19 @@ def center_scroll_bar(QScrollBar): QScrollBar.setValue((maximum + minimum) // 2) +#:tag:GUI +def resize_to_contents(QTableWidget): + """Resizes the columns of the given QTableWidget to its contents + This also fixes the stretch problem of the last column + + Args: + QTableWidget (QTableWidget): Self-explanatory + """ + QTableWidget.resizeColumnsToContents() + default_size = QTableWidget.horizontalHeader().defaultSectionSize() + QTableWidget.horizontalHeader().resizeSection(QTableWidget.columnCount() - 1, default_size) + + #:tag:GUI def fill_value_combobox(QCombobox, current_index=type_defs.VALUE_INDEX.INDEX_4BYTES): """Fills the given QCombobox with value_index strings From a60d8026df5f1ac2cac6066fdb92b8c6d42a4cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 4 Jul 2022 22:54:33 +0300 Subject: [PATCH 014/487] Fix nop_instruction action --- PINCE.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index 42999bcf..023d07ad 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3244,9 +3244,10 @@ def copy_all_columns(row): if not GDB_Engine.check_address_in_breakpoints(current_address_int): GuiUtils.delete_menu_entries(menu, [add_condition]) menu.addSeparator() - if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() != '90': - nop_instruction = menu.addAction("Replace instruction with NOPs") - menu.addSeparator() + nop_instruction = menu.addAction("Replace instruction with NOPs") + if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() == '90': + GuiUtils.delete_menu_entries(menu, [nop_instruction]) + menu.addSeparator() track_breakpoint = menu.addAction("Find out which addresses this instruction accesses") trace_instructions = menu.addAction("Break and trace instructions[Ctrl+T]") dissect_region = menu.addAction("Dissect this region[Ctrl+D]") From 8443e270f099ebbf60143a6e4a13d69a50acc996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 5 Jul 2022 01:38:18 +0300 Subject: [PATCH 015/487] Add refresh to InstructionsRestoreWidget --- PINCE.py | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/PINCE.py b/PINCE.py index 023d07ad..0f83a9b1 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3605,34 +3605,41 @@ def __init__(self, parent=None): instances.append(self) GuiUtils.center(self) self.setWindowFlags(Qt.Window) - self.refresh() + + # Saving the original function because super() doesn't work when we override functions like this + self.tableWidget_Instructions.keyPressEvent_original = self.tableWidget_Instructions.keyPressEvent + self.tableWidget_Instructions.keyPressEvent = self.tableWidget_Instructions_key_press_event self.tableWidget_Instructions.contextMenuEvent = self.tableWidget_Instructions_context_menu_event + self.refresh() def tableWidget_Instructions_context_menu_event(self, event): selected_row = GuiUtils.get_current_row(self.tableWidget_Instructions) + menu = QMenu() + restore_instruction = menu.addAction("Restore this instruction") if selected_row != -1: selected_address_text = self.tableWidget_Instructions.item(selected_row, INSTR_ADDR_COL).text() selected_address = SysUtils.extract_address(selected_address_text) selected_address_int = int(selected_address, 16) else: + GuiUtils.delete_menu_entries(menu, [restore_instruction]) selected_address_int = None - - if selected_address_int is not None: - menu = QMenu() - restore_instruction = menu.addAction("Restore this instruction") - + menu.addSeparator() + refresh = menu.addAction("Refresh[R]") font_size = self.tableWidget_Instructions.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec_(event.globalPos()) actions = { - restore_instruction: lambda: GDB_Engine.restore_instruction(selected_address_int) + restore_instruction: lambda: self.restore_instruction(selected_address_int), + refresh: self.refresh } try: actions[action]() except KeyError: pass - if action != -1 and action is not None: - self.refresh_all() + + def restore_instruction(self, selected_address_int): + GDB_Engine.restore_instruction(selected_address_int) + self.refresh_all() def refresh(self): noped_instructions = GDB_Engine.get_noped_instructions() @@ -3647,6 +3654,16 @@ def refresh_all(self): self.parent().refresh_disassemble_view() self.refresh() + def tableWidget_Instructions_key_press_event(self, event): + actions = type_defs.KeyboardModifiersTupleDict([ + ((Qt.NoModifier, Qt.Key_R), self.refresh) + ]) + try: + actions[event.modifiers(), event.key()]() + except KeyError: + pass + self.tableWidget_Instructions.keyPressEvent_original(event) + def closeEvent(self, QCloseEvent): global instances instances.remove(self) From e5c79eb4b19aa832148d223b6291e51065883234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 5 Jul 2022 15:43:19 +0300 Subject: [PATCH 016/487] Rename to RestoreInstructionsWidget for consistency Also fixed its size a bit --- ...ionsRestoreWidget.py => RestoreInstructionsWidget.py} | 9 ++++----- ...ionsRestoreWidget.ui => RestoreInstructionsWidget.ui} | 4 ++-- PINCE.py | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) rename GUI/{InstructionsRestoreWidget.py => RestoreInstructionsWidget.py} (86%) rename GUI/{InstructionsRestoreWidget.ui => RestoreInstructionsWidget.ui} (96%) diff --git a/GUI/InstructionsRestoreWidget.py b/GUI/RestoreInstructionsWidget.py similarity index 86% rename from GUI/InstructionsRestoreWidget.py rename to GUI/RestoreInstructionsWidget.py index 02d84405..1501dee7 100644 --- a/GUI/InstructionsRestoreWidget.py +++ b/GUI/RestoreInstructionsWidget.py @@ -1,11 +1,10 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'InstructionsRestoreWidget.ui' +# Form implementation generated from reading ui file 'RestoreInstructionsWidget.ui' # -# Created by: PyQt5 UI code generator 5.15.7 +# Created by: PyQt5 UI code generator 5.14.1 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. +# WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets @@ -14,7 +13,7 @@ class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") - Form.resize(684, 539) + Form.resize(400, 400) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.tableWidget_Instructions = QtWidgets.QTableWidget(Form) diff --git a/GUI/InstructionsRestoreWidget.ui b/GUI/RestoreInstructionsWidget.ui similarity index 96% rename from GUI/InstructionsRestoreWidget.ui rename to GUI/RestoreInstructionsWidget.ui index 427fbc5e..08232cce 100644 --- a/GUI/InstructionsRestoreWidget.ui +++ b/GUI/RestoreInstructionsWidget.ui @@ -6,8 +6,8 @@ 0 0 - 684 - 539 + 400 + 400 diff --git a/PINCE.py b/PINCE.py index 0f83a9b1..8c65e8d3 100755 --- a/PINCE.py +++ b/PINCE.py @@ -64,7 +64,7 @@ from GUI.ReferencedStringsWidget import Ui_Form as ReferencedStringsWidget from GUI.ReferencedCallsWidget import Ui_Form as ReferencedCallsWidget from GUI.ExamineReferrersWidget import Ui_Form as ExamineReferrersWidget -from GUI.InstructionsRestoreWidget import Ui_Form as InstructionsRestoreWidget +from GUI.RestoreInstructionsWidget import Ui_Form as RestoreInstructionsWidget from GUI.CustomAbstractTableModels.HexModel import QHexModel from GUI.CustomAbstractTableModels.AsciiModel import QAsciiModel @@ -3388,7 +3388,7 @@ def actionMemory_Regions_triggered(self): memory_regions_widget.show() def actionRestore_Instructions_triggered(self): - restore_instructions_widget = InstructionsRestoreWidgetForm(self) + restore_instructions_widget = RestoreInstructionsWidgetForm(self) restore_instructions_widget.show() def actionReferenced_Strings_triggered(self): @@ -3596,7 +3596,7 @@ def update_frame_info(self, index): self.textBrowser_Info.setText(frame_info) -class InstructionsRestoreWidgetForm(QWidget, InstructionsRestoreWidget): +class RestoreInstructionsWidgetForm(QWidget, RestoreInstructionsWidget): def __init__(self, parent=None): super().__init__() self.setupUi(self) From 5fd8a2a0a7cafd7a0efef4c6b11f8a61176c3fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 6 Jul 2022 00:41:28 +0300 Subject: [PATCH 017/487] Fix dissect_code output --- libpince/gdb_python_scripts/GDBCommandExtensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 46c21f12..2e34c3de 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -474,7 +474,7 @@ def invoke(self, arg, from_tty): region_finished = True else: offset = buffer - status_info = region_info + (hex(start_addr) + "-" + hex(start_addr + offset), + status_info = region_info + (hex(start_addr)[2:] + "-" + hex(start_addr + offset)[2:], ref_str_count, ref_jmp_count, ref_call_count) pickle.dump(status_info, open(dissect_code_status_file, "wb")) try: From 488afe8c5744289bccc18ea0356bc258932f57b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 6 Jul 2022 00:45:39 +0300 Subject: [PATCH 018/487] Fix dissect_code docs --- libpince/GDB_Engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index b637c797..bb3a6984 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -1985,7 +1985,7 @@ def dissect_code(region_list, discard_invalid_strings=True): Args: region_list (list): A list of psutil._pslinux.pmmap_ext objects - Can be returned from functions like SysUtils.get_memory_regions_by_perms + Can be returned from functions like SysUtils.filter_memory_regions discard_invalid_strings (bool): Entries that can't be decoded as utf-8 won't be included in referenced strings """ send_command("pince-dissect-code", send_with_file=True, file_contents_send=(region_list, discard_invalid_strings)) From 2b80f6bf2aab2e0a99f528355ac8bb78a4dea129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 6 Jul 2022 15:04:26 +0300 Subject: [PATCH 019/487] Fix dissect_code file access issues --- PINCE.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 8c65e8d3..3a777aa2 100755 --- a/PINCE.py +++ b/PINCE.py @@ -5023,7 +5023,11 @@ def __init__(self, parent=None): self.listWidget_Referrers.resize(400, self.listWidget_Referrers.height()) self.hex_len = 16 if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64 else 8 str_dict, jmp_dict, call_dict = GDB_Engine.get_dissect_code_data() - if len(str_dict) == 0 and len(jmp_dict) == 0 and len(call_dict) == 0: + str_dict_len, jmp_dict_len, call_dict_len = len(str_dict), len(jmp_dict), len(call_dict) + str_dict.close() + jmp_dict.close() + call_dict.close() + if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: confirm_dialog = InputDialogForm(item_list=[("You need to dissect code first\nProceed?",)]) if confirm_dialog.exec_(): dissect_code_dialog = DissectCodeDialogForm() @@ -5157,15 +5161,16 @@ def __init__(self, parent=None): self.listWidget_Referrers.resize(400, self.listWidget_Referrers.height()) self.hex_len = 16 if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64 else 8 str_dict, jmp_dict, call_dict = GDB_Engine.get_dissect_code_data() - if len(str_dict) == 0 and len(jmp_dict) == 0 and len(call_dict) == 0: + str_dict_len, jmp_dict_len, call_dict_len = len(str_dict), len(jmp_dict), len(call_dict) + str_dict.close() + jmp_dict.close() + call_dict.close() + if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: confirm_dialog = InputDialogForm(item_list=[("You need to dissect code first\nProceed?",)]) if confirm_dialog.exec_(): dissect_code_dialog = DissectCodeDialogForm() dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec_() - str_dict.close() - jmp_dict.close() - call_dict.close() self.refresh_table() self.tableWidget_References.sortByColumn(REF_CALL_ADDR_COL, Qt.AscendingOrder) self.tableWidget_References.selectionModel().currentChanged.connect(self.tableWidget_References_current_changed) From a4a1aa52adf06199f6c03dbec80b7d567e627728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 6 Jul 2022 15:06:35 +0300 Subject: [PATCH 020/487] Hotfix shared memory file closed twice --- PINCE.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index 3a777aa2..99cb21d2 100755 --- a/PINCE.py +++ b/PINCE.py @@ -5033,9 +5033,6 @@ def __init__(self, parent=None): dissect_code_dialog = DissectCodeDialogForm() dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec_() - str_dict.close() - jmp_dict.close() - call_dict.close() self.refresh_table() self.tableWidget_References.sortByColumn(REF_STR_ADDR_COL, Qt.AscendingOrder) self.tableWidget_References.selectionModel().currentChanged.connect(self.tableWidget_References_current_changed) From 23cba1faa3993bc4cf3ead2462b7ec5dff5ce006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 8 Jul 2022 17:33:02 +0300 Subject: [PATCH 021/487] Support all scanmem types --- PINCE.py | 97 +++++++++++++++----------------- README.md | 2 +- libpince/GDB_Engine.py | 15 +---- libpince/GuiUtils.py | 4 +- libpince/SysUtils.py | 12 ++-- libpince/type_defs.py | 125 ++++++++++++++++++++++++++--------------- 6 files changed, 137 insertions(+), 118 deletions(-) diff --git a/PINCE.py b/PINCE.py index 99cb21d2..273d421e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -142,6 +142,11 @@ def get_hotkeys(): TYPE_COL = 3 # Type VALUE_COL = 4 # Value +# represents the index of columns in search results table +SEARCH_TABLE_ADDRESS_COL = 0 +SEARCH_TABLE_VALUE_COL = 1 +SEARCH_TABLE_PREVIOUS_COL = 2 + # represents the index of columns in disassemble table DISAS_ADDR_COL = 0 DISAS_BYTES_COL = 1 @@ -343,6 +348,8 @@ def __init__(self): self.treeWidget_AddressTable.setColumnWidth(DESC_COL, 150) self.treeWidget_AddressTable.setColumnWidth(ADDR_COL, 150) self.treeWidget_AddressTable.setColumnWidth(TYPE_COL, 150) + self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) + self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) app.setOrganizationName("PINCE") app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") app.setApplicationName("PINCE") @@ -898,7 +905,6 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_NextScan.setEnabled(False) self.comboBox_ScanScope.setEnabled(True) self.progressBar.setValue(0) - self.comboBox_ScanType_init() else: self.scan_mode = type_defs.SCAN_MODE.ONGOING self.pushButton_NewFirstScan.setText("New Scan") @@ -908,7 +914,7 @@ def pushButton_NewFirstScan_clicked(self): self.backend.send_command("option region_scan_level " + str(search_scope)) self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan - self.comboBox_ScanType_init() + self.comboBox_ScanType_init() def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, @@ -950,13 +956,10 @@ def comboBox_ScanScope_init(self): def comboBox_ValueType_init(self): self.comboBox_ValueType.clear() - items = [type_defs.VALUE_INDEX.INDEX_BYTE, type_defs.VALUE_INDEX.INDEX_2BYTES, - type_defs.VALUE_INDEX.INDEX_4BYTES, type_defs.VALUE_INDEX.INDEX_8BYTES, - type_defs.VALUE_INDEX.INDEX_FLOAT, type_defs.VALUE_INDEX.INDEX_DOUBLE, - type_defs.VALUE_INDEX.INDEX_STRING_UTF8, type_defs.VALUE_INDEX.INDEX_AOB] - for type_index in items: - self.comboBox_ValueType.addItem(type_defs.index_to_text_dict[type_index], type_index) - self.comboBox_ValueType.setCurrentIndex(type_defs.VALUE_INDEX.INDEX_4BYTES) + for value_index, value_text in type_defs.scan_index_to_text_dict.items(): + self.comboBox_ValueType.addItem(value_text, value_index) + self.comboBox_ValueType.setCurrentIndex(type_defs.SCAN_INDEX.INDEX_INT32) + self.comboBox_ValueType_current_index_changed() # :doc: # adds things like 0x when searching for etc, basically just makes the line valid for scanmem @@ -974,12 +977,12 @@ def validate_search(self, search_for, search_for2): return symbol_map[type_index] # none of these should be possible to be true at the same time - current_type = self.comboBox_ValueType.currentData(Qt.UserRole) - if current_type == type_defs.VALUE_INDEX.INDEX_FLOAT: + scan_index = self.comboBox_ValueType.currentData(Qt.UserRole) + if scan_index == type_defs.SCAN_INDEX.INDEX_FLOAT32 or scan_index == type_defs.SCAN_INDEX.INDEX_FLOAT64: # this is odd, since when searching for floats from command line it uses `.` and not `,` search_for = search_for.replace(".", ",") search_for2 = search_for2.replace(".", ",") - elif type_defs.VALUE_INDEX.is_string(current_type): + elif scan_index == type_defs.SCAN_INDEX.INDEX_STRING: search_for = "\" " + search_for elif self.checkBox_Hex.isChecked(): if not search_for.startswith("0x"): @@ -1005,52 +1008,47 @@ def pushButton_NextScan_clicked(self): # ProgressBar global threadpool threadpool.start(Worker(self.update_progress_bar)) - # TODO add some validation for the search command self.backend.send_command(search_for) matches = self.backend.matches() ProgressRun = 0 - self.label_MatchCount.setText("Match count: {}".format(self.backend.get_match_count())) + match_count = self.backend.get_match_count() + if match_count > 10000: + self.label_MatchCount.setText("Match count: {} (10000 shown)".format(match_count)) + else: + self.label_MatchCount.setText("Match count: {}".format(match_count)) self.tableWidget_valuesearchtable.setRowCount(0) current_type = self.comboBox_ValueType.currentData(Qt.UserRole) length = self._scan_to_length(current_type) - for n, address, offset, region_type, value, t in matches: + for n, address, offset, region_type, value, result_type in matches: n = int(n) address = "0x" + address - self.tableWidget_valuesearchtable.insertRow( - self.tableWidget_valuesearchtable.rowCount()) - self.tableWidget_valuesearchtable.setItem(n, 0, QTableWidgetItem(address)) - if current_type == type_defs.VALUE_INDEX.INDEX_STRING_UTF8: - value = GDB_Engine.read_memory(address, current_type, length) - self.tableWidget_valuesearchtable.setItem(n, 1, QTableWidgetItem(value)) - self.tableWidget_valuesearchtable.setItem(n, 2, QTableWidgetItem(value)) + current_item = QTableWidgetItem(address) + value_index = type_defs.scanmem_result_to_index_dict[result_type.split(" ")[0]] + current_item.setData(Qt.UserRole, value_index) + self.tableWidget_valuesearchtable.insertRow(self.tableWidget_valuesearchtable.rowCount()) + self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_ADDRESS_COL, current_item) + if current_type == type_defs.SCAN_INDEX.INDEX_STRING: + value = GDB_Engine.read_memory(address, type_defs.VALUE_INDEX.INDEX_STRING_UTF8, length) + self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_VALUE_COL, QTableWidgetItem(value)) + self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_PREVIOUS_COL, QTableWidgetItem(value)) + if n == 10000: + break def _scan_to_length(self, type_index): - if type_defs.VALUE_INDEX.has_length(type_index): - if type_index == type_defs.VALUE_INDEX.INDEX_AOB: - return self.lineEdit_Scan.text().count(" ") + 1 + if type_index == type_defs.SCAN_INDEX.INDEX_AOB: + return self.lineEdit_Scan.text().count(" ") + 1 + if type_index == type_defs.SCAN_INDEX.INDEX_STRING: return len(self.lineEdit_Scan.text()) return 0 @GDB_Engine.execute_with_temporary_interruption def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): - addr = self.tableWidget_valuesearchtable.item(row, 0).text() - current_type = self.comboBox_ValueType.currentData(Qt.UserRole) - length = self._scan_to_length(current_type) - self.add_entry_to_addresstable("", addr, current_type, length) + current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) + length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) + self.add_entry_to_addresstable("", current_item.text(), current_item.data(Qt.UserRole), length) def comboBox_ValueType_current_index_changed(self): - # used for making our types in the combo box into what scanmem uses - PINCE_TYPES_TO_SCANMEM = { - type_defs.VALUE_INDEX.INDEX_BYTE: "int8", - type_defs.VALUE_INDEX.INDEX_2BYTES: "int16", - type_defs.VALUE_INDEX.INDEX_4BYTES: "int32", - type_defs.VALUE_INDEX.INDEX_8BYTES: "int64", - type_defs.VALUE_INDEX.INDEX_FLOAT: "float32", - type_defs.VALUE_INDEX.INDEX_DOUBLE: "float64", - type_defs.VALUE_INDEX.INDEX_STRING_UTF8: "string", - type_defs.VALUE_INDEX.INDEX_AOB: "bytearray" - } current_type = self.comboBox_ValueType.currentData(Qt.UserRole) validator_map = { "int": QRegExpValidator(QRegExp("-?[0-9]*"), parent=self.lineEdit_Scan), # integers @@ -1060,7 +1058,7 @@ def comboBox_ValueType_current_index_changed(self): # array of bytes "string": None } - scanmem_type = PINCE_TYPES_TO_SCANMEM[current_type] + scanmem_type = type_defs.scan_index_to_scanmem_dict[current_type] validator_str = scanmem_type # used to get the correct validator # TODO this can probably be made to look nicer, though it doesn't really matter @@ -1070,7 +1068,7 @@ def comboBox_ValueType_current_index_changed(self): else: self.checkBox_Hex.setChecked(False) self.checkBox_Hex.setEnabled(False) - if "float" in validator_str: + if "float" in validator_str or validator_str == "number": validator_str = "float" self.lineEdit_Scan.setValidator(validator_map[validator_str]) @@ -1079,8 +1077,6 @@ def comboBox_ValueType_current_index_changed(self): # according to scanmem instructions you should always do `reset` after changing type self.backend.send_command("reset") - # shows the process select window - def pushButton_AttachProcess_clicked(self): self.processwindow = ProcessForm(self) self.processwindow.show() @@ -1164,12 +1160,11 @@ def delete_address_table_contents(self): def copy_to_address_table(self): i = -1 - current_type = self.comboBox_ValueType.currentData(Qt.UserRole) - length = self._scan_to_length(current_type) + length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) for row in self.tableWidget_valuesearchtable.selectedItems(): i = i + 1 if i % 3 == 0: - self.add_entry_to_addresstable("", row.text(), current_type, length) + self.add_entry_to_addresstable("", row.text(), row.data(Qt.UserRole), length) def on_inferior_exit(self): if GDB_Engine.currentpid == -1: @@ -1476,7 +1471,7 @@ def pushButton_CreateProcess_clicked(self): # Add Address Manually Dialog class ManualAddressDialogForm(QDialog, ManualAddressDialog): def __init__(self, parent=None, description="No Description", address="0x", - index=type_defs.VALUE_INDEX.INDEX_4BYTES, length=10, zero_terminate=True, hex_repr=False): + index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, hex_repr=False): super().__init__(parent=parent) self.setupUi(self) self.adjustSize() @@ -1599,7 +1594,7 @@ def get_values(self): class EditTypeDialogForm(QDialog, EditTypeDialog): - def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_4BYTES, length=10, zero_terminate=True, + def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, hex_repr=False): super().__init__(parent=parent) self.setupUi(self) @@ -1732,7 +1727,7 @@ class InputDialogForm(QDialog, InputDialog): # that points the current index of the QComboBox, for instance: ["0", "1", 1] will create a QCombobox with the items # "0" and "1" then will set current index to 1 (which is the item "1") # label_alignment is optional - def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=type_defs.VALUE_INDEX.INDEX_4BYTES, + def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=type_defs.VALUE_INDEX.INDEX_INT32, buttons=(QDialogButtonBox.Ok, QDialogButtonBox.Cancel)): super().__init__(parent=parent) self.setupUi(self) @@ -2465,7 +2460,7 @@ def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.B watchpoint_dialog = InputDialogForm(item_list=[("Enter the watchpoint length in size of bytes", "")]) if watchpoint_dialog.exec_(): user_input = watchpoint_dialog.get_values() - user_input_int = SysUtils.parse_string(user_input, type_defs.VALUE_INDEX.INDEX_4BYTES) + user_input_int = SysUtils.parse_string(user_input, type_defs.VALUE_INDEX.INDEX_INT32) if user_input_int is None: QMessageBox.information(self, "Error", user_input + " can't be parsed as an integer") return diff --git a/README.md b/README.md index 6485e107..5d2855eb 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Pre-release screenshots: # Features - **Memory searching:** PINCE uses [libscanmem](https://github.com/scanmem/scanmem) to search the memory efficiently **[Done]** - **Variable Inspection&Modification** **[Done/Basic]** - * **CheatEngine-like value type support:** Byte to 8 Bytes, Float, Double, Strings(including utf-8, utf-16, utf-32 and zero-terminate strings), Array of Bytes **[Done]** + * **CheatEngine-like value type support:** Currently supports all types of CE and scanmem along with extended strings(utf-8, utf-16, utf-32) **[Done]** * **Symbol Recognition:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) **[Done]** * **Automatic Variable Allocation:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) **[Done]** * **Dynamic Address Table:** Supports drag&drop, recursive copy&pasting&inserting and many more **[Done]** diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index bb3a6984..07ce6a8f 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -757,19 +757,6 @@ def inject_with_dlopen_call(library_path): return True -#:tag:ValueType -def value_index_to_gdbcommand(index): - """Converts the given value_index to a parameter that'll be used in "x" command of gdb - - Args: - index (int): Can be a member of type_defs.VALUE_INDEX - - Returns: - str: The str corresponding to the index in type_defs.index_to_gdbcommand_dict - """ - return type_defs.index_to_gdbcommand_dict.get(index, "out of bounds") - - #:tag:MemoryRW def read_memory(address, value_index, length=None, zero_terminate=True, only_bytes=False, mem_handle=None): """Reads value from the given address @@ -788,7 +775,7 @@ def read_memory(address, value_index, length=None, zero_terminate=True, only_byt Returns: str: If the value_index is INDEX_STRING or INDEX_AOB - float: If the value_index is INDEX_FLOAT or INDEX_DOUBLE + float: If the value_index is INDEX_FLOAT32 or INDEX_FLOAT64 int: If the value_index is anything else bytes: If the only_bytes is True None: If an error occurs while reading the given address diff --git a/libpince/GuiUtils.py b/libpince/GuiUtils.py index d7502f1b..7b13fa4e 100644 --- a/libpince/GuiUtils.py +++ b/libpince/GuiUtils.py @@ -91,7 +91,7 @@ def resize_to_contents(QTableWidget): #:tag:GUI -def fill_value_combobox(QCombobox, current_index=type_defs.VALUE_INDEX.INDEX_4BYTES): +def fill_value_combobox(QCombobox, current_index=type_defs.VALUE_INDEX.INDEX_INT32): """Fills the given QCombobox with value_index strings Args: @@ -271,7 +271,7 @@ def text_to_valuetype(string): string="String_UTF8[15],NZT"--▼ value_index=type_defs.VALUE_INDEX.INDEX_STRING_UTF8, length=15, zero_terminate=False, byte_length=-1 string="AoB[42]"-->value_index=type_defs.VALUE_INDEX.INDEX_AOB, length=42, None, 42 - string="Double"-->value_index=type_defs.VALUE_INDEX.INDEX_DOUBLE, length=-1, None, 8 + string="Double"-->value_index=type_defs.VALUE_INDEX.INDEX_FLOAT64, length=-1, None, 8 """ index, length, hex_repr = -1, -1, False zero_terminate = None diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 09f853a7..efe3f18d 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -548,7 +548,7 @@ def parse_string(string, value_index): Returns: str: If the value_index is INDEX_STRING list: If the value_index is INDEX_AOB. A list of ints is returned - float: If the value_index is INDEX_FLOAT or INDEX_DOUBLE + float: If the value_index is INDEX_FLOAT32 or INDEX_FLOAT64 int: If the value_index is anything else None: If the string is not parsable by using the parameter value_index @@ -580,7 +580,7 @@ def parse_string(string, value_index): except: print(string + " can't be parsed as array of bytes") return - elif value_index is type_defs.VALUE_INDEX.INDEX_FLOAT or value_index is type_defs.VALUE_INDEX.INDEX_DOUBLE: + elif value_index is type_defs.VALUE_INDEX.INDEX_FLOAT32 or value_index is type_defs.VALUE_INDEX.INDEX_FLOAT64: try: string = float(string) except: @@ -599,13 +599,13 @@ def parse_string(string, value_index): except: print(string + " can't be parsed as integer or hexadecimal") return - if value_index is type_defs.VALUE_INDEX.INDEX_BYTE: + if value_index is type_defs.VALUE_INDEX.INDEX_INT8: string = string % 0x100 # 256 - elif value_index is type_defs.VALUE_INDEX.INDEX_2BYTES: + elif value_index is type_defs.VALUE_INDEX.INDEX_INT16: string = string % 0x10000 # 65536 - elif value_index is type_defs.VALUE_INDEX.INDEX_4BYTES: + elif value_index is type_defs.VALUE_INDEX.INDEX_INT32: string = string % 0x100000000 # 4294967296 - elif value_index is type_defs.VALUE_INDEX.INDEX_8BYTES: + elif value_index is type_defs.VALUE_INDEX.INDEX_INT64: string = string % 0x10000000000000000 # 18446744073709551616 return string diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 29c2f507..398d26f9 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -143,22 +143,20 @@ class FLOAT: XMM = ["xmm" + str(i) for i in range(8)] -# represents the indexes of value types -# Also used in PINCE's value comboboxes class VALUE_INDEX: - INDEX_BYTE = 0 - INDEX_2BYTES = 1 - INDEX_4BYTES = 2 - INDEX_8BYTES = 3 - INDEX_FLOAT = 4 - INDEX_DOUBLE = 5 + INDEX_INT8 = 0 + INDEX_INT16 = 1 + INDEX_INT32 = 2 + INDEX_INT64 = 3 + INDEX_FLOAT32 = 4 + INDEX_FLOAT64 = 5 # Beginning of the string indexes, new string indexes should be added between 6 and 9 INDEX_STRING_ASCII = 6 INDEX_STRING_UTF8 = 7 INDEX_STRING_UTF16 = 8 INDEX_STRING_UTF32 = 9 - # Ending of the string indexes, 69... not on purpose tho + # Ending of the string indexes INDEX_AOB = 10 # Array of Bytes @@ -172,6 +170,20 @@ def has_length(value_index): value_index == VALUE_INDEX.INDEX_AOB +class SCAN_INDEX: + INDEX_INT_ANY = 0 + INDEX_INT8 = 1 + INDEX_INT16 = 2 + INDEX_INT32 = 3 + INDEX_INT64 = 4 + INDEX_FLOAT_ANY = 5 + INDEX_FLOAT32 = 6 + INDEX_FLOAT64 = 7 + INDEX_ANY = 8 + INDEX_STRING = 9 + INDEX_AOB = 10 # Array of Bytes + + on_hit_to_text_dict = { BREAKPOINT_ON_HIT.BREAK: "Break", BREAKPOINT_ON_HIT.FIND_CODE: "Find Code", @@ -179,14 +191,14 @@ def has_length(value_index): BREAKPOINT_ON_HIT.TRACE: "Trace" } -# Represents the texts at indexes in combobox +# Represents the texts at indexes in the address table index_to_text_dict = collections.OrderedDict([ - (VALUE_INDEX.INDEX_BYTE, "Byte"), - (VALUE_INDEX.INDEX_2BYTES, "2 Bytes"), - (VALUE_INDEX.INDEX_4BYTES, "4 Bytes"), - (VALUE_INDEX.INDEX_8BYTES, "8 Bytes"), - (VALUE_INDEX.INDEX_FLOAT, "Float"), - (VALUE_INDEX.INDEX_DOUBLE, "Double"), + (VALUE_INDEX.INDEX_INT8, "Int8"), + (VALUE_INDEX.INDEX_INT16, "Int16"), + (VALUE_INDEX.INDEX_INT32, "Int32"), + (VALUE_INDEX.INDEX_INT64, "Int64"), + (VALUE_INDEX.INDEX_FLOAT32, "Float32"), + (VALUE_INDEX.INDEX_FLOAT64, "Float64"), (VALUE_INDEX.INDEX_STRING_ASCII, "String_ASCII"), (VALUE_INDEX.INDEX_STRING_UTF8, "String_UTF8"), (VALUE_INDEX.INDEX_STRING_UTF16, "String_UTF16"), @@ -198,6 +210,47 @@ def has_length(value_index): for key in index_to_text_dict: text_to_index_dict[index_to_text_dict[key]] = key +scanmem_result_to_index_dict = collections.OrderedDict([ + ("I8", VALUE_INDEX.INDEX_INT8), + ("I16", VALUE_INDEX.INDEX_INT16), + ("I32", VALUE_INDEX.INDEX_INT32), + ("I64", VALUE_INDEX.INDEX_INT64), + ("F32", VALUE_INDEX.INDEX_FLOAT32), + ("F64", VALUE_INDEX.INDEX_FLOAT64), + ("string", VALUE_INDEX.INDEX_STRING_UTF8), + ("bytearray", VALUE_INDEX.INDEX_AOB), +]) + +# Represents the texts at indexes in scan combobox +scan_index_to_text_dict = collections.OrderedDict([ + (SCAN_INDEX.INDEX_INT_ANY, "Int(any)"), + (SCAN_INDEX.INDEX_INT8, "Int8"), + (SCAN_INDEX.INDEX_INT16, "Int16"), + (SCAN_INDEX.INDEX_INT32, "Int32"), + (SCAN_INDEX.INDEX_INT64, "Int64"), + (SCAN_INDEX.INDEX_FLOAT_ANY, "Float(any)"), + (SCAN_INDEX.INDEX_FLOAT32, "Float32"), + (SCAN_INDEX.INDEX_FLOAT64, "Float64"), + (SCAN_INDEX.INDEX_ANY, "Any(int, float)"), + (SCAN_INDEX.INDEX_STRING, "String"), + (VALUE_INDEX.INDEX_AOB, "Array of Bytes") +]) + +# Used in scan_data_type option of scanmem +scan_index_to_scanmem_dict = collections.OrderedDict([ + (SCAN_INDEX.INDEX_INT_ANY, "int"), + (SCAN_INDEX.INDEX_INT8, "int8"), + (SCAN_INDEX.INDEX_INT16, "int16"), + (SCAN_INDEX.INDEX_INT32, "int32"), + (SCAN_INDEX.INDEX_INT64, "int64"), + (SCAN_INDEX.INDEX_FLOAT_ANY, "float"), + (SCAN_INDEX.INDEX_FLOAT32, "float32"), + (SCAN_INDEX.INDEX_FLOAT64, "float64"), + (SCAN_INDEX.INDEX_ANY, "number"), + (SCAN_INDEX.INDEX_STRING, "string"), + (VALUE_INDEX.INDEX_AOB, "bytearray") +]) + class SCAN_TYPE: EXACT = 0 @@ -259,31 +312,15 @@ class SCAN_SCOPE: VALUE_INDEX.INDEX_STRING_UTF32: 8, } -# A dictionary used to convert value_combobox index to gdb/mi x command -# Check GDB_Engine for an exemplary usage -index_to_gdbcommand_dict = { - VALUE_INDEX.INDEX_BYTE: "db", - VALUE_INDEX.INDEX_2BYTES: "dh", - VALUE_INDEX.INDEX_4BYTES: "dw", - VALUE_INDEX.INDEX_8BYTES: "dg", - VALUE_INDEX.INDEX_FLOAT: "fw", - VALUE_INDEX.INDEX_DOUBLE: "fg", - VALUE_INDEX.INDEX_STRING_ASCII: "xb", - VALUE_INDEX.INDEX_STRING_UTF8: "xb", - VALUE_INDEX.INDEX_STRING_UTF16: "xb", - VALUE_INDEX.INDEX_STRING_UTF32: "xb", - VALUE_INDEX.INDEX_AOB: "xb" -} - # first value is the length and the second one is the type # Check ScriptUtils for an exemplary usage index_to_valuetype_dict = { - VALUE_INDEX.INDEX_BYTE: [1, "b"], - VALUE_INDEX.INDEX_2BYTES: [2, "h"], - VALUE_INDEX.INDEX_4BYTES: [4, "i"], - VALUE_INDEX.INDEX_8BYTES: [8, "q"], - VALUE_INDEX.INDEX_FLOAT: [4, "f"], - VALUE_INDEX.INDEX_DOUBLE: [8, "d"], + VALUE_INDEX.INDEX_INT8: [1, "b"], + VALUE_INDEX.INDEX_INT16: [2, "h"], + VALUE_INDEX.INDEX_INT32: [4, "i"], + VALUE_INDEX.INDEX_INT64: [8, "q"], + VALUE_INDEX.INDEX_FLOAT32: [4, "f"], + VALUE_INDEX.INDEX_FLOAT64: [8, "d"], VALUE_INDEX.INDEX_STRING_ASCII: [None, None], VALUE_INDEX.INDEX_STRING_UTF8: [None, None], VALUE_INDEX.INDEX_STRING_UTF16: [None, None], @@ -293,12 +330,12 @@ class SCAN_SCOPE: # Check ScriptUtils for an exemplary usage index_to_struct_pack_dict = { - VALUE_INDEX.INDEX_BYTE: "B", - VALUE_INDEX.INDEX_2BYTES: "H", - VALUE_INDEX.INDEX_4BYTES: "I", - VALUE_INDEX.INDEX_8BYTES: "Q", - VALUE_INDEX.INDEX_FLOAT: "f", - VALUE_INDEX.INDEX_DOUBLE: "d" + VALUE_INDEX.INDEX_INT8: "B", + VALUE_INDEX.INDEX_INT16: "H", + VALUE_INDEX.INDEX_INT32: "I", + VALUE_INDEX.INDEX_INT64: "Q", + VALUE_INDEX.INDEX_FLOAT32: "f", + VALUE_INDEX.INDEX_FLOAT64: "d" } # Format: {tag:tag_description} From a258cf0c28c4ce8f1cb569f17e611d8b58da988b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 8 Jul 2022 23:01:16 +0300 Subject: [PATCH 022/487] Hotfix for scanmem type support --- libpince/type_defs.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 398d26f9..0c5bbe64 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -212,9 +212,17 @@ class SCAN_INDEX: scanmem_result_to_index_dict = collections.OrderedDict([ ("I8", VALUE_INDEX.INDEX_INT8), + ("I8u", VALUE_INDEX.INDEX_INT8), + ("I8s", VALUE_INDEX.INDEX_INT8), ("I16", VALUE_INDEX.INDEX_INT16), + ("I16u", VALUE_INDEX.INDEX_INT16), + ("I16s", VALUE_INDEX.INDEX_INT16), ("I32", VALUE_INDEX.INDEX_INT32), + ("I32u", VALUE_INDEX.INDEX_INT32), + ("I32s", VALUE_INDEX.INDEX_INT32), ("I64", VALUE_INDEX.INDEX_INT64), + ("I64u", VALUE_INDEX.INDEX_INT64), + ("I64s", VALUE_INDEX.INDEX_INT64), ("F32", VALUE_INDEX.INDEX_FLOAT32), ("F64", VALUE_INDEX.INDEX_FLOAT64), ("string", VALUE_INDEX.INDEX_STRING_UTF8), From a887ac686777dfe00edcec8d0f7a82b192eeb442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 9 Jul 2022 16:51:37 +0300 Subject: [PATCH 023/487] Fix handle_signals_data --- PINCE.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 273d421e..85d489f1 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1910,7 +1910,8 @@ def accept(self): GDB_Engine.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) - self.settings.setValue("Debug/ignored_signals", ",".join(self.handle_signals_data)) + if self.handle_signals_data is not None: + self.settings.setValue("Debug/ignored_signals", ",".join(self.handle_signals_data)) super(SettingsDialogForm, self).accept() def config_gui(self): From f24e3315735b93801db548aed2bce1d087913efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 9 Jul 2022 17:08:32 +0300 Subject: [PATCH 024/487] Fix spacing issue in SettingsDialog --- GUI/SettingsDialog.py | 72 +++++++++++++++++-------------------------- GUI/SettingsDialog.ui | 29 ++++------------- 2 files changed, 34 insertions(+), 67 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index a0941713..e5caed2a 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -62,6 +62,7 @@ def setupUi(self, Dialog): self.QWidget_UpdateInterval = QtWidgets.QWidget(self.page) self.QWidget_UpdateInterval.setObjectName("QWidget_UpdateInterval") self.horizontalLayout_UpdateInterval = QtWidgets.QHBoxLayout(self.QWidget_UpdateInterval) + self.horizontalLayout_UpdateInterval.setContentsMargins(-1, 0, -1, -1) self.horizontalLayout_UpdateInterval.setObjectName("horizontalLayout_UpdateInterval") self.label = QtWidgets.QLabel(self.QWidget_UpdateInterval) self.label.setMinimumSize(QtCore.QSize(102, 0)) @@ -77,6 +78,7 @@ def setupUi(self, Dialog): self.LockInterval = QtWidgets.QWidget(self.page) self.LockInterval.setObjectName("LockInterval") self.horizontalLayout_14 = QtWidgets.QHBoxLayout(self.LockInterval) + self.horizontalLayout_14.setContentsMargins(-1, 0, -1, -1) self.horizontalLayout_14.setObjectName("horizontalLayout_14") self.label_12 = QtWidgets.QLabel(self.LockInterval) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) @@ -105,18 +107,10 @@ def setupUi(self, Dialog): spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_7.addItem(spacerItem) self.verticalLayout_5.addLayout(self.horizontalLayout_7) - self.horizontalLayout_13 = QtWidgets.QHBoxLayout() - self.horizontalLayout_13.setObjectName("horizontalLayout_13") - spacerItem1 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) - self.horizontalLayout_13.addItem(spacerItem1) - self.verticalLayout_5.addLayout(self.horizontalLayout_13) self.checkBox_MessageBoxOnException = QtWidgets.QCheckBox(self.page) self.checkBox_MessageBoxOnException.setChecked(True) self.checkBox_MessageBoxOnException.setObjectName("checkBox_MessageBoxOnException") self.verticalLayout_5.addWidget(self.checkBox_MessageBoxOnException) - self.verticalLayout_12 = QtWidgets.QVBoxLayout() - self.verticalLayout_12.setObjectName("verticalLayout_12") - self.verticalLayout_5.addLayout(self.verticalLayout_12) self.checkBox_MessageBoxOnToggleAttach = QtWidgets.QCheckBox(self.page) self.checkBox_MessageBoxOnToggleAttach.setChecked(True) self.checkBox_MessageBoxOnToggleAttach.setObjectName("checkBox_MessageBoxOnToggleAttach") @@ -138,8 +132,8 @@ def setupUi(self, Dialog): self.checkBox_OutputModeCommandInfo.setChecked(True) self.checkBox_OutputModeCommandInfo.setObjectName("checkBox_OutputModeCommandInfo") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeCommandInfo) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_3.addItem(spacerItem2) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem1) self.verticalLayout_5.addLayout(self.horizontalLayout_3) self.horizontalLayout_12 = QtWidgets.QHBoxLayout() self.horizontalLayout_12.setContentsMargins(-1, 0, -1, -1) @@ -162,11 +156,11 @@ def setupUi(self, Dialog): self.comboBox_Logo = QtWidgets.QComboBox(self.page) self.comboBox_Logo.setObjectName("comboBox_Logo") self.horizontalLayout_15.addWidget(self.comboBox_Logo) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_15.addItem(spacerItem3) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_15.addItem(spacerItem2) self.verticalLayout_5.addLayout(self.horizontalLayout_15) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout_5.addItem(spacerItem4) + spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_5.addItem(spacerItem3) self.gridLayout_2.addLayout(self.verticalLayout_5, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page) self.page_2 = QtWidgets.QWidget() @@ -194,14 +188,14 @@ def setupUi(self, Dialog): self.verticalLayout_6.addLayout(self.verticalLayout_Hotkey) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_4.addItem(spacerItem5) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_4.addItem(spacerItem4) self.pushButton_ClearHotkey = QtWidgets.QPushButton(self.page_2) self.pushButton_ClearHotkey.setObjectName("pushButton_ClearHotkey") self.horizontalLayout_4.addWidget(self.pushButton_ClearHotkey) self.verticalLayout_6.addLayout(self.horizontalLayout_4) - spacerItem6 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout_6.addItem(spacerItem6) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_6.addItem(spacerItem5) self.horizontalLayout_5.addLayout(self.verticalLayout_6) self.gridLayout_3.addLayout(self.horizontalLayout_5, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_2) @@ -220,8 +214,8 @@ def setupUi(self, Dialog): self.verticalLayout_8.addWidget(self.label_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") - spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_6.addItem(spacerItem7) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_6.addItem(spacerItem6) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setObjectName("verticalLayout_7") self.radioButton_SimpleDLopenCall = QtWidgets.QRadioButton(self.page_3) @@ -235,11 +229,11 @@ def setupUi(self, Dialog): self.horizontalLayout_6.addLayout(self.verticalLayout_7) self.verticalLayout_8.addLayout(self.horizontalLayout_6) self.horizontalLayout_8.addLayout(self.verticalLayout_8) - spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_8.addItem(spacerItem8) + spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_8.addItem(spacerItem7) self.verticalLayout_9.addLayout(self.horizontalLayout_8) - spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout_9.addItem(spacerItem9) + spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_9.addItem(spacerItem8) self.gridLayout_4.addLayout(self.verticalLayout_9, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_3) self.page_4 = QtWidgets.QWidget() @@ -263,11 +257,11 @@ def setupUi(self, Dialog): self.lineEdit_InstructionsPerScroll.setObjectName("lineEdit_InstructionsPerScroll") self.horizontalLayout_9.addWidget(self.lineEdit_InstructionsPerScroll) self.horizontalLayout_10.addLayout(self.horizontalLayout_9) - spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_10.addItem(spacerItem10) + spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_10.addItem(spacerItem9) self.verticalLayout_10.addLayout(self.horizontalLayout_10) - spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout_10.addItem(spacerItem11) + spacerItem10 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_10.addItem(spacerItem10) self.gridLayout_5.addLayout(self.verticalLayout_10, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_4) self.page_5 = QtWidgets.QWidget() @@ -300,11 +294,11 @@ def setupUi(self, Dialog): self.pushButton_HandleSignals = QtWidgets.QPushButton(self.page_5) self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) - spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_16.addItem(spacerItem12) + spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_16.addItem(spacerItem11) self.verticalLayout_11.addLayout(self.horizontalLayout_16) - spacerItem13 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout_11.addItem(spacerItem13) + spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_11.addItem(spacerItem12) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) self.horizontalLayout_2.addWidget(self.stackedWidget) @@ -314,8 +308,8 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem14) + spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem13) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) @@ -377,13 +371,3 @@ def retranslateUi(self, Dialog): self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) self.pushButton_HandleSignals.setText(_translate("Dialog", "Handle Signals")) self.pushButton_ResetSettings.setText(_translate("Dialog", "Reset Settings")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - Dialog = QtWidgets.QDialog() - ui = Ui_Dialog() - ui.setupUi(Dialog) - Dialog.show() - sys.exit(app.exec_()) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index ebea30ee..775b5e69 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -95,6 +95,9 @@ + + 0 + @@ -128,6 +131,9 @@ + + 0 + @@ -199,26 +205,6 @@ - - - - - - Qt::Vertical - - - QSizePolicy::Maximum - - - - 10 - 20 - - - - - - @@ -229,9 +215,6 @@ - - - From f13351d6c549d74a14778fd4ffcb8c28ef780d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 10 Jul 2022 22:43:24 +0300 Subject: [PATCH 025/487] read_memory now returns unsigned by default --- libpince/type_defs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 0c5bbe64..da0dea26 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -323,10 +323,10 @@ class SCAN_SCOPE: # first value is the length and the second one is the type # Check ScriptUtils for an exemplary usage index_to_valuetype_dict = { - VALUE_INDEX.INDEX_INT8: [1, "b"], - VALUE_INDEX.INDEX_INT16: [2, "h"], - VALUE_INDEX.INDEX_INT32: [4, "i"], - VALUE_INDEX.INDEX_INT64: [8, "q"], + VALUE_INDEX.INDEX_INT8: [1, "B"], + VALUE_INDEX.INDEX_INT16: [2, "H"], + VALUE_INDEX.INDEX_INT32: [4, "I"], + VALUE_INDEX.INDEX_INT64: [8, "Q"], VALUE_INDEX.INDEX_FLOAT32: [4, "f"], VALUE_INDEX.INDEX_FLOAT64: [8, "d"], VALUE_INDEX.INDEX_STRING_ASCII: [None, None], From 4bf7908a1496f6fef42aad90f048863721b66b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 11 Jul 2022 16:47:14 +0300 Subject: [PATCH 026/487] Implement signed/unsigned conversion --- PINCE.py | 89 +++++++++++++++++++++++------------------- README.md | 2 +- libpince/GDB_Engine.py | 17 ++++---- libpince/GuiUtils.py | 25 +++++++----- libpince/type_defs.py | 13 ++++++ 5 files changed, 86 insertions(+), 60 deletions(-) diff --git a/PINCE.py b/PINCE.py index 85d489f1..6de7a6cb 100755 --- a/PINCE.py +++ b/PINCE.py @@ -602,6 +602,9 @@ def treeWidget_AddressTable_context_menu_event(self, event): edit_type = edit_menu.addAction("Type[Alt+Enter]") edit_value = edit_menu.addAction("Value[Enter]") show_hex = menu.addAction("Show as hexadecimal") + show_dec = menu.addAction("Show as decimal") + show_unsigned = menu.addAction("Show as unsigned") + show_signed = menu.addAction("Show as signed") toggle_record = menu.addAction("Toggle selected records[Space]") menu.addSeparator() browse_region = menu.addAction("Browse this memory region[Ctrl+B]") @@ -620,16 +623,21 @@ def treeWidget_AddressTable_context_menu_event(self, event): what_reads = menu.addAction("Find out what reads this address") what_accesses = menu.addAction("Find out what accesses this address") if current_row is None: - deletion_list = [edit_menu.menuAction(), show_hex, toggle_record, browse_region, disassemble, what_writes, - what_reads, what_accesses] + deletion_list = [edit_menu.menuAction(), show_hex, show_dec, show_unsigned, show_signed, toggle_record, + browse_region, disassemble, what_writes, what_reads, what_accesses] GuiUtils.delete_menu_entries(menu, deletion_list) else: current_text = current_row.text(TYPE_COL) - index, length, zero_terminate, byte_len, hex_repr = GuiUtils.text_to_valuetype(current_text) - if type_defs.VALUE_INDEX.has_length(index): - GuiUtils.delete_menu_entries(menu, [show_hex]) - elif hex_repr: - show_hex.setText("Show as decimal") + index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(current_text) + if type_defs.VALUE_INDEX.is_integer(index): + if value_repr is type_defs.VALUE_REPR.HEX: + GuiUtils.delete_menu_entries(menu, [show_unsigned, show_signed, show_hex]) + elif value_repr is type_defs.VALUE_REPR.UNSIGNED: + GuiUtils.delete_menu_entries(menu, [show_unsigned, show_dec]) + elif value_repr is type_defs.VALUE_REPR.SIGNED: + GuiUtils.delete_menu_entries(menu, [show_signed, show_dec]) + else: + GuiUtils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed]) font_size = self.treeWidget_AddressTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec_(event.globalPos()) @@ -638,7 +646,10 @@ def treeWidget_AddressTable_context_menu_event(self, event): edit_address: self.treeWidget_AddressTable_edit_address, edit_type: self.treeWidget_AddressTable_edit_type, edit_value: self.treeWidget_AddressTable_edit_value, - show_hex: self.treeWidget_AddressTable_show_hex, + show_hex: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.HEX), + show_dec: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.UNSIGNED), + show_unsigned: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.UNSIGNED), + show_signed: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.SIGNED), toggle_record: self.toggle_selected_records, browse_region: self.browse_region_for_selected_row, disassemble: self.disassemble_selected_row, @@ -666,7 +677,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): return address = selected_row.text(ADDR_COL) value_type_text = selected_row.text(TYPE_COL) - index, length, zero_terminate, byte_len, hex_repr = GuiUtils.text_to_valuetype(value_type_text) + index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type_text) if byte_len == -1: value_text = selected_row.text(VALUE_COL) encoding, option = type_defs.string_index_to_encoding_dict[index] @@ -823,7 +834,7 @@ def update_address_table(self): table_contents = [] address_expr_list = [] value_type_list = [] - hex_repr_list = [] + value_repr_list = [] rows = [] while True: row = it.value() @@ -838,16 +849,19 @@ def update_address_table(self): except type_defs.InferiorRunningException: address_list = address_expr_list for address, value_type in zip(address_list, value_type_list): - index, length, zero_terminate, byte_len, hex_repr = GuiUtils.text_to_valuetype(value_type) - table_contents.append((address, index, length, zero_terminate)) - hex_repr_list.append(hex_repr) + index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type) + signed = False + if value_repr == type_defs.VALUE_REPR.SIGNED: + signed = True + table_contents.append((address, index, length, zero_terminate, signed)) + value_repr_list.append(value_repr) new_table_contents = GDB_Engine.read_memory_multiple(table_contents) - for row, address, address_expr, value, hex_repr in zip(rows, address_list, address_expr_list, - new_table_contents, hex_repr_list): + for row, address, address_expr, value, value_repr in zip(rows, address_list, address_expr_list, + new_table_contents, value_repr_list): row.setText(ADDR_COL, address or address_expr) if value is None: value = "" - elif hex_repr: + elif value_repr == type_defs.VALUE_REPR.HEX: value = hex(value) else: value = str(value) @@ -860,7 +874,7 @@ def resize_address_table(self): def pushButton_AddAddressManually_clicked(self): manual_address_dialog = ManualAddressDialogForm() if manual_address_dialog.exec_(): - desc, address_expr, address_type, length, zero_terminate, hex_repr = manual_address_dialog.get_values() + desc, address_expr, address_type, length, zero_terminate = manual_address_dialog.get_values() self.add_entry_to_addresstable(desc, address_expr, address_type, length, zero_terminate) def pushButton_MemoryView_clicked(self): @@ -1283,13 +1297,11 @@ def treeWidget_AddressTable_item_clicked(self, row, column): if (len(FreezeVars) == 0): FreezeStop = 1 - def treeWidget_AddressTable_show_hex(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) - value_text = row.text(TYPE_COL) - index, length, zero_terminate, byte_len, hex_repr = GuiUtils.text_to_valuetype(value_text) - hex_repr = not hex_repr + def treeWidget_AddressTable_change_repr(self, new_repr): + value_text = GuiUtils.get_current_item(self.treeWidget_AddressTable).text(TYPE_COL) + index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_text) for row in self.treeWidget_AddressTable.selectedItems(): - row.setText(TYPE_COL, GuiUtils.valuetype_to_text(index, length, zero_terminate, hex_repr)) + row.setText(TYPE_COL, GuiUtils.valuetype_to_text(index, length, zero_terminate, new_repr)) self.update_address_table() def treeWidget_AddressTable_edit_value(self): @@ -1338,13 +1350,13 @@ def treeWidget_AddressTable_edit_address(self): if not row: return desc, address_expr, value_type = self.read_address_table_entries(row=row) - index, length, zero_terminate, byte_len, hex_repr = GuiUtils.text_to_valuetype(value_type) + index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type) manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, index=index, - length=length, zero_terminate=zero_terminate, hex_repr=hex_repr) + length=length, zero_terminate=zero_terminate) manual_address_dialog.setWindowTitle("Edit Address") if manual_address_dialog.exec_(): - desc, address_expr, address_type, length, zero_terminate, hex_repr = manual_address_dialog.get_values() - address_type_text = GuiUtils.valuetype_to_text(address_type, length, zero_terminate, hex_repr) + desc, address_expr, address_type, length, zero_terminate = manual_address_dialog.get_values() + address_type_text = GuiUtils.valuetype_to_text(address_type, length, zero_terminate, value_repr) self.change_address_table_entries(row, desc, address_expr, address_type_text) def treeWidget_AddressTable_edit_type(self): @@ -1352,11 +1364,11 @@ def treeWidget_AddressTable_edit_type(self): if not row: return value_type = row.text(TYPE_COL) - value_index, length, zero_terminate, byte_len, hex_repr = GuiUtils.text_to_valuetype(value_type) - dialog = EditTypeDialogForm(index=value_index, length=length, zero_terminate=zero_terminate, hex_repr=hex_repr) + value_index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type) + dialog = EditTypeDialogForm(index=value_index, length=length, zero_terminate=zero_terminate) if dialog.exec_(): - params = dialog.get_values() - type_text = GuiUtils.valuetype_to_text(*params) + value_index, length, zero_terminate = dialog.get_values() + type_text = GuiUtils.valuetype_to_text(value_index, length, zero_terminate, value_repr) for row in self.treeWidget_AddressTable.selectedItems(): row.setText(TYPE_COL, type_text) self.update_address_table() @@ -1368,7 +1380,7 @@ def change_address_table_entries(self, row, description="", address_expr="", add except type_defs.InferiorRunningException: address = address_expr value = '' - index, length, zero_terminate, byte_len, hex_repr = GuiUtils.text_to_valuetype(address_type) + index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(address_type) if address: value = GDB_Engine.read_memory(address, index, length, zero_terminate) @@ -1471,14 +1483,13 @@ def pushButton_CreateProcess_clicked(self): # Add Address Manually Dialog class ManualAddressDialogForm(QDialog, ManualAddressDialog): def __init__(self, parent=None, description="No Description", address="0x", - index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, hex_repr=False): + index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True): super().__init__(parent=parent) self.setupUi(self) self.adjustSize() self.setMinimumWidth(300) self.setFixedHeight(self.height()) self.lineEdit_length.setValidator(QHexValidator(999, self)) - self.hex_repr = hex_repr GuiUtils.fill_value_combobox(self.comboBox_ValueType, index) self.lineEdit_description.setText(description) self.lineEdit_address.setText(address) @@ -1590,17 +1601,15 @@ def get_values(self): if self.checkBox_zeroterminate.isChecked(): zero_terminate = True address_type = self.comboBox_ValueType.currentIndex() - return description, address, address_type, length, zero_terminate, self.hex_repr + return description, address, address_type, length, zero_terminate class EditTypeDialogForm(QDialog, EditTypeDialog): - def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, - hex_repr=False): + def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True): super().__init__(parent=parent) self.setupUi(self) self.setMaximumSize(100, 100) self.lineEdit_Length.setValidator(QHexValidator(999, self)) - self.hex_repr = hex_repr GuiUtils.fill_value_combobox(self.comboBox_ValueType, index) if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.label_Length.show() @@ -1667,7 +1676,7 @@ def get_values(self): if self.checkBox_ZeroTerminate.isChecked(): zero_terminate = True address_type = self.comboBox_ValueType.currentIndex() - return address_type, length, zero_terminate, self.hex_repr + return address_type, length, zero_terminate class LoadingDialogForm(QDialog, LoadingDialog): @@ -2552,7 +2561,7 @@ def exec_hex_view_add_address_dialog(self): manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), index=type_defs.VALUE_INDEX.INDEX_AOB) if manual_address_dialog.exec_(): - desc, address_expr, address_type, length, zero_terminate, hex_repr = manual_address_dialog.get_values() + desc, address_expr, address_type, length, zero_terminate = manual_address_dialog.get_values() self.parent().add_entry_to_addresstable(desc, address_expr, address_type, length, zero_terminate) def verticalScrollBar_HexView_mouse_release_event(self, event): diff --git a/README.md b/README.md index 5d2855eb..1f5e1af3 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - Refactorize memory write/read functions - - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. Only update the visible rows to prevent this(check ```disassemble_check_viewport``` for an example) - - Implement same system for the TrackBreakpointWidgetForm if necessary. Do performance tests -- - Consider using a class instead of primitive return types to store the raw bytes. This also gets rid of the unnecessary parameter only_bytes. This class should also include a method to display None type as red '??' text for Qt +- - Consider using a class instead of primitive return types to store the raw bytes. This class should also include a method to display None type as red '??' text for Qt - - text_to_valuetype is a bad design pattern. Store the information inside the items of tableWidget_AddressTable instead - - read_memory_multiple follows a bad design pattern, use named tuples or something like that - - Provide an option to cut BOM bytes when writing to memory with the types UTF-16 and UTF-32 diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 07ce6a8f..889423d1 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -758,7 +758,7 @@ def inject_with_dlopen_call(library_path): #:tag:MemoryRW -def read_memory(address, value_index, length=None, zero_terminate=True, only_bytes=False, mem_handle=None): +def read_memory(address, value_index, length=None, zero_terminate=True, signed=False, mem_handle=None): """Reads value from the given address Args: @@ -768,7 +768,7 @@ def read_memory(address, value_index, length=None, zero_terminate=True, only_byt INDEX_STRING or INDEX_AOB. Ignored otherwise zero_terminate (bool): If True, data will be split when a null character has been read. Only used when value_index is INDEX_STRING. Ignored otherwise - only_bytes (bool): Returns only bytes instead of converting it to the according type of value_index + signed (bool): Casts the data as signed if True, unsigned if False. Only usable with integer types mem_handle (BinaryIO): A file handle that points to the memory file of the current process This parameter is used for optimization, intended for internal usage. Check read_memory_multiple for an example Don't forget to close the handle after you're done if you use this parameter manually @@ -777,7 +777,6 @@ def read_memory(address, value_index, length=None, zero_terminate=True, only_byt str: If the value_index is INDEX_STRING or INDEX_AOB float: If the value_index is INDEX_FLOAT32 or INDEX_FLOAT64 int: If the value_index is anything else - bytes: If the only_bytes is True None: If an error occurs while reading the given address """ try: @@ -826,8 +825,6 @@ def read_memory(address, value_index, length=None, zero_terminate=True, only_byt # Maybe creating a function that toggles logging on and off? Other functions could use it too # print("Can't access the memory at address " + hex(address) + " or offset " + hex(address + expected_length)) return - if only_bytes: - return data_read if type_defs.VALUE_INDEX.is_string(value_index): encoding, option = type_defs.string_index_to_encoding_dict[value_index] returned_string = data_read.decode(encoding, option) @@ -840,6 +837,8 @@ def read_memory(address, value_index, length=None, zero_terminate=True, only_byt elif value_index is type_defs.VALUE_INDEX.INDEX_AOB: return " ".join(format(n, '02x') for n in data_read) else: + if type_defs.VALUE_INDEX.is_integer(value_index) and signed: + data_type = data_type.lower() return struct.unpack_from(data_type, data_read)[0] @@ -856,7 +855,7 @@ def read_memory_multiple(nested_list): parameters are the same with the function read_memory. Examples: - All parameters are passed-->[[address1, value_index1, length1, zero_terminate1, only_bytes], ...] + All parameters are passed-->[[address1, value_index1, length1, zero_terminate1, signed], ...] Parameters are partially passed--▼ [[address1, value_index1],[address2, value_index2, length2],[address3, value_index3, length3], ...] @@ -881,10 +880,10 @@ def read_memory_multiple(nested_list): except IndexError: zero_terminate = True try: - only_bytes = item[4] + signed = item[4] except IndexError: - only_bytes = False - data_read = read_memory(address, index, length, zero_terminate, only_bytes, mem_handle) + signed = False + data_read = read_memory(address, index, length, zero_terminate, signed, mem_handle) data_read_list.append(data_read) mem_handle.close() return data_read_list diff --git a/libpince/GuiUtils.py b/libpince/GuiUtils.py index 7b13fa4e..b716685d 100644 --- a/libpince/GuiUtils.py +++ b/libpince/GuiUtils.py @@ -222,7 +222,7 @@ def get_layout_widgets(layout): #:tag:ValueType -def valuetype_to_text(value_index=int, length=0, zero_terminate=True, hex_repr=False): +def valuetype_to_text(value_index=int, length=0, zero_terminate=True, value_repr=type_defs.VALUE_REPR.UNSIGNED): """Returns a str according to given parameters Args: @@ -230,7 +230,7 @@ def valuetype_to_text(value_index=int, length=0, zero_terminate=True, hex_repr=F length (int): Length of the data. Only used when the value_index is INDEX_STRING or INDEX_AOB. Ignored otherwise zero_terminate (bool): If False, ",NZT" will be appended to str. Only used when value_index is INDEX_STRING. Ignored otherwise. "NZT" stands for "Not Zero Terminate" - hex_repr (bool): If text should be represented as a hexadecimal value + value_repr (int): Determines how the data is represented. Can be a member of type_defs.VALUE_REPR Returns: str: A str generated by given parameters @@ -248,8 +248,11 @@ def valuetype_to_text(value_index=int, length=0, zero_terminate=True, hex_repr=F returned_string += ",NZT" elif value_index is type_defs.VALUE_INDEX.INDEX_AOB: returned_string += "[" + str(length) + "]" - if hex_repr and not type_defs.VALUE_INDEX.has_length(value_index): - returned_string += "(h)" + if type_defs.VALUE_INDEX.is_integer(value_index): + if value_repr is type_defs.VALUE_REPR.SIGNED: + returned_string += "(s)" + elif value_repr is type_defs.VALUE_REPR.HEX: + returned_string += "(h)" return returned_string @@ -262,7 +265,7 @@ def text_to_valuetype(string): Returns: tuple: A tuple consisting of parameters of the function valuetype_to_text--▼ - value_index, length, zero_terminate, byte_length, hex_repr + value_index, length, zero_terminate, byte_length, value_repr If value_index doesn't contain length, length will be returned as -1 If value_index is INDEX_STRING, byte_length will be returned as -1 @@ -271,9 +274,9 @@ def text_to_valuetype(string): string="String_UTF8[15],NZT"--▼ value_index=type_defs.VALUE_INDEX.INDEX_STRING_UTF8, length=15, zero_terminate=False, byte_length=-1 string="AoB[42]"-->value_index=type_defs.VALUE_INDEX.INDEX_AOB, length=42, None, 42 - string="Double"-->value_index=type_defs.VALUE_INDEX.INDEX_FLOAT64, length=-1, None, 8 + string="Float64"-->value_index=type_defs.VALUE_INDEX.INDEX_FLOAT64, length=-1, None, 8 """ - index, length, hex_repr = -1, -1, False + index, length, value_repr = -1, -1, type_defs.VALUE_REPR.UNSIGNED zero_terminate = None for key in type_defs.text_to_index_dict: if string.startswith(key): @@ -289,9 +292,11 @@ def text_to_valuetype(string): zero_terminate = False else: zero_terminate = True - elif "(h)" in string: - hex_repr = True - return index, length, zero_terminate, byte_len, hex_repr + if string.endswith("(s)"): + value_repr = type_defs.VALUE_REPR.SIGNED + elif string.endswith("(h)"): + value_repr = type_defs.VALUE_REPR.HEX + return index, length, zero_terminate, byte_len, value_repr #:tag:GUI diff --git a/libpince/type_defs.py b/libpince/type_defs.py index da0dea26..af0b53db 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -143,11 +143,20 @@ class FLOAT: XMM = ["xmm" + str(i) for i in range(8)] +class VALUE_REPR: + UNSIGNED = 0 + SIGNED = 1 + HEX = 2 + + class VALUE_INDEX: + # Beginning of the integer indexes, new integer indexes should be added between 0 and 3 INDEX_INT8 = 0 INDEX_INT16 = 1 INDEX_INT32 = 2 INDEX_INT64 = 3 + # Ending of the integer indexes + INDEX_FLOAT32 = 4 INDEX_FLOAT64 = 5 @@ -160,6 +169,10 @@ class VALUE_INDEX: INDEX_AOB = 10 # Array of Bytes + @staticmethod + def is_integer(value_index): + return VALUE_INDEX.INDEX_INT8 <= value_index <= VALUE_INDEX.INDEX_INT32 + @staticmethod def is_string(value_index): return VALUE_INDEX.INDEX_STRING_ASCII <= value_index <= VALUE_INDEX.INDEX_STRING_UTF32 From 40650ddea58240adabccdef9c2c90d4d7e96ad62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 11 Jul 2022 17:04:57 +0300 Subject: [PATCH 027/487] Remove redundant parentheses --- PINCE.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index 6de7a6cb..56340e4c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1244,22 +1244,22 @@ def update_progress_bar(self): global Exiting self.progressBar.setValue(0) ProgressRun = 1 - while (ProgressRun == 1 and Exiting == 0): + while ProgressRun == 1 and Exiting == 0: sleep(0.1) value = int(round(self.backend.get_scan_progress() * 100)) self.progressBar.setValue(value) def update_address_table_loop(self): - while (Exiting == 0): + while Exiting == 0: sleep(table_update_interval / 1000) - if (update_table): + if update_table: try: self.update_address_table() except: print("Update Table failed :(") def freeze(self): - while (FreezeStop == 0 and Exiting == 0): + while FreezeStop == 0 and Exiting == 0: sleep(FreezeInterval / 1000) for x in FreezeVars: GDB_Engine.write_memory(x, FreezeVars[x][0], FreezeVars[x][1]) @@ -1280,11 +1280,11 @@ def treeWidget_AddressTable_item_clicked(self, row, column): global FreezeStop global FreezeInterval global threadpool - if (column == 0): - if (row.checkState(0) == Qt.Checked): + if column == 0: + if row.checkState(0) == Qt.Checked: value = row.text(VALUE_COL) value_index = GuiUtils.text_to_valuetype(row.text(TYPE_COL))[0] - if (len(FreezeVars) == 0): + if len(FreezeVars) == 0: FreezeStop = 0 FreezeThread = Worker(self.freeze) threadpool.start(FreezeThread) @@ -1294,7 +1294,7 @@ def treeWidget_AddressTable_item_clicked(self, row, column): if row.text(ADDR_COL) in FreezeVars: del FreezeVars[row.text(ADDR_COL)] self.freeze_consistancy(row.text(ADDR_COL), Qt.Unchecked) - if (len(FreezeVars) == 0): + if len(FreezeVars) == 0: FreezeStop = 1 def treeWidget_AddressTable_change_repr(self, new_repr): From 1f9eaf7ba49bb99eced747a54370c34ec1bd4cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 13 Jul 2022 19:14:39 +0300 Subject: [PATCH 028/487] Refactor text_to_valuetype --- PINCE.py | 131 ++++++++++++++++++++++------------------ README.md | 1 - libpince/GuiUtils.py | 96 ----------------------------- libpince/type_defs.py | 44 ++++++++++++++ tests/GuiUtils_tests.py | 8 ++- 5 files changed, 121 insertions(+), 159 deletions(-) diff --git a/PINCE.py b/PINCE.py index 56340e4c..4910280c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -627,14 +627,13 @@ def treeWidget_AddressTable_context_menu_event(self, event): browse_region, disassemble, what_writes, what_reads, what_accesses] GuiUtils.delete_menu_entries(menu, deletion_list) else: - current_text = current_row.text(TYPE_COL) - index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(current_text) - if type_defs.VALUE_INDEX.is_integer(index): - if value_repr is type_defs.VALUE_REPR.HEX: + value_type = current_row.data(TYPE_COL, Qt.UserRole) + if type_defs.VALUE_INDEX.is_integer(value_type.value_index): + if value_type.value_repr is type_defs.VALUE_REPR.HEX: GuiUtils.delete_menu_entries(menu, [show_unsigned, show_signed, show_hex]) - elif value_repr is type_defs.VALUE_REPR.UNSIGNED: + elif value_type.value_repr is type_defs.VALUE_REPR.UNSIGNED: GuiUtils.delete_menu_entries(menu, [show_unsigned, show_dec]) - elif value_repr is type_defs.VALUE_REPR.SIGNED: + elif value_type.value_repr is type_defs.VALUE_REPR.SIGNED: GuiUtils.delete_menu_entries(menu, [show_signed, show_dec]) else: GuiUtils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed]) @@ -676,12 +675,15 @@ def exec_track_watchpoint_widget(self, watchpoint_type): if not selected_row: return address = selected_row.text(ADDR_COL) - value_type_text = selected_row.text(TYPE_COL) - index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type_text) - if byte_len == -1: + value_type = selected_row.data(TYPE_COL, Qt.UserRole) + if type_defs.VALUE_INDEX.is_string(value_type.value_index): value_text = selected_row.text(VALUE_COL) - encoding, option = type_defs.string_index_to_encoding_dict[index] + encoding, option = type_defs.string_index_to_encoding_dict[value_type.value_index] byte_len = len(value_text.encode(encoding, option)) + elif value_type.value_index == type_defs.VALUE_INDEX.INDEX_AOB: + byte_len = value_type.length + else: + byte_len = type_defs.index_to_valuetype_dict[value_type.value_index][0] TrackWatchpointWidgetForm(address, byte_len, watchpoint_type, self).show() def browse_region_for_selected_row(self): @@ -713,7 +715,7 @@ def cut_selected_records(self): def copy_selected_records(self): # Flat copy, does not preserve structure - app.clipboard().setText(repr([self.read_address_table_entries(selected_row) + ((),) for selected_row in + app.clipboard().setText(repr([self.read_address_table_entries(selected_row, True) + ((),) for selected_row in self.treeWidget_AddressTable.selectedItems()])) # each element in the list has no children @@ -763,7 +765,10 @@ def insert_records(self, records, parent_row, insert_index): for rec in records: row = QTreeWidgetItem() row.setCheckState(FROZEN_COL, Qt.Unchecked) - self.change_address_table_entries(row, *rec[:-1]) + + # Deserialize the value_type param + value_type = type_defs.ValueType(*rec[2]) + self.change_address_table_entries(row, *rec[:-2], value_type) self.insert_records(rec[-1], row, 0) rows.append(row) @@ -842,19 +847,19 @@ def update_address_table(self): break it += 1 address_expr_list.append(row.data(ADDR_COL, Qt.UserRole)) - value_type_list.append(row.text(TYPE_COL)) + value_type_list.append(row.data(TYPE_COL, Qt.UserRole)) rows.append(row) try: address_list = [item.address for item in GDB_Engine.examine_expressions(address_expr_list)] except type_defs.InferiorRunningException: address_list = address_expr_list for address, value_type in zip(address_list, value_type_list): - index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type) signed = False - if value_repr == type_defs.VALUE_REPR.SIGNED: + if value_type.value_repr == type_defs.VALUE_REPR.SIGNED: signed = True - table_contents.append((address, index, length, zero_terminate, signed)) - value_repr_list.append(value_repr) + current_item = (address, value_type.value_index, value_type.length, value_type.zero_terminate, signed) + table_contents.append(current_item) + value_repr_list.append(value_type.value_repr) new_table_contents = GDB_Engine.read_memory_multiple(table_contents) for row, address, address_expr, value, value_repr in zip(rows, address_list, address_expr_list, new_table_contents, value_repr_list): @@ -874,8 +879,8 @@ def resize_address_table(self): def pushButton_AddAddressManually_clicked(self): manual_address_dialog = ManualAddressDialogForm() if manual_address_dialog.exec_(): - desc, address_expr, address_type, length, zero_terminate = manual_address_dialog.get_values() - self.add_entry_to_addresstable(desc, address_expr, address_type, length, zero_terminate) + desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() + self.add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate) def pushButton_MemoryView_clicked(self): self.memory_view_window.showMaximized() @@ -1217,12 +1222,12 @@ def get_checked_state(self, address): else: return Qt.Unchecked - def add_entry_to_addresstable(self, description, address_expr, address_type, length=0, zero_terminate=True): + def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True): current_row = QTreeWidgetItem() current_row.setCheckState(FROZEN_COL, self.get_checked_state(address_expr)) - address_type_text = GuiUtils.valuetype_to_text(address_type, length, zero_terminate) + value_type = type_defs.ValueType(value_index, length, zero_terminate) self.treeWidget_AddressTable.addTopLevelItem(current_row) - self.change_address_table_entries(current_row, description, address_expr, address_type_text) + self.change_address_table_entries(current_row, description, address_expr, value_type) self.show() # In case of getting called from elsewhere self.activateWindow() @@ -1283,7 +1288,7 @@ def treeWidget_AddressTable_item_clicked(self, row, column): if column == 0: if row.checkState(0) == Qt.Checked: value = row.text(VALUE_COL) - value_index = GuiUtils.text_to_valuetype(row.text(TYPE_COL))[0] + value_index = row.data(TYPE_COL, Qt.UserRole).value_index if len(FreezeVars) == 0: FreezeStop = 0 FreezeThread = Worker(self.freeze) @@ -1298,10 +1303,11 @@ def treeWidget_AddressTable_item_clicked(self, row, column): FreezeStop = 1 def treeWidget_AddressTable_change_repr(self, new_repr): - value_text = GuiUtils.get_current_item(self.treeWidget_AddressTable).text(TYPE_COL) - index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_text) + value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.UserRole) + value_type.value_repr = new_repr for row in self.treeWidget_AddressTable.selectedItems(): - row.setText(TYPE_COL, GuiUtils.valuetype_to_text(index, length, zero_terminate, new_repr)) + row.setData(TYPE_COL, Qt.UserRole, value_type) + row.setText(TYPE_COL, value_type.text()) self.update_address_table() def treeWidget_AddressTable_edit_value(self): @@ -1310,7 +1316,7 @@ def treeWidget_AddressTable_edit_value(self): if not row: return value = row.text(VALUE_COL) - value_index = GuiUtils.text_to_valuetype(row.text(TYPE_COL))[0] + value_index = row.data(TYPE_COL, Qt.UserRole).value_index label_text = "Enter the new value" if type_defs.VALUE_INDEX.is_string(value_index): label_text += "\nPINCE doesn't automatically insert a null terminated string at the end" \ @@ -1318,20 +1324,20 @@ def treeWidget_AddressTable_edit_value(self): dialog = InputDialogForm(item_list=[(label_text, value)], parsed_index=0, value_index=value_index) if dialog.exec_(): table_contents = [] - value_text = dialog.get_values() + new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): address = row.text(ADDR_COL) - value_type = row.text(TYPE_COL) - value_index = GuiUtils.text_to_valuetype(value_type)[0] - if type_defs.VALUE_INDEX.is_string(value_index) or value_index == type_defs.VALUE_INDEX.INDEX_AOB: - unknown_type = SysUtils.parse_string(value_text, value_index) + value_type = row.data(TYPE_COL, Qt.UserRole) + if type_defs.VALUE_INDEX.has_length(value_type.value_index): + unknown_type = SysUtils.parse_string(new_value, value_type.value_index) if unknown_type is not None: - length = len(unknown_type) - row.setText(TYPE_COL, GuiUtils.change_text_length(value_type, length)) + value_type.length = len(unknown_type) + row.setData(TYPE_COL, Qt.UserRole, value_type) + row.setText(TYPE_COL, value_type.text()) if row.text(ADDR_COL) in FreezeVars: - FreezeVars[row.text(ADDR_COL)] = [value_index, value_text] - table_contents.append((address, value_index)) - GDB_Engine.write_memory_multiple(table_contents, value_text) + FreezeVars[row.text(ADDR_COL)] = [value_type.value_index, new_value] + table_contents.append((address, value_type.value_index)) + GDB_Engine.write_memory_multiple(table_contents, new_value) self.update_address_table() def treeWidget_AddressTable_edit_desc(self): @@ -1349,61 +1355,66 @@ def treeWidget_AddressTable_edit_address(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not row: return - desc, address_expr, value_type = self.read_address_table_entries(row=row) - index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type) - manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, index=index, - length=length, zero_terminate=zero_terminate) + desc, address_expr, value_type = self.read_address_table_entries(row) + manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, + index=value_type.value_index, length=value_type.length, + zero_terminate=value_type.zero_terminate) manual_address_dialog.setWindowTitle("Edit Address") if manual_address_dialog.exec_(): - desc, address_expr, address_type, length, zero_terminate = manual_address_dialog.get_values() - address_type_text = GuiUtils.valuetype_to_text(address_type, length, zero_terminate, value_repr) - self.change_address_table_entries(row, desc, address_expr, address_type_text) + desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() + value_type = type_defs.ValueType(value_index, length, zero_terminate, value_type.value_repr) + self.change_address_table_entries(row, desc, address_expr, value_type) def treeWidget_AddressTable_edit_type(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not row: return - value_type = row.text(TYPE_COL) - value_index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(value_type) - dialog = EditTypeDialogForm(index=value_index, length=length, zero_terminate=zero_terminate) + value_type = row.data(TYPE_COL, Qt.UserRole) + dialog = EditTypeDialogForm(index=value_type.value_index, length=value_type.length, + zero_terminate=value_type.zero_terminate) if dialog.exec_(): value_index, length, zero_terminate = dialog.get_values() - type_text = GuiUtils.valuetype_to_text(value_index, length, zero_terminate, value_repr) + value_type = type_defs.ValueType(value_index, length, zero_terminate, value_type.value_repr) for row in self.treeWidget_AddressTable.selectedItems(): - row.setText(TYPE_COL, type_text) + row.setData(TYPE_COL, Qt.UserRole, value_type) + row.setText(TYPE_COL, value_type.text()) self.update_address_table() # Changes the column values of the given row - def change_address_table_entries(self, row, description="", address_expr="", address_type=""): + def change_address_table_entries(self, row, description="", address_expr="", value_type=None): try: address = GDB_Engine.examine_expression(address_expr).address except type_defs.InferiorRunningException: address = address_expr value = '' - index, length, zero_terminate, byte_len, value_repr = GuiUtils.text_to_valuetype(address_type) if address: - value = GDB_Engine.read_memory(address, index, length, zero_terminate) + value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, + value_type.zero_terminate) assert isinstance(row, QTreeWidgetItem) row.setText(DESC_COL, description) row.setData(ADDR_COL, Qt.UserRole, address_expr) row.setText(ADDR_COL, address or address_expr) - row.setText(TYPE_COL, address_type) + row.setData(TYPE_COL, Qt.UserRole, value_type) + row.setText(TYPE_COL, value_type.text()) row.setText(VALUE_COL, "" if value is None else str(value)) self.update_address_table() # Returns the column values of the given row - def read_address_table_entries(self, row): + def read_address_table_entries(self, row, serialize=False): description = row.text(DESC_COL) address_expr = row.data(ADDR_COL, Qt.UserRole) - value_type = row.text(TYPE_COL) + if serialize: + value_type = row.data(TYPE_COL, Qt.UserRole).serialize() + else: + value_type = row.data(TYPE_COL, Qt.UserRole) return description, address_expr, value_type # Returns the values inside the given row and all of its descendants. # All values except the last are the same as read_address_table_entries output. # Last value is an iterable of information about its direct children. def read_address_table_recursively(self, row): - return self.read_address_table_entries(row) + \ + return self.read_address_table_entries(row, True) + \ ([self.read_address_table_recursively(row.child(i)) for i in range(row.childCount())],) @@ -1600,8 +1611,8 @@ def get_values(self): zero_terminate = False if self.checkBox_zeroterminate.isChecked(): zero_terminate = True - address_type = self.comboBox_ValueType.currentIndex() - return description, address, address_type, length, zero_terminate + value_index = self.comboBox_ValueType.currentIndex() + return description, address, value_index, length, zero_terminate class EditTypeDialogForm(QDialog, EditTypeDialog): @@ -2561,8 +2572,8 @@ def exec_hex_view_add_address_dialog(self): manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), index=type_defs.VALUE_INDEX.INDEX_AOB) if manual_address_dialog.exec_(): - desc, address_expr, address_type, length, zero_terminate = manual_address_dialog.get_values() - self.parent().add_entry_to_addresstable(desc, address_expr, address_type, length, zero_terminate) + desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() + self.parent().add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate) def verticalScrollBar_HexView_mouse_release_event(self, event): GuiUtils.center_scroll_bar(self.verticalScrollBar_HexView) diff --git a/README.md b/README.md index 1f5e1af3..87416a3a 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,6 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. Only update the visible rows to prevent this(check ```disassemble_check_viewport``` for an example) - - Implement same system for the TrackBreakpointWidgetForm if necessary. Do performance tests - - Consider using a class instead of primitive return types to store the raw bytes. This class should also include a method to display None type as red '??' text for Qt -- - text_to_valuetype is a bad design pattern. Store the information inside the items of tableWidget_AddressTable instead - - read_memory_multiple follows a bad design pattern, use named tuples or something like that - - Provide an option to cut BOM bytes when writing to memory with the types UTF-16 and UTF-32 - - Put a warning for users about replacement bytes for non UTF-8 types diff --git a/libpince/GuiUtils.py b/libpince/GuiUtils.py index b716685d..d8566268 100644 --- a/libpince/GuiUtils.py +++ b/libpince/GuiUtils.py @@ -221,102 +221,6 @@ def get_layout_widgets(layout): return [layout.itemAt(x).widget() for x in range(layout.count())] -#:tag:ValueType -def valuetype_to_text(value_index=int, length=0, zero_terminate=True, value_repr=type_defs.VALUE_REPR.UNSIGNED): - """Returns a str according to given parameters - - Args: - value_index (int): Determines the type of data. Can be a member of type_defs.VALUE_INDEX - length (int): Length of the data. Only used when the value_index is INDEX_STRING or INDEX_AOB. Ignored otherwise - zero_terminate (bool): If False, ",NZT" will be appended to str. Only used when value_index is INDEX_STRING. - Ignored otherwise. "NZT" stands for "Not Zero Terminate" - value_repr (int): Determines how the data is represented. Can be a member of type_defs.VALUE_REPR - - Returns: - str: A str generated by given parameters - str "out of bounds" is returned if the value_index doesn't match the dictionary - - Examples: - value_index=type_defs.VALUE_INDEX.INDEX_STRING_UTF16, length=15, zero_terminate=False--▼ - returned str="String_UTF16[15],NZT" - value_index=type_defs.VALUE_INDEX.INDEX_AOB, length=42-->returned str="AoB[42]" - """ - returned_string = type_defs.index_to_text_dict.get(value_index, "out of bounds") - if type_defs.VALUE_INDEX.is_string(value_index): - returned_string = returned_string + "[" + str(length) + "]" - if not zero_terminate: - returned_string += ",NZT" - elif value_index is type_defs.VALUE_INDEX.INDEX_AOB: - returned_string += "[" + str(length) + "]" - if type_defs.VALUE_INDEX.is_integer(value_index): - if value_repr is type_defs.VALUE_REPR.SIGNED: - returned_string += "(s)" - elif value_repr is type_defs.VALUE_REPR.HEX: - returned_string += "(h)" - return returned_string - - -#:tag:ValueType -def text_to_valuetype(string): - """Returns a tuple of parameters of the function valuetype_to_text evaluated according to given str - - Args: - string (str): String must be generated from the function valuetype_to_text - - Returns: - tuple: A tuple consisting of parameters of the function valuetype_to_text--▼ - value_index, length, zero_terminate, byte_length, value_repr - - If value_index doesn't contain length, length will be returned as -1 - If value_index is INDEX_STRING, byte_length will be returned as -1 - - Examples: - string="String_UTF8[15],NZT"--▼ - value_index=type_defs.VALUE_INDEX.INDEX_STRING_UTF8, length=15, zero_terminate=False, byte_length=-1 - string="AoB[42]"-->value_index=type_defs.VALUE_INDEX.INDEX_AOB, length=42, None, 42 - string="Float64"-->value_index=type_defs.VALUE_INDEX.INDEX_FLOAT64, length=-1, None, 8 - """ - index, length, value_repr = -1, -1, type_defs.VALUE_REPR.UNSIGNED - zero_terminate = None - for key in type_defs.text_to_index_dict: - if string.startswith(key): - index = type_defs.text_to_index_dict[key] - break - byte_len = type_defs.index_to_valuetype_dict.get(index, [-1])[0] - if type_defs.VALUE_INDEX.has_length(index): - length = int(common_regexes.valuetype_length.search(string).group(1)) - byte_len = length - if type_defs.VALUE_INDEX.is_string(index): - byte_len = -1 - if common_regexes.valuetype_nzt.search(string): - zero_terminate = False - else: - zero_terminate = True - if string.endswith("(s)"): - value_repr = type_defs.VALUE_REPR.SIGNED - elif string.endswith("(h)"): - value_repr = type_defs.VALUE_REPR.HEX - return index, length, zero_terminate, byte_len, value_repr - - -#:tag:GUI -def change_text_length(string, length): - """Changes the length of the given str to the given length - - Args: - string (str): String must be generated from the function valuetype_to_text - length (int,str): New length - - Returns: - str: The changed str - int: -1 is returned if the value_index of the given string isn't INDEX_STRING or INDEX_AOB - """ - index = text_to_valuetype(string)[0] - if type_defs.VALUE_INDEX.has_length(index): - return common_regexes.valuetype_length.sub("[" + str(length) + "]", string) - return -1 - - #:tag:GUI def contains_reference_mark(string): """Checks if given string contains the reference mark diff --git a/libpince/type_defs.py b/libpince/type_defs.py index af0b53db..df6cbbbb 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -405,6 +405,50 @@ def __init__(self, message="GDB not initialized"): super(GDBInitializeException, self).__init__(message) +class ValueType: + def __init__(self, value_index, length, zero_terminate, value_repr=VALUE_REPR.UNSIGNED): + """ + Args: + value_index (int): Determines the type of data. Can be a member of VALUE_INDEX + length (int): Length of the data. Only used when the value_index is INDEX_STRING or INDEX_AOB + zero_terminate (bool): If False, ",NZT" will be appended to the text representation + Only used when value_index is INDEX_STRING. Ignored otherwise. "NZT" stands for "Not Zero Terminate" + value_repr (int): Determines how the data is represented. Can be a member of VALUE_REPR + """ + self.value_index = value_index + self.length = length + self.zero_terminate = zero_terminate + self.value_repr = value_repr + + def serialize(self): + return self.value_index, self.length, self.zero_terminate, self.value_repr + + def text(self): + """Returns the text representation according to its members + + Returns: + str: A str generated by given parameters + + Examples: + value_index=VALUE_INDEX.INDEX_STRING_UTF16, length=15, zero_terminate=False--▼ + returned str="String_UTF16[15],NZT" + value_index=VALUE_INDEX.INDEX_AOB, length=42-->returned str="AoB[42]" + """ + returned_string = index_to_text_dict[self.value_index] + if VALUE_INDEX.is_string(self.value_index): + returned_string = returned_string + "[" + str(self.length) + "]" + if not self.zero_terminate: + returned_string += ",NZT" + elif self.value_index == VALUE_INDEX.INDEX_AOB: + returned_string += "[" + str(self.length) + "]" + if VALUE_INDEX.is_integer(self.value_index): + if self.value_repr == VALUE_REPR.SIGNED: + returned_string += "(s)" + elif self.value_repr == VALUE_REPR.HEX: + returned_string += "(h)" + return returned_string + + class RegisterQueue: def __init__(self): self.queue_list = [] diff --git a/tests/GuiUtils_tests.py b/tests/GuiUtils_tests.py index ad339c4f..1da4e72f 100644 --- a/tests/GuiUtils_tests.py +++ b/tests/GuiUtils_tests.py @@ -15,9 +15,13 @@ along with this program. If not, see . """ import unittest -from libpince import GuiUtils + + +# from libpince import GuiUtils class GuiUtils_tests(unittest.TestCase): def test_change_text_length(self): - self.assertEqual(GuiUtils.change_text_length("AoB[42]", 30), "AoB[30]") + self.assertEqual(True, True) + # The function below was removed during refactorization, thus making this test just a placeholder for now + # self.assertEqual(GuiUtils.change_text_length("AoB[42]", 30), "AoB[30]") From ede8aac4e1dc948a98d91430ecbcfaba0e15105c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 13 Jul 2022 21:28:38 +0300 Subject: [PATCH 029/487] Remove redundant update_address_table call --- PINCE.py | 1 - 1 file changed, 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 4910280c..c862c82e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1398,7 +1398,6 @@ def change_address_table_entries(self, row, description="", address_expr="", val row.setData(TYPE_COL, Qt.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) row.setText(VALUE_COL, "" if value is None else str(value)) - self.update_address_table() # Returns the column values of the given row def read_address_table_entries(self, row, serialize=False): From 70083c8e01eb8ad43adf14d461690c3c1fb79bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 14 Jul 2022 15:41:50 +0300 Subject: [PATCH 030/487] Remove unused regexes --- libpince/common_regexes.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index f9747113..4695e263 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -30,7 +30,6 @@ address_with_symbol = compile(r"(" + hex_number_grouped.pattern + r"\s*(<.+>)?)") # 0x7f3067f1174d \n thread_info = compile(r"\*\s+\d+\s+(.*)\\n") inferior_pid = compile(r"process\s+(\d+)") -numbers = compile(r"\d+") hw_breakpoint_count = compile(r"(hw|read|acc)") breakpoint_size = compile(r"char\[(\d+)\]") breakpoint_created = compile(r"breakpoint-created") @@ -53,8 +52,6 @@ # --------------------------------------------GuiUtils------------------------------------------------------------------ -valuetype_length = compile(r"\[(\d+)\]") -valuetype_nzt = compile(r",NZT") reference_mark = compile(r"\{\d*\}") # --------------------------------------------GDBCommandExtensions------------------------------------------------------ From eb35d44711b8dc2cf3cd4f57408adf1eaaec960c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 15 Jul 2022 00:12:26 +0300 Subject: [PATCH 031/487] Implement the new scope --- PINCE.py | 5 ++--- libpince/type_defs.py | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index c862c82e..2abb768d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -968,9 +968,8 @@ def comboBox_ScanType_init(self): self.comboBox_ScanType.setCurrentIndex(old_index) def comboBox_ScanScope_init(self): - items = [type_defs.SCAN_SCOPE.BASIC, type_defs.SCAN_SCOPE.NORMAL, type_defs.SCAN_SCOPE.FULL] - for scope in items: - self.comboBox_ScanScope.addItem(type_defs.scan_scope_to_text_dict[scope], scope) + for scope, text in type_defs.scan_scope_to_text_dict.items(): + self.comboBox_ScanScope.addItem(text, scope) self.comboBox_ScanScope.setCurrentIndex(1) # type_defs.SCAN_SCOPE.NORMAL def comboBox_ValueType_init(self): diff --git a/libpince/type_defs.py b/libpince/type_defs.py index df6cbbbb..e4ae1019 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -311,12 +311,14 @@ class SCAN_MODE: class SCAN_SCOPE: BASIC = 1 NORMAL = 2 - FULL = 3 + FULL_RW = 3 + FULL = 4 scan_scope_to_text_dict = collections.OrderedDict([ (SCAN_SCOPE.BASIC, "Basic"), (SCAN_SCOPE.NORMAL, "Normal"), + (SCAN_SCOPE.FULL_RW, "Read+Write"), (SCAN_SCOPE.FULL, "Full") ]) From 622f2019b82866103df29e10929466d58e3f4bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 15 Jul 2022 14:58:43 +0300 Subject: [PATCH 032/487] Reset scanmem on new search --- PINCE.py | 1 + 1 file changed, 1 insertion(+) diff --git a/PINCE.py b/PINCE.py index 2abb768d..238a4e0c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -931,6 +931,7 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_NextScan.setEnabled(True) search_scope = self.comboBox_ScanScope.currentData(Qt.UserRole) self.backend.send_command("option region_scan_level " + str(search_scope)) + self.backend.send_command("reset") self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan self.comboBox_ScanType_init() From d77984debf4acd54a6b767a4e4001d9a7cd45243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 16 Jul 2022 21:12:53 +0300 Subject: [PATCH 033/487] Implement increment/decrement mode for freezing --- PINCE.py | 44 +++++++++++++++++++++++++++++++++++-------- libpince/type_defs.py | 6 ++++++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index 238a4e0c..9c9c48b9 100755 --- a/PINCE.py +++ b/PINCE.py @@ -227,6 +227,7 @@ def get_hotkeys(): # vars for communication/storage with the non blocking threads # see treeWidget_AddressTable_item_clicked Exiting = 0 +# Format: {address:[value_index, value, freeze_type]} FreezeVars = {} FreezeStop = 0 ProgressRun = 0 @@ -606,6 +607,10 @@ def treeWidget_AddressTable_context_menu_event(self, event): show_unsigned = menu.addAction("Show as unsigned") show_signed = menu.addAction("Show as signed") toggle_record = menu.addAction("Toggle selected records[Space]") + freeze_menu = menu.addMenu("Freeze") + freeze_default = freeze_menu.addAction("Default") + freeze_inc = freeze_menu.addAction("Incremental") + freeze_dec = freeze_menu.addAction("Decremental") menu.addSeparator() browse_region = menu.addAction("Browse this memory region[Ctrl+B]") disassemble = menu.addAction("Disassemble this address[Ctrl+D]") @@ -624,7 +629,8 @@ def treeWidget_AddressTable_context_menu_event(self, event): what_accesses = menu.addAction("Find out what accesses this address") if current_row is None: deletion_list = [edit_menu.menuAction(), show_hex, show_dec, show_unsigned, show_signed, toggle_record, - browse_region, disassemble, what_writes, what_reads, what_accesses] + freeze_menu.menuAction(), browse_region, disassemble, what_writes, what_reads, + what_accesses] GuiUtils.delete_menu_entries(menu, deletion_list) else: value_type = current_row.data(TYPE_COL, Qt.UserRole) @@ -635,8 +641,11 @@ def treeWidget_AddressTable_context_menu_event(self, event): GuiUtils.delete_menu_entries(menu, [show_unsigned, show_dec]) elif value_type.value_repr is type_defs.VALUE_REPR.SIGNED: GuiUtils.delete_menu_entries(menu, [show_signed, show_dec]) + if current_row.checkState(FROZEN_COL) == Qt.Unchecked: + GuiUtils.delete_menu_entries(menu, [freeze_menu.menuAction()]) else: - GuiUtils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed]) + GuiUtils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed, + freeze_menu.menuAction()]) font_size = self.treeWidget_AddressTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec_(event.globalPos()) @@ -650,6 +659,9 @@ def treeWidget_AddressTable_context_menu_event(self, event): show_unsigned: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.UNSIGNED), show_signed: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.SIGNED), toggle_record: self.toggle_selected_records, + freeze_default: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.DEFAULT), + freeze_inc: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.INCREMENT), + freeze_dec: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.DECREMENT), browse_region: self.browse_region_for_selected_row, disassemble: self.disassemble_selected_row, cut_record: self.cut_selected_records, @@ -700,6 +712,12 @@ def disassemble_selected_row(self): self.memory_view_window.show() self.memory_view_window.activateWindow() + def change_freeze_type(self, freeze_type): + global FreezeVars + for row in self.treeWidget_AddressTable.selectedItems(): + row.setData(FROZEN_COL, Qt.UserRole, freeze_type) + FreezeVars[row.text(ADDR_COL)][2] = freeze_type + def toggle_selected_records(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if row: @@ -707,6 +725,7 @@ def toggle_selected_records(self): new_check_state = Qt.Checked if check_state == Qt.Unchecked else Qt.Unchecked for row in self.treeWidget_AddressTable.selectedItems(): row.setCheckState(FROZEN_COL, new_check_state) + self.treeWidget_AddressTable_item_clicked(row, FROZEN_COL) def cut_selected_records(self): # Flat cut, does not preserve structure @@ -1225,6 +1244,7 @@ def get_checked_state(self, address): def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True): current_row = QTreeWidgetItem() current_row.setCheckState(FROZEN_COL, self.get_checked_state(address_expr)) + current_row.setData(FROZEN_COL, Qt.UserRole, type_defs.FREEZE_TYPE.DEFAULT) value_type = type_defs.ValueType(value_index, length, zero_terminate) self.treeWidget_AddressTable.addTopLevelItem(current_row) self.change_address_table_entries(current_row, description, address_expr, value_type) @@ -1264,10 +1284,18 @@ def update_address_table_loop(self): print("Update Table failed :(") def freeze(self): + global FreezeVars while FreezeStop == 0 and Exiting == 0: sleep(FreezeInterval / 1000) - for x in FreezeVars: - GDB_Engine.write_memory(x, FreezeVars[x][0], FreezeVars[x][1]) + for address, (value_index, value, freeze_type) in FreezeVars.items(): + if type_defs.VALUE_INDEX.is_integer(value_index): + new_value = GDB_Engine.read_memory(address, value_index) + if freeze_type == type_defs.FREEZE_TYPE.INCREMENT and new_value > int(value, 0) or \ + freeze_type == type_defs.FREEZE_TYPE.DECREMENT and new_value < int(value, 0): + FreezeVars[address][1] = str(new_value) + GDB_Engine.write_memory(address, value_index, new_value) + continue + GDB_Engine.write_memory(address, value_index, value) # ---------------------------------------------------- @@ -1285,15 +1313,15 @@ def treeWidget_AddressTable_item_clicked(self, row, column): global FreezeStop global FreezeInterval global threadpool - if column == 0: - if row.checkState(0) == Qt.Checked: + if column == FROZEN_COL: + if row.checkState(FROZEN_COL) == Qt.Checked: value = row.text(VALUE_COL) value_index = row.data(TYPE_COL, Qt.UserRole).value_index if len(FreezeVars) == 0: FreezeStop = 0 FreezeThread = Worker(self.freeze) threadpool.start(FreezeThread) - FreezeVars[row.text(ADDR_COL)] = [value_index, value] + FreezeVars[row.text(ADDR_COL)] = [value_index, value, type_defs.FREEZE_TYPE.DEFAULT] self.freeze_consistancy(row.text(ADDR_COL), Qt.Checked) else: if row.text(ADDR_COL) in FreezeVars: @@ -1335,7 +1363,7 @@ def treeWidget_AddressTable_edit_value(self): row.setData(TYPE_COL, Qt.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) if row.text(ADDR_COL) in FreezeVars: - FreezeVars[row.text(ADDR_COL)] = [value_type.value_index, new_value] + FreezeVars[row.text(ADDR_COL)][1] = new_value table_contents.append((address, value_type.value_index)) GDB_Engine.write_memory_multiple(table_contents, new_value) self.update_address_table() diff --git a/libpince/type_defs.py b/libpince/type_defs.py index e4ae1019..ca7a16ce 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -143,6 +143,12 @@ class FLOAT: XMM = ["xmm" + str(i) for i in range(8)] +class FREEZE_TYPE: + DEFAULT = 0 + INCREMENT = 1 + DECREMENT = 2 + + class VALUE_REPR: UNSIGNED = 0 SIGNED = 1 From bff82201dc9ac72fe99389705b3ab8aec9ef00db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 17 Jul 2022 16:07:34 +0300 Subject: [PATCH 034/487] Refactor freezing --- PINCE.py | 96 +++++++++++++++---------------------------- libpince/type_defs.py | 6 +++ 2 files changed, 38 insertions(+), 64 deletions(-) diff --git a/PINCE.py b/PINCE.py index 9c9c48b9..b6bb021f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -225,11 +225,7 @@ def get_hotkeys(): saved_addresses_changed_list = list() # vars for communication/storage with the non blocking threads -# see treeWidget_AddressTable_item_clicked Exiting = 0 -# Format: {address:[value_index, value, freeze_type]} -FreezeVars = {} -FreezeStop = 0 ProgressRun = 0 threadpool = QThreadPool() @@ -399,8 +395,10 @@ def __init__(self): self.check_status_thread.process_running.connect(self.memory_view_window.process_running) self.check_status_thread.start() self.update_address_table_thread = Worker(self.update_address_table_loop) + self.freeze_thread = Worker(self.freeze_loop) global threadpool threadpool.start(self.update_address_table_thread) + threadpool.start(self.freeze_thread) self.shortcut_open_file = QShortcut(QKeySequence("Ctrl+O"), self) self.shortcut_open_file.activated.connect(self.pushButton_Open_clicked) GuiUtils.append_shortcut_to_tooltip(self.pushButton_Open, self.shortcut_open_file) @@ -713,10 +711,9 @@ def disassemble_selected_row(self): self.memory_view_window.activateWindow() def change_freeze_type(self, freeze_type): - global FreezeVars for row in self.treeWidget_AddressTable.selectedItems(): - row.setData(FROZEN_COL, Qt.UserRole, freeze_type) - FreezeVars[row.text(ADDR_COL)][2] = freeze_type + frozen = row.data(FROZEN_COL, Qt.UserRole) + frozen.freeze_type = freeze_type def toggle_selected_records(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) @@ -811,21 +808,10 @@ def paste_records(self, insert_after=None, insert_inside=False): self.insert_records(records, parent, parent.indexOfChild(insert_row) + insert_after) self.update_address_table() - def check_if_address_exists(self, address): - root = self.treeWidget_AddressTable.invisibleRootItem() - child_count = root.childCount() - for i in range(child_count): - item = root.child(i) - if item.text(ADDR_COL) == address: - return True - return False - def delete_selected_records(self): root = self.treeWidget_AddressTable.invisibleRootItem() for item in self.treeWidget_AddressTable.selectedItems(): (item.parent() or root).removeChild(item) - if not self.check_if_address_exists(item.text(ADDR_COL)): - del FreezeVars[item.text(ADDR_COL)] def treeWidget_AddressTable_key_press_event(self, event): actions = type_defs.KeyboardModifiersTupleDict([ @@ -1233,18 +1219,11 @@ def closeEvent(self, event): GDB_Engine.detach() app.closeAllWindows() - # checks if item is a duplicate of something currently being frozen - def get_checked_state(self, address): - global FreezeVars - if address in FreezeVars: - return Qt.Checked - else: - return Qt.Unchecked - def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True): current_row = QTreeWidgetItem() - current_row.setCheckState(FROZEN_COL, self.get_checked_state(address_expr)) - current_row.setData(FROZEN_COL, Qt.UserRole, type_defs.FREEZE_TYPE.DEFAULT) + current_row.setCheckState(FROZEN_COL, Qt.Unchecked) + frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) + current_row.setData(FROZEN_COL, Qt.UserRole, frozen) value_type = type_defs.ValueType(value_index, length, zero_terminate) self.treeWidget_AddressTable.addTopLevelItem(current_row) self.change_address_table_entries(current_row, description, address_expr, value_type) @@ -1283,52 +1262,41 @@ def update_address_table_loop(self): except: print("Update Table failed :(") - def freeze(self): - global FreezeVars - while FreezeStop == 0 and Exiting == 0: + def freeze_loop(self): + while Exiting == 0: sleep(FreezeInterval / 1000) - for address, (value_index, value, freeze_type) in FreezeVars.items(): + try: + self.freeze() + except: + print("Freeze failed :(") + + def freeze(self): + it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) + while it.value(): + row = it.value() + if row.checkState(FROZEN_COL) == Qt.Checked: + value_index = row.data(TYPE_COL, Qt.UserRole).value_index + address = row.text(ADDR_COL) + frozen = row.data(FROZEN_COL, Qt.UserRole) + value = frozen.value + freeze_type = frozen.freeze_type if type_defs.VALUE_INDEX.is_integer(value_index): new_value = GDB_Engine.read_memory(address, value_index) if freeze_type == type_defs.FREEZE_TYPE.INCREMENT and new_value > int(value, 0) or \ freeze_type == type_defs.FREEZE_TYPE.DECREMENT and new_value < int(value, 0): - FreezeVars[address][1] = str(new_value) - GDB_Engine.write_memory(address, value_index, new_value) + frozen.value = str(new_value) + GDB_Engine.write_memory(address, value_index, frozen.value) continue GDB_Engine.write_memory(address, value_index, value) + it += 1 # ---------------------------------------------------- - def freeze_consistancy(self, address, constant): - root = self.treeWidget_AddressTable.invisibleRootItem() - child_count = root.childCount() - for i in range(child_count): - item = root.child(i) - if item.text(ADDR_COL) == address: - if item.checkState(0) != constant: - item.setCheckState(0, constant) - def treeWidget_AddressTable_item_clicked(self, row, column): - global FreezeVars - global FreezeStop - global FreezeInterval - global threadpool if column == FROZEN_COL: if row.checkState(FROZEN_COL) == Qt.Checked: - value = row.text(VALUE_COL) - value_index = row.data(TYPE_COL, Qt.UserRole).value_index - if len(FreezeVars) == 0: - FreezeStop = 0 - FreezeThread = Worker(self.freeze) - threadpool.start(FreezeThread) - FreezeVars[row.text(ADDR_COL)] = [value_index, value, type_defs.FREEZE_TYPE.DEFAULT] - self.freeze_consistancy(row.text(ADDR_COL), Qt.Checked) - else: - if row.text(ADDR_COL) in FreezeVars: - del FreezeVars[row.text(ADDR_COL)] - self.freeze_consistancy(row.text(ADDR_COL), Qt.Unchecked) - if len(FreezeVars) == 0: - FreezeStop = 1 + frozen = row.data(FROZEN_COL, Qt.UserRole) + frozen.value = row.text(VALUE_COL) def treeWidget_AddressTable_change_repr(self, new_repr): value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.UserRole) @@ -1339,7 +1307,6 @@ def treeWidget_AddressTable_change_repr(self, new_repr): self.update_address_table() def treeWidget_AddressTable_edit_value(self): - global FreezeVars row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not row: return @@ -1362,8 +1329,9 @@ def treeWidget_AddressTable_edit_value(self): value_type.length = len(unknown_type) row.setData(TYPE_COL, Qt.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) - if row.text(ADDR_COL) in FreezeVars: - FreezeVars[row.text(ADDR_COL)][1] = new_value + frozen = row.data(FROZEN_COL, Qt.UserRole) + frozen.value = new_value + row.setData(FROZEN_COL, Qt.UserRole, frozen) table_contents.append((address, value_type.value_index)) GDB_Engine.write_memory_multiple(table_contents, new_value) self.update_address_table() diff --git a/libpince/type_defs.py b/libpince/type_defs.py index ca7a16ce..c6748477 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -413,6 +413,12 @@ def __init__(self, message="GDB not initialized"): super(GDBInitializeException, self).__init__(message) +class Frozen: + def __init__(self, value, freeze_type): + self.value = value + self.freeze_type = freeze_type + + class ValueType: def __init__(self, value_index, length, zero_terminate, value_repr=VALUE_REPR.UNSIGNED): """ From e93c2323a22459e6887fd6bd05e2ff5ecbad186c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 17 Jul 2022 17:42:04 +0300 Subject: [PATCH 035/487] Add null while modifying strings --- PINCE.py | 10 +++------- README.md | 2 +- libpince/GDB_Engine.py | 21 --------------------- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/PINCE.py b/PINCE.py index b6bb021f..e4614fe0 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1313,13 +1313,11 @@ def treeWidget_AddressTable_edit_value(self): value = row.text(VALUE_COL) value_index = row.data(TYPE_COL, Qt.UserRole).value_index label_text = "Enter the new value" - if type_defs.VALUE_INDEX.is_string(value_index): - label_text += "\nPINCE doesn't automatically insert a null terminated string at the end" \ - "\nCopy-paste this character(\0) if you need to insert it at somewhere" dialog = InputDialogForm(item_list=[(label_text, value)], parsed_index=0, value_index=value_index) if dialog.exec_(): - table_contents = [] new_value = dialog.get_values() + if type_defs.VALUE_INDEX.is_string(value_index): + new_value += "\0" for row in self.treeWidget_AddressTable.selectedItems(): address = row.text(ADDR_COL) value_type = row.data(TYPE_COL, Qt.UserRole) @@ -1327,13 +1325,11 @@ def treeWidget_AddressTable_edit_value(self): unknown_type = SysUtils.parse_string(new_value, value_type.value_index) if unknown_type is not None: value_type.length = len(unknown_type) - row.setData(TYPE_COL, Qt.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) frozen = row.data(FROZEN_COL, Qt.UserRole) frozen.value = new_value row.setData(FROZEN_COL, Qt.UserRole, frozen) - table_contents.append((address, value_type.value_index)) - GDB_Engine.write_memory_multiple(table_contents, new_value) + GDB_Engine.write_memory(address, value_type.value_index, new_value) self.update_address_table() def treeWidget_AddressTable_edit_desc(self): diff --git a/README.md b/README.md index 87416a3a..520af98e 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run # Current Roadmap - Refactor file naming conventions(decide on snake_case or camelCase for modules etc) - Create ```CONTRIBUTING.md``` and combine all non-tutorial notes within it -- Consider replacing read/write_memory_multiple functions with mem_handle&read/write_memory functions, this fixes the "read_memory_multiple follows a bad design pattern" step +- Consider replacing read_memory_multiple function with mem_handle&read_memory functions, this fixes the "read_memory_multiple follows a bad design pattern" step - Refactorize memory write/read functions - - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. Only update the visible rows to prevent this(check ```disassemble_check_viewport``` for an example) - - Implement same system for the TrackBreakpointWidgetForm if necessary. Do performance tests diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 889423d1..95baa179 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -935,27 +935,6 @@ def write_memory(address, value_index, value): return -#:tag:MemoryRW -def write_memory_multiple(nested_list, value): - """Sets the given value to the given addresses - - If any errors occurs while setting values to the according addresses, it'll be ignored but the information about - error will be printed to the terminal. - - Args: - nested_list (list): List of the address and value_index parameters of the function write_memory - Both parameters address and value_index are necessary. - value (str): The value that'll be written to the given addresses - - Examples: - nested_list-->[[address1, value_index1],[address2, value_index2], ...] - """ - for item in nested_list: - address = item[0] - index = item[1] - write_memory(address, index, value) - - #:tag:Assembly def disassemble(expression, offset_or_address): """Disassembles the address evaluated by the given expression From c42128f42721a5bd691d63c2037cc4ebd549ba50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 17 Jul 2022 18:53:10 +0300 Subject: [PATCH 036/487] Hotfix freezing --- PINCE.py | 6 +++--- libpince/GDB_Engine.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index e4614fe0..a1ba8c97 100755 --- a/PINCE.py +++ b/PINCE.py @@ -781,6 +781,8 @@ def insert_records(self, records, parent_row, insert_index): for rec in records: row = QTreeWidgetItem() row.setCheckState(FROZEN_COL, Qt.Unchecked) + frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) + row.setData(FROZEN_COL, Qt.UserRole, frozen) # Deserialize the value_type param value_type = type_defs.ValueType(*rec[2]) @@ -1288,7 +1290,7 @@ def freeze(self): GDB_Engine.write_memory(address, value_index, frozen.value) continue GDB_Engine.write_memory(address, value_index, value) - it += 1 + it += 1 # ---------------------------------------------------- @@ -1316,8 +1318,6 @@ def treeWidget_AddressTable_edit_value(self): dialog = InputDialogForm(item_list=[(label_text, value)], parsed_index=0, value_index=value_index) if dialog.exec_(): new_value = dialog.get_values() - if type_defs.VALUE_INDEX.is_string(value_index): - new_value += "\0" for row in self.treeWidget_AddressTable.selectedItems(): address = row.text(ADDR_COL) value_type = row.data(TYPE_COL, Qt.UserRole) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 95baa179..54032999 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -923,7 +923,7 @@ def write_memory(address, value_index, value): data_type = type_defs.index_to_struct_pack_dict.get(value_index, -1) write_data = struct.pack(data_type, write_data) else: - write_data = write_data.encode(encoding, option) + write_data = write_data.encode(encoding, option) + b"\x00" # Zero-terminated by default FILE = open(mem_file, "rb+") try: FILE.seek(address) From c4f3549eaf176a8eca1631cd07acf20a9d08d6ae Mon Sep 17 00:00:00 2001 From: Berk Ozler Date: Sun, 17 Jul 2022 19:09:40 +0300 Subject: [PATCH 037/487] Added basic pointer type support --- GUI/AddAddressManuallyDialog.py | 149 ++++++++++------ GUI/AddAddressManuallyDialog.ui | 294 +++++++++++++++++++++----------- PINCE.py | 91 +++++++--- libpince/GDB_Engine.py | 30 ++++ libpince/type_defs.py | 21 +++ 5 files changed, 417 insertions(+), 168 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 00ade6c1..bf6f9930 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -2,68 +2,59 @@ # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt5 UI code generator 5.15.7 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + from PyQt5 import QtCore, QtGui, QtWidgets + class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(232, 248) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + Dialog.resize(224, 360) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) Dialog.setSizePolicy(sizePolicy) - Dialog.setMaximumSize(QtCore.QSize(16777215, 248)) + Dialog.setMinimumSize(QtCore.QSize(0, 0)) + Dialog.setMaximumSize(QtCore.QSize(224, 360)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) - self.buttonBox.setObjectName("buttonBox") - self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 1) - self.verticalLayout_2 = QtWidgets.QVBoxLayout() - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.label = QtWidgets.QLabel(Dialog) - self.label.setObjectName("label") - self.verticalLayout_2.addWidget(self.label) - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - self.lineEdit_address = QtWidgets.QLineEdit(Dialog) + self.widget_Pointer = QtWidgets.QWidget(Dialog) + self.widget_Pointer.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_Pointer.sizePolicy().hasHeightForWidth()) + self.widget_Pointer.setSizePolicy(sizePolicy) + self.widget_Pointer.setMinimumSize(QtCore.QSize(0, 0)) + self.widget_Pointer.setObjectName("widget_Pointer") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.widget_Pointer) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.verticalLayout_Pointers = QtWidgets.QVBoxLayout() + self.verticalLayout_Pointers.setObjectName("verticalLayout_Pointers") + self.label_BaseAddress = QtWidgets.QLabel(self.widget_Pointer) + self.label_BaseAddress.setObjectName("label_BaseAddress") + self.verticalLayout_Pointers.addWidget(self.label_BaseAddress) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.lineEdit_PtrStartAddress = QtWidgets.QLineEdit(self.widget_Pointer) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_address.sizePolicy().hasHeightForWidth()) - self.lineEdit_address.setSizePolicy(sizePolicy) - self.lineEdit_address.setMinimumSize(QtCore.QSize(100, 0)) - self.lineEdit_address.setText("") - self.lineEdit_address.setObjectName("lineEdit_address") - self.horizontalLayout.addWidget(self.lineEdit_address) - self.label_2 = QtWidgets.QLabel(Dialog) - self.label_2.setObjectName("label_2") - self.horizontalLayout.addWidget(self.label_2) - self.label_valueofaddress = QtWidgets.QLabel(Dialog) - self.label_valueofaddress.setText("") - self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) - self.label_valueofaddress.setObjectName("label_valueofaddress") - self.horizontalLayout.addWidget(self.label_valueofaddress) + sizePolicy.setHeightForWidth(self.lineEdit_PtrStartAddress.sizePolicy().hasHeightForWidth()) + self.lineEdit_PtrStartAddress.setSizePolicy(sizePolicy) + self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") + self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem) - self.verticalLayout_2.addLayout(self.horizontalLayout) - self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) - self.verticalLayout = QtWidgets.QVBoxLayout() - self.verticalLayout.setObjectName("verticalLayout") - self.label_4 = QtWidgets.QLabel(Dialog) - self.label_4.setObjectName("label_4") - self.verticalLayout.addWidget(self.label_4) - self.lineEdit_description = QtWidgets.QLineEdit(Dialog) - self.lineEdit_description.setText("") - self.lineEdit_description.setObjectName("lineEdit_description") - self.verticalLayout.addWidget(self.lineEdit_description) - self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) + self.horizontalLayout_4.addItem(spacerItem) + self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) + self.verticalLayout_4.addLayout(self.verticalLayout_Pointers) + self.gridLayout.addWidget(self.widget_Pointer, 7, 0, 1, 1) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") self.horizontalLayout_3 = QtWidgets.QHBoxLayout() @@ -106,21 +97,77 @@ def setupUi(self, Dialog): self.horizontalLayout_2.addWidget(self.lineEdit_length) self.verticalLayout_3.addLayout(self.horizontalLayout_2) self.gridLayout.addLayout(self.verticalLayout_3, 2, 0, 1, 1) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label = QtWidgets.QLabel(Dialog) + self.label.setObjectName("label") + self.verticalLayout_2.addWidget(self.label) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.lineEdit_address = QtWidgets.QLineEdit(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_address.sizePolicy().hasHeightForWidth()) + self.lineEdit_address.setSizePolicy(sizePolicy) + self.lineEdit_address.setMinimumSize(QtCore.QSize(100, 0)) + self.lineEdit_address.setText("") + self.lineEdit_address.setObjectName("lineEdit_address") + self.horizontalLayout.addWidget(self.lineEdit_address) + self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.label_valueofaddress = QtWidgets.QLabel(Dialog) + self.label_valueofaddress.setText("") + self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_valueofaddress.setObjectName("label_valueofaddress") + self.horizontalLayout.addWidget(self.label_valueofaddress) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.verticalLayout_2.addLayout(self.horizontalLayout) + self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) + self.checkBox_IsPointer = QtWidgets.QCheckBox(Dialog) + self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") + self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.label_4 = QtWidgets.QLabel(Dialog) + self.label_4.setObjectName("label_4") + self.verticalLayout.addWidget(self.label_4) + self.lineEdit_description = QtWidgets.QLineEdit(Dialog) + self.lineEdit_description.setText("") + self.lineEdit_description.setObjectName("lineEdit_description") + self.verticalLayout.addWidget(self.lineEdit_description) + self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) + self.buttonBox.setSizePolicy(sizePolicy) + self.buttonBox.setMaximumSize(QtCore.QSize(16777215, 35)) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) + spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem4, 8, 0, 1, 1) self.retranslateUi(Dialog) self.comboBox_ValueType.setCurrentIndex(-1) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Add Address Manually")) - self.label.setText(_translate("Dialog", "Address:")) - self.label_2.setText(_translate("Dialog", "=")) - self.label_4.setText(_translate("Dialog", "Description:")) + self.label_BaseAddress.setText(_translate("Dialog", "Base Address:")) self.label_5.setText(_translate("Dialog", "Type:")) self.checkBox_zeroterminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_length.setText(_translate("Dialog", "Length")) self.lineEdit_length.setText(_translate("Dialog", "10")) - + self.label.setText(_translate("Dialog", "Address:")) + self.label_2.setText(_translate("Dialog", "=")) + self.checkBox_IsPointer.setText(_translate("Dialog", "Pointer")) + self.label_4.setText(_translate("Dialog", "Description:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 89610ce6..bab57f75 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -6,118 +6,91 @@ 0 0 - 232 - 248 + 224 + 360 - + 0 0 + + + 0 + 0 + + - 16777215 - 248 + 224 + 360 Add Address Manually - - - - Qt::Horizontal + + + + true - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + Base Address: + + + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + - - - - - - Address: - - - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - - - - - - - = - - - - - - - - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Description: - - - - - - - - - - - - @@ -218,6 +191,133 @@ + + + + + + Address: + + + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + + + + + = + + + + + + + + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Pointer + + + + + + + + + Description: + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 35 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + @@ -229,8 +329,8 @@ accept() - 280 - 371 + 286 + 399 157 @@ -245,8 +345,8 @@ reject() - 280 - 371 + 286 + 399 283 diff --git a/PINCE.py b/PINCE.py index a1ba8c97..bea5ee21 100755 --- a/PINCE.py +++ b/PINCE.py @@ -684,7 +684,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): selected_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not selected_row: return - address = selected_row.text(ADDR_COL) + address = selected_row.text(ADDR_COL).strip("P->") value_type = selected_row.data(TYPE_COL, Qt.UserRole) if type_defs.VALUE_INDEX.is_string(value_type.value_index): value_text = selected_row.text(VALUE_COL) @@ -699,14 +699,14 @@ def exec_track_watchpoint_widget(self, watchpoint_type): def browse_region_for_selected_row(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if row: - self.memory_view_window.hex_dump_address(int(row.text(ADDR_COL), 16)) + self.memory_view_window.hex_dump_address(int(row.text(ADDR_COL).strip("P->"), 16)) self.memory_view_window.show() self.memory_view_window.activateWindow() def disassemble_selected_row(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if row: - if self.memory_view_window.disassemble_expression(row.text(ADDR_COL), append_to_travel_history=True): + if self.memory_view_window.disassemble_expression(row.text(ADDR_COL).strip("P->"), append_to_travel_history=True): self.memory_view_window.show() self.memory_view_window.activateWindow() @@ -853,7 +853,12 @@ def update_address_table(self): if not row: break it += 1 - address_expr_list.append(row.data(ADDR_COL, Qt.UserRole)) + address_data = row.data(ADDR_COL, Qt.UserRole) + if isinstance(address_data, type_defs.PointerType): + pointer_address = GDB_Engine.read_pointer(address_data) + address_expr_list.append(hex(pointer_address)) + else: + address_expr_list.append(address_data) value_type_list.append(row.data(TYPE_COL, Qt.UserRole)) rows.append(row) try: @@ -870,7 +875,12 @@ def update_address_table(self): new_table_contents = GDB_Engine.read_memory_multiple(table_contents) for row, address, address_expr, value, value_repr in zip(rows, address_list, address_expr_list, new_table_contents, value_repr_list): - row.setText(ADDR_COL, address or address_expr) + address_data = row.data(ADDR_COL, Qt.UserRole) + if isinstance(address_data, type_defs.PointerType): + address_text = f'P->{address}' + else: + address_text = address + row.setText(ADDR_COL, address_text or address_expr) if value is None: value = "" elif value_repr == type_defs.VALUE_REPR.HEX: @@ -1072,7 +1082,7 @@ def _scan_to_length(self, type_index): def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) - self.add_entry_to_addresstable("", current_item.text(), current_item.data(Qt.UserRole), length) + self.add_entry_to_addresstable("No Description", current_item.text(), current_item.data(Qt.UserRole), length) def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.UserRole) @@ -1278,7 +1288,7 @@ def freeze(self): row = it.value() if row.checkState(FROZEN_COL) == Qt.Checked: value_index = row.data(TYPE_COL, Qt.UserRole).value_index - address = row.text(ADDR_COL) + address = row.text(ADDR_COL).strip("P->") frozen = row.data(FROZEN_COL, Qt.UserRole) value = frozen.value freeze_type = frozen.freeze_type @@ -1319,7 +1329,7 @@ def treeWidget_AddressTable_edit_value(self): if dialog.exec_(): new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): - address = row.text(ADDR_COL) + address = row.text(ADDR_COL).strip("P->") # strip leading pointer text if pointer value_type = row.data(TYPE_COL, Qt.UserRole) if type_defs.VALUE_INDEX.has_length(value_type.value_index): unknown_type = SysUtils.parse_string(new_value, value_type.value_index) @@ -1373,11 +1383,16 @@ def treeWidget_AddressTable_edit_type(self): self.update_address_table() # Changes the column values of the given row - def change_address_table_entries(self, row, description="", address_expr="", value_type=None): - try: - address = GDB_Engine.examine_expression(address_expr).address - except type_defs.InferiorRunningException: - address = address_expr + def change_address_table_entries(self, row, description="No Description", address_expr="", value_type=None): + if isinstance(address_expr, type_defs.PointerType): + address = GDB_Engine.read_pointer(address_expr) + address_text = f'P->{hex(address)}' + else: + try: + address = GDB_Engine.examine_expression(address_expr).address + except type_defs.InferiorRunningException: + address = address_expr + address_text = hex(address) if type(address) != str else address value = '' if address: value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, @@ -1386,7 +1401,7 @@ def change_address_table_entries(self, row, description="", address_expr="", val assert isinstance(row, QTreeWidgetItem) row.setText(DESC_COL, description) row.setData(ADDR_COL, Qt.UserRole, address_expr) - row.setText(ADDR_COL, address or address_expr) + row.setText(ADDR_COL, address_text or address_expr) row.setData(TYPE_COL, Qt.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) row.setText(VALUE_COL, "" if value is None else str(value)) @@ -1494,7 +1509,14 @@ def __init__(self, parent=None, description="No Description", address="0x", self.lineEdit_length.setValidator(QHexValidator(999, self)) GuiUtils.fill_value_combobox(self.comboBox_ValueType, index) self.lineEdit_description.setText(description) - self.lineEdit_address.setText(address) + if not isinstance(address, type_defs.PointerType): + self.lineEdit_address.setText(address) + self.widget_Pointer.hide() + else: + self.lineEdit_address.setEnabled(False) + self.lineEdit_PtrStartAddress.setText(address.get_hex_address()) + self.checkBox_IsPointer.setChecked(True) + self.widget_Pointer.show() if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.label_length.show() self.lineEdit_length.show() @@ -1521,6 +1543,8 @@ def __init__(self, parent=None, description="No Description", address="0x", self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.lineEdit_length.textChanged.connect(self.update_value_of_address) self.checkBox_zeroterminate.stateChanged.connect(self.update_value_of_address) + self.checkBox_IsPointer.stateChanged.connect(self.comboBox_ValueType_current_index_changed) + self.lineEdit_PtrStartAddress.textChanged.connect(self.update_value_of_address) self.lineEdit_address.textChanged.connect(self.update_value_of_address) self.label_valueofaddress.contextMenuEvent = self.label_valueofaddress_context_menu_event self.update_value_of_address() @@ -1540,14 +1564,27 @@ def label_valueofaddress_context_menu_event(self, event): pass def update_value_of_address(self): - address = self.lineEdit_address.text() - try: - address = GDB_Engine.examine_expression(address).address - except type_defs.InferiorRunningException: - pass + if self.checkBox_IsPointer.isChecked(): + try: + ptr_base_address = int(self.lineEdit_PtrStartAddress.text(), 16) + except ValueError: # if text empty or 0x + ptr_base_address = 0 + address = GDB_Engine.read_pointer(type_defs.PointerType(ptr_base_address)) + if address != None: + address_text = hex(address) + else: + address_text = hex(0) + self.lineEdit_address.setText(address_text) + else: + address = self.lineEdit_address.text() + try: + address = GDB_Engine.examine_expression(address).address + except type_defs.InferiorRunningException: + pass if not address: self.label_valueofaddress.setText("??") return + address_type = self.comboBox_ValueType.currentIndex() if address_type == type_defs.VALUE_INDEX.INDEX_AOB: length = self.lineEdit_length.text() @@ -1573,6 +1610,14 @@ def comboBox_ValueType_current_index_changed(self): self.label_length.hide() self.lineEdit_length.hide() self.checkBox_zeroterminate.hide() + if self.checkBox_IsPointer.isChecked(): + self.lineEdit_address.setEnabled(False) + if self.lineEdit_PtrStartAddress.text() == "": + self.lineEdit_PtrStartAddress.setText(self.lineEdit_address.text()) + self.widget_Pointer.show() + else: + self.lineEdit_address.setEnabled(True) + self.widget_Pointer.hide() self.update_value_of_address() def reject(self): @@ -1603,6 +1648,12 @@ def get_values(self): if self.checkBox_zeroterminate.isChecked(): zero_terminate = True value_index = self.comboBox_ValueType.currentIndex() + if self.checkBox_IsPointer.isChecked(): + try: + ptr_base_address = int(self.lineEdit_PtrStartAddress.text(), 16) + except ValueError: + ptr_base_address = 0 + address = type_defs.PointerType(ptr_base_address) return description, address, value_index, length, zero_terminate diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 54032999..de7c908a 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -757,6 +757,36 @@ def inject_with_dlopen_call(library_path): return True +#:tag:MemoryRW +def read_pointer(pointer_type): + """Reads the address pointed by this pointer + + Args: + pointer_type (PointerType): type_defs.PointerType class containing a base_address and an offsets list + + Returns: + int: Final pointed address after dereferencing this pointer and it's offsets list + """ + if not isinstance(pointer_type, type_defs.PointerType): + raise TypeError("Passed non-PointerType to read_pointer!") + + if inferior_arch == type_defs.INFERIOR_ARCH.ARCH_32: + value_index = type_defs.VALUE_INDEX.INDEX_INT32 + else: + value_index = type_defs.VALUE_INDEX.INDEX_INT64 + + try: + with open(mem_file, "rb") as mem_handle: + deref_address = read_memory(pointer_type.base_address, value_index, mem_handle=mem_handle) + for offset in pointer_type.offsets_list: + offset_address = deref_address + offset + deref_address = read_memory(offset_address, value_index, mem_handle=mem_handle) + except OSError: + deref_address = pointer_type.base_address + + return deref_address + + #:tag:MemoryRW def read_memory(address, value_index, length=None, zero_terminate=True, signed=False, mem_handle=None): """Reads value from the given address diff --git a/libpince/type_defs.py b/libpince/type_defs.py index c6748477..746306d3 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -463,6 +463,27 @@ def text(self): return returned_string +class PointerType: + def __init__(self, base_address, offsets_list=None): + """ + Args: + base_address (int): The base address of where this pointer starts from. + offsets_list (list): List of offsets to reach the final pointed data. Can be None for single-level pointer. + """ + self.base_address = base_address + if offsets_list == None: + self.offsets_list = [] + + def serialize(self): + return self.base_address, self.offsets_list + + def get_hex_address(self): + """ + Returns the text hex representation of this pointer's base address + """ + return hex(self.base_address) + + class RegisterQueue: def __init__(self): self.queue_list = [] From 5ebd7ebd843491cb7ac1a8df2d291168c45af96d Mon Sep 17 00:00:00 2001 From: Berk Ozler Date: Mon, 18 Jul 2022 10:28:36 +0300 Subject: [PATCH 038/487] Add PointerType serialization --- PINCE.py | 13 +++++++++++-- libpince/type_defs.py | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index bea5ee21..ec6b96da 100755 --- a/PINCE.py +++ b/PINCE.py @@ -785,8 +785,12 @@ def insert_records(self, records, parent_row, insert_index): row.setData(FROZEN_COL, Qt.UserRole, frozen) # Deserialize the value_type param + if type(rec[1]) == list: + address_expr = type_defs.PointerType(*rec[1]) + else: + address_expr = rec[1] value_type = type_defs.ValueType(*rec[2]) - self.change_address_table_entries(row, *rec[:-2], value_type) + self.change_address_table_entries(row, rec[0], address_expr, value_type) self.insert_records(rec[-1], row, 0) rows.append(row) @@ -1409,10 +1413,15 @@ def change_address_table_entries(self, row, description="No Description", addres # Returns the column values of the given row def read_address_table_entries(self, row, serialize=False): description = row.text(DESC_COL) - address_expr = row.data(ADDR_COL, Qt.UserRole) if serialize: + address_data = row.data(ADDR_COL, Qt.UserRole) + if isinstance(address_data, type_defs.PointerType): + address_expr = address_data.serialize() + else: + address_expr = address_data value_type = row.data(TYPE_COL, Qt.UserRole).serialize() else: + address_expr = row.data(ADDR_COL, Qt.UserRole) value_type = row.data(TYPE_COL, Qt.UserRole) return description, address_expr, value_type diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 746306d3..0a267695 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -473,6 +473,8 @@ def __init__(self, base_address, offsets_list=None): self.base_address = base_address if offsets_list == None: self.offsets_list = [] + else: + self.offsets_list = offsets_list def serialize(self): return self.base_address, self.offsets_list From db43a9b0f76b382ac0a451bd3b580ec306868e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 19 Jul 2022 23:32:50 +0300 Subject: [PATCH 039/487] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 520af98e..2dd32e8a 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ If you like to uninstall PINCE, just delete this folder, almost everything is in ***Notes:*** - GDB enhancements (peda, pwndbg, etc) that use a global gdbinit file might cause PINCE to misfunction at times. Please disable them or use them locally before starting PINCE - If you are having problems with your default gdb version, you can use the `install_gdb.sh` script to install another version locally. Read the comments in it for more information -- Check #116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` +- Check https://github.com/korcankaraokcu/PINCE/issues/116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` # Running PINCE Just run ```sh PINCE.sh``` in the PINCE directory From 7adc9cba04ed36933293217ec54a2889244dd694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 20 Jul 2022 15:14:25 +0300 Subject: [PATCH 040/487] Add indicator for freeze_type --- GUI/MainWindow.py | 1 + GUI/MainWindow.ui | 3 +++ PINCE.py | 11 +++++++++++ 3 files changed, 15 insertions(+) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 4d4c55fb..dfe4a8ca 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -23,6 +23,7 @@ def setupUi(self, MainWindow): self.treeWidget_AddressTable.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop) self.treeWidget_AddressTable.setDefaultDropAction(QtCore.Qt.MoveAction) self.treeWidget_AddressTable.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.treeWidget_AddressTable.setIndentation(12) self.treeWidget_AddressTable.setExpandsOnDoubleClick(False) self.treeWidget_AddressTable.setObjectName("treeWidget_AddressTable") self.gridLayout.addWidget(self.treeWidget_AddressTable, 3, 0, 1, 1) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index edd5cb88..a14d5166 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -29,6 +29,9 @@ QAbstractItemView::ExtendedSelection + + 12 + false diff --git a/PINCE.py b/PINCE.py index a1ba8c97..843a7b1d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -715,6 +715,15 @@ def change_freeze_type(self, freeze_type): frozen = row.data(FROZEN_COL, Qt.UserRole) frozen.freeze_type = freeze_type + # TODO: Create a QWidget subclass with signals so freeze type can be changed by clicking on the cell + # This also helps it to accept rich text, colors for arrows would be nice + if freeze_type == type_defs.FREEZE_TYPE.DEFAULT: + row.setText(FROZEN_COL, "") + elif freeze_type == type_defs.FREEZE_TYPE.INCREMENT: + row.setText(FROZEN_COL, "▲") + elif freeze_type == type_defs.FREEZE_TYPE.DECREMENT: + row.setText(FROZEN_COL, "▼") + def toggle_selected_records(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if row: @@ -1299,6 +1308,8 @@ def treeWidget_AddressTable_item_clicked(self, row, column): if row.checkState(FROZEN_COL) == Qt.Checked: frozen = row.data(FROZEN_COL, Qt.UserRole) frozen.value = row.text(VALUE_COL) + else: + row.setText(FROZEN_COL, "") def treeWidget_AddressTable_change_repr(self, new_repr): value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.UserRole) From b9f0b003bf84d1a1dcbca93388ffe194815796ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 21 Jul 2022 13:03:43 +0300 Subject: [PATCH 041/487] Remove read_memory_multiple --- PINCE.py | 31 +++++++----------- README.md | 2 -- libpince/GDB_Engine.py | 74 ++++++++++-------------------------------- 3 files changed, 28 insertions(+), 79 deletions(-) diff --git a/PINCE.py b/PINCE.py index 843a7b1d..072d3f05 100755 --- a/PINCE.py +++ b/PINCE.py @@ -852,10 +852,8 @@ def update_address_table(self): if GDB_Engine.currentpid == -1 or self.treeWidget_AddressTable.topLevelItemCount() == 0: return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) - table_contents = [] + mem_handle = GDB_Engine.memory_handle() address_expr_list = [] - value_type_list = [] - value_repr_list = [] rows = [] while True: row = it.value() @@ -863,26 +861,21 @@ def update_address_table(self): break it += 1 address_expr_list.append(row.data(ADDR_COL, Qt.UserRole)) - value_type_list.append(row.data(TYPE_COL, Qt.UserRole)) rows.append(row) try: address_list = [item.address for item in GDB_Engine.examine_expressions(address_expr_list)] except type_defs.InferiorRunningException: address_list = address_expr_list - for address, value_type in zip(address_list, value_type_list): - signed = False - if value_type.value_repr == type_defs.VALUE_REPR.SIGNED: - signed = True - current_item = (address, value_type.value_index, value_type.length, value_type.zero_terminate, signed) - table_contents.append(current_item) - value_repr_list.append(value_type.value_repr) - new_table_contents = GDB_Engine.read_memory_multiple(table_contents) - for row, address, address_expr, value, value_repr in zip(rows, address_list, address_expr_list, - new_table_contents, value_repr_list): - row.setText(ADDR_COL, address or address_expr) + for index, row in enumerate(rows): + value_type = row.data(TYPE_COL, Qt.UserRole) + address = address_list[index] + signed = True if value_type.value_repr == type_defs.VALUE_REPR.SIGNED else False + value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, + value_type.zero_terminate, signed, mem_handle=mem_handle) + row.setText(ADDR_COL, address or address_expr_list[index]) if value is None: value = "" - elif value_repr == type_defs.VALUE_REPR.HEX: + elif value_type.value_repr == type_defs.VALUE_REPR.HEX: value = hex(value) else: value = str(value) @@ -3991,13 +3984,11 @@ def update_list(self): self.tableWidget_TrackInfo.selectRow(self.last_selected_row) def update_values(self): - param_list = [] + mem_handle = GDB_Engine.memory_handle() value_type = self.comboBox_ValueType.currentIndex() for row in range(self.tableWidget_TrackInfo.rowCount()): address = self.tableWidget_TrackInfo.item(row, TRACK_BREAKPOINT_ADDR_COL).text() - param_list.append((address, value_type, 10)) - value_list = GDB_Engine.read_memory_multiple(param_list) - for row, value in enumerate(value_list): + value = GDB_Engine.read_memory(address, value_type, 10, mem_handle=mem_handle) value = "" if value is None else str(value) self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_VALUE_COL, QTableWidgetItem(value)) GuiUtils.resize_to_contents(self.tableWidget_TrackInfo) diff --git a/README.md b/README.md index 2dd32e8a..591a024e 100644 --- a/README.md +++ b/README.md @@ -95,12 +95,10 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run # Current Roadmap - Refactor file naming conventions(decide on snake_case or camelCase for modules etc) - Create ```CONTRIBUTING.md``` and combine all non-tutorial notes within it -- Consider replacing read_memory_multiple function with mem_handle&read_memory functions, this fixes the "read_memory_multiple follows a bad design pattern" step - Refactorize memory write/read functions - - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. Only update the visible rows to prevent this(check ```disassemble_check_viewport``` for an example) - - Implement same system for the TrackBreakpointWidgetForm if necessary. Do performance tests - - Consider using a class instead of primitive return types to store the raw bytes. This class should also include a method to display None type as red '??' text for Qt -- - read_memory_multiple follows a bad design pattern, use named tuples or something like that - - Provide an option to cut BOM bytes when writing to memory with the types UTF-16 and UTF-32 - - Put a warning for users about replacement bytes for non UTF-8 types - - Extend string types with LE and BE variants of UTF-16 and UTF-32 diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 54032999..740605d3 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -757,6 +757,17 @@ def inject_with_dlopen_call(library_path): return True +#:tag:MemoryRW +def memory_handle(): + """ + Acquire the handle of the currently attached process + + Returns: + BinaryIO: A file handle that points to the memory file of the current process + """ + return open(mem_file, "rb") + + #:tag:MemoryRW def read_memory(address, value_index, length=None, zero_terminate=True, signed=False, mem_handle=None): """Reads value from the given address @@ -770,7 +781,7 @@ def read_memory(address, value_index, length=None, zero_terminate=True, signed=F value_index is INDEX_STRING. Ignored otherwise signed (bool): Casts the data as signed if True, unsigned if False. Only usable with integer types mem_handle (BinaryIO): A file handle that points to the memory file of the current process - This parameter is used for optimization, intended for internal usage. Check read_memory_multiple for an example + This parameter is used for optimization, See memory_handle Don't forget to close the handle after you're done if you use this parameter manually Returns: @@ -842,53 +853,6 @@ def read_memory(address, value_index, length=None, zero_terminate=True, signed=F return struct.unpack_from(data_type, data_read)[0] -#:tag:MemoryRW -def read_memory_multiple(nested_list): - """Reads multiple values from the given addresses - - Optimized version of the function read_memory. This function is significantly faster after 100 addresses compared - to using read_memory in a for loop. - - Args: - nested_list (list): List of *args of the function read_memory. You don't have to pass all of the parameters for - each list in the nested_list, only parameters address and value_index are obligatory. Defaults of the other - parameters are the same with the function read_memory. - - Examples: - All parameters are passed-->[[address1, value_index1, length1, zero_terminate1, signed], ...] - Parameters are partially passed--▼ - [[address1, value_index1],[address2, value_index2, length2],[address3, value_index3, length3], ...] - - Returns: - list: A list of the values read. - If any errors occurs while reading addresses, it's ignored and the belonging address is returned as None - For instance; If 4 addresses has been read and 3rd one is problematic, the returned list will be - [returned_value1,returned_value2,None,returned_value4] - """ - data_read_list = [] - mem_handle = open(mem_file, "rb") - - for item in nested_list: - address = item[0] - index = item[1] - try: - length = item[2] - except IndexError: - length = 0 - try: - zero_terminate = item[3] - except IndexError: - zero_terminate = True - try: - signed = item[4] - except IndexError: - signed = False - data_read = read_memory(address, index, length, zero_terminate, signed, mem_handle) - data_read_list.append(data_read) - mem_handle.close() - return data_read_list - - #:tag:MemoryRW def write_memory(address, value_index, value): """Sets the given value to the given address @@ -2051,14 +2015,10 @@ def search_referenced_strings(searched_str, value_index=type_defs.VALUE_INDEX.IN print("An exception occurred while trying to compile the given regex\n", str(e)) return str_dict = get_dissect_code_data(True, False, False)[0] - nested_list = [] - referenced_list = [] + mem_handle = memory_handle() returned_list = [] - for item in str_dict: - nested_list.append((int(item, 16), value_index, 100)) - referenced_list.append(item) - value_list = read_memory_multiple(nested_list) - for index, value in enumerate(value_list): + for address, refs in str_dict.items(): + value = read_memory(int(address, 16), value_index, 100, mem_handle=mem_handle) value_str = "" if value is None else str(value) if not value_str: continue @@ -2072,9 +2032,9 @@ def search_referenced_strings(searched_str, value_index=type_defs.VALUE_INDEX.IN else: if value_str.lower().find(searched_str.lower()) == -1: continue - ref_addr = referenced_list[index] - returned_list.append((ref_addr, len(str_dict[ref_addr]), value)) + returned_list.append((address, len(refs), value)) str_dict.close() + mem_handle.close() return returned_list From 33ead45dabebb3c494d97e925fa68fed0c0086ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 21 Jul 2022 22:47:46 +0300 Subject: [PATCH 042/487] Implement update_search_table --- PINCE.py | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index 072d3f05..22c90655 100755 --- a/PINCE.py +++ b/PINCE.py @@ -395,9 +395,11 @@ def __init__(self): self.check_status_thread.process_running.connect(self.memory_view_window.process_running) self.check_status_thread.start() self.update_address_table_thread = Worker(self.update_address_table_loop) + self.update_search_table_thread = Worker(self.update_search_table_loop) self.freeze_thread = Worker(self.freeze_loop) global threadpool threadpool.start(self.update_address_table_thread) + threadpool.start(self.update_search_table_thread) threadpool.start(self.freeze_thread) self.shortcut_open_file = QShortcut(QKeySequence("Ctrl+O"), self) self.shortcut_open_file.activated.connect(self.pushButton_Open_clicked) @@ -1052,8 +1054,12 @@ def pushButton_NextScan_clicked(self): n = int(n) address = "0x" + address current_item = QTableWidgetItem(address) - value_index = type_defs.scanmem_result_to_index_dict[result_type.split(" ")[0]] - current_item.setData(Qt.UserRole, value_index) + result = result_type.split(" ")[0] + value_index = type_defs.scanmem_result_to_index_dict[result] + signed = False + if type_defs.VALUE_INDEX.is_integer(value_index) and result.endswith("s"): + signed = True + current_item.setData(Qt.UserRole, (value_index, signed)) self.tableWidget_valuesearchtable.insertRow(self.tableWidget_valuesearchtable.rowCount()) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_ADDRESS_COL, current_item) if current_type == type_defs.SCAN_INDEX.INDEX_STRING: @@ -1074,7 +1080,7 @@ def _scan_to_length(self, type_index): def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) - self.add_entry_to_addresstable("", current_item.text(), current_item.data(Qt.UserRole), length) + self.add_entry_to_addresstable("", current_item.text(), current_item.data(Qt.UserRole)[0], length) def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.UserRole) @@ -1192,7 +1198,7 @@ def copy_to_address_table(self): for row in self.tableWidget_valuesearchtable.selectedItems(): i = i + 1 if i % 3 == 0: - self.add_entry_to_addresstable("", row.text(), row.data(Qt.UserRole), length) + self.add_entry_to_addresstable("", row.text(), row.data(Qt.UserRole)[0], length) def on_inferior_exit(self): if GDB_Engine.currentpid == -1: @@ -1264,7 +1270,15 @@ def update_address_table_loop(self): try: self.update_address_table() except: - print("Update Table failed :(") + print("Update Address Table failed :(") + + def update_search_table_loop(self): + while Exiting == 0: + sleep(0.5) + try: + self.update_search_table() + except: + print("Update Search Table failed :(") def freeze_loop(self): while Exiting == 0: @@ -1274,6 +1288,25 @@ def freeze_loop(self): except: print("Freeze failed :(") + # ---------------------------------------------------- + + def update_search_table(self): + row_count = self.tableWidget_valuesearchtable.rowCount() + if row_count > 0: + length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) + mem_handle = GDB_Engine.memory_handle() + for row_index in range(row_count): + address_item = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_ADDRESS_COL) + previous_text = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_PREVIOUS_COL).text() + value_index, signed = address_item.data(Qt.UserRole) + address = address_item.text() + new_value = str(GDB_Engine.read_memory(address, value_index, length, signed=signed, + mem_handle=mem_handle)) + value_item = QTableWidgetItem(new_value) + if new_value != previous_text: + value_item.setForeground(QBrush(QColor(255, 0, 0))) + self.tableWidget_valuesearchtable.setItem(row_index, SEARCH_TABLE_VALUE_COL, value_item) + def freeze(self): it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) while it.value(): @@ -1294,8 +1327,6 @@ def freeze(self): GDB_Engine.write_memory(address, value_index, value) it += 1 - # ---------------------------------------------------- - def treeWidget_AddressTable_item_clicked(self, row, column): if column == FROZEN_COL: if row.checkState(FROZEN_COL) == Qt.Checked: From 96946868ed384a70e5c60f6e143795056732f32d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 22 Jul 2022 13:27:52 +0300 Subject: [PATCH 043/487] Add color to freeze_type --- PINCE.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PINCE.py b/PINCE.py index 22c90655..07f4862d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -721,10 +721,13 @@ def change_freeze_type(self, freeze_type): # This also helps it to accept rich text, colors for arrows would be nice if freeze_type == type_defs.FREEZE_TYPE.DEFAULT: row.setText(FROZEN_COL, "") + row.setForeground(FROZEN_COL, QBrush(QColor(0, 0, 0))) elif freeze_type == type_defs.FREEZE_TYPE.INCREMENT: row.setText(FROZEN_COL, "▲") + row.setForeground(FROZEN_COL, QBrush(QColor(0, 255, 0))) elif freeze_type == type_defs.FREEZE_TYPE.DECREMENT: row.setText(FROZEN_COL, "▼") + row.setForeground(FROZEN_COL, QBrush(QColor(255, 0, 0))) def toggle_selected_records(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) @@ -1334,6 +1337,7 @@ def treeWidget_AddressTable_item_clicked(self, row, column): frozen.value = row.text(VALUE_COL) else: row.setText(FROZEN_COL, "") + row.setForeground(FROZEN_COL, QBrush(QColor(0, 0, 0))) def treeWidget_AddressTable_change_repr(self, new_repr): value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.UserRole) From 7a48537053976bd97d760d09acc0df60d8dd0f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 22 Jul 2022 13:34:51 +0300 Subject: [PATCH 044/487] Remove redundant comment --- PINCE.py | 1 - 1 file changed, 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 07f4862d..25e8122e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -718,7 +718,6 @@ def change_freeze_type(self, freeze_type): frozen.freeze_type = freeze_type # TODO: Create a QWidget subclass with signals so freeze type can be changed by clicking on the cell - # This also helps it to accept rich text, colors for arrows would be nice if freeze_type == type_defs.FREEZE_TYPE.DEFAULT: row.setText(FROZEN_COL, "") row.setForeground(FROZEN_COL, QBrush(QColor(0, 0, 0))) From 7de1e08e01a147f133c11baf032ae8b814cbd53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 22 Jul 2022 14:10:41 +0300 Subject: [PATCH 045/487] Fix search table results --- PINCE.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index 25e8122e..98bd19dd 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1051,8 +1051,8 @@ def pushButton_NextScan_clicked(self): self.tableWidget_valuesearchtable.setRowCount(0) current_type = self.comboBox_ValueType.currentData(Qt.UserRole) length = self._scan_to_length(current_type) - - for n, address, offset, region_type, value, result_type in matches: + mem_handle = GDB_Engine.memory_handle() + for n, address, offset, region_type, val, result_type in matches: n = int(n) address = "0x" + address current_item = QTableWidgetItem(address) @@ -1062,10 +1062,9 @@ def pushButton_NextScan_clicked(self): if type_defs.VALUE_INDEX.is_integer(value_index) and result.endswith("s"): signed = True current_item.setData(Qt.UserRole, (value_index, signed)) + value = str(GDB_Engine.read_memory(address, value_index, length, signed=signed, mem_handle=mem_handle)) self.tableWidget_valuesearchtable.insertRow(self.tableWidget_valuesearchtable.rowCount()) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_ADDRESS_COL, current_item) - if current_type == type_defs.SCAN_INDEX.INDEX_STRING: - value = GDB_Engine.read_memory(address, type_defs.VALUE_INDEX.INDEX_STRING_UTF8, length) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_VALUE_COL, QTableWidgetItem(value)) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_PREVIOUS_COL, QTableWidgetItem(value)) if n == 10000: From 3ce95404f543c0b4c2e8d869e66d3cc878fc6ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 23 Jul 2022 16:24:36 +0300 Subject: [PATCH 046/487] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 591a024e..64a48cbc 100644 --- a/README.md +++ b/README.md @@ -157,11 +157,9 @@ Gibus # Supported platforms - Ubuntu and its flavors, actively tested on Kubuntu -- Debian -- Kali Linux -- Parrot OS -- Linux Mint (install the package "python3-psutil" if you encounter ImportError or NameError, thanks Gibus) +- Debian and Debian-based (Kali, Mint etc.) - Archlinux(tag [cagriulas](https://github.com/cagriulas) or [TsarFox](https://github.com/TsarFox) when creating an issue) +- SUSE # Trusted Sources * [Official github page](https://github.com/korcankaraokcu/PINCE) From c866038e2bffe9d4bf8b14772a8caf1f0efe09da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 24 Jul 2022 23:10:17 +0300 Subject: [PATCH 047/487] Install scanmem in current directory --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index c24b9e70..d6a02e17 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -26,7 +26,7 @@ CURRENT_USER="$(who mom likes | awk '{print $1}')" # assumes you're in scanmem directory compile_scanmem() { sh autogen.sh - ./configure --prefix=/usr + ./configure --prefix="$(pwd)" make -j $(grep -m 1 "cpu cores" /proc/cpuinfo | cut -d: -f 2 | xargs) libscanmem.la chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file } From 90258c401528c9404bb0709e2e42c0d6a7422a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 26 Jul 2022 21:44:01 +0300 Subject: [PATCH 048/487] Implement requested changes by owner for PR. Also change read_pointer offset behaviour to emulate CE behaviour closer --- GUI/AddAddressManuallyDialog.py | 2 +- GUI/AddAddressManuallyDialog.ui | 2 +- PINCE.py | 20 +++++++------------- libpince/GDB_Engine.py | 24 +++++++++++++++++++----- libpince/type_defs.py | 11 ++++++----- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index bf6f9930..99eb9bc9 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -150,7 +150,7 @@ def setupUi(self, Dialog): self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem4 = QtWidgets.QSpacerItem(20, 120, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem4, 8, 0, 1, 1) self.retranslateUi(Dialog) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index bab57f75..b85be691 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -313,7 +313,7 @@ 20 - 40 + 120 diff --git a/PINCE.py b/PINCE.py index 86d573ee..5ead4738 100755 --- a/PINCE.py +++ b/PINCE.py @@ -871,6 +871,8 @@ def update_address_table(self): address_data = row.data(ADDR_COL, Qt.UserRole) if isinstance(address_data, type_defs.PointerType): pointer_address = GDB_Engine.read_pointer(address_data) + if pointer_address == None: + continue address_expr_list.append(hex(pointer_address)) else: address_expr_list.append(address_data) @@ -1429,7 +1431,7 @@ def treeWidget_AddressTable_edit_type(self): def change_address_table_entries(self, row, description="No Description", address_expr="", value_type=None): if isinstance(address_expr, type_defs.PointerType): address = GDB_Engine.read_pointer(address_expr) - address_text = f'P->{hex(address)}' + address_text = f'P->{hex(address)}' if address != None else address_expr.get_base_address() else: try: address = GDB_Engine.examine_expression(address_expr).address @@ -1562,7 +1564,7 @@ def __init__(self, parent=None, description="No Description", address="0x", self.widget_Pointer.hide() else: self.lineEdit_address.setEnabled(False) - self.lineEdit_PtrStartAddress.setText(address.get_hex_address()) + self.lineEdit_PtrStartAddress.setText(address.get_base_address()) self.checkBox_IsPointer.setChecked(True) self.widget_Pointer.show() if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): @@ -1613,15 +1615,11 @@ def label_valueofaddress_context_menu_event(self, event): def update_value_of_address(self): if self.checkBox_IsPointer.isChecked(): - try: - ptr_base_address = int(self.lineEdit_PtrStartAddress.text(), 16) - except ValueError: # if text empty or 0x - ptr_base_address = 0 - address = GDB_Engine.read_pointer(type_defs.PointerType(ptr_base_address)) + address = GDB_Engine.read_pointer(type_defs.PointerType(self.lineEdit_PtrStartAddress.text())) if address != None: address_text = hex(address) else: - address_text = hex(0) + address_text = "??" self.lineEdit_address.setText(address_text) else: address = self.lineEdit_address.text() @@ -1697,11 +1695,7 @@ def get_values(self): zero_terminate = True value_index = self.comboBox_ValueType.currentIndex() if self.checkBox_IsPointer.isChecked(): - try: - ptr_base_address = int(self.lineEdit_PtrStartAddress.text(), 16) - except ValueError: - ptr_base_address = 0 - address = type_defs.PointerType(ptr_base_address) + address = type_defs.PointerType(self.lineEdit_PtrStartAddress.text()) return description, address, value_index, length, zero_terminate diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 6c6c13ea..00250f9f 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -776,15 +776,29 @@ def read_pointer(pointer_type): value_index = type_defs.VALUE_INDEX.INDEX_INT64 try: - with open(mem_file, "rb") as mem_handle: - deref_address = read_memory(pointer_type.base_address, value_index, mem_handle=mem_handle) + start_address = examine_expression(pointer_type.base_address).address + except type_defs.InferiorRunningException: + if type(pointer_type.base_address) == str: + try: + start_address = int(pointer_type.base_address, 16) + except ValueError: + start_address = 0 + else: + start_address = pointer_type.base_address + + try: + with memory_handle() as mem_handle: + final_address = deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) for offset in pointer_type.offsets_list: offset_address = deref_address + offset - deref_address = read_memory(offset_address, value_index, mem_handle=mem_handle) + if offset != pointer_type.offsets_list[-1]: # CE derefs every offset except for the last one + deref_address = read_memory(offset_address, value_index, mem_handle=mem_handle) + else: + final_address = offset_address except OSError: - deref_address = pointer_type.base_address + final_address = start_address - return deref_address + return final_address def memory_handle(): diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 0a267695..87c72a37 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -467,8 +467,9 @@ class PointerType: def __init__(self, base_address, offsets_list=None): """ Args: - base_address (int): The base address of where this pointer starts from. - offsets_list (list): List of offsets to reach the final pointed data. Can be None for single-level pointer. + base_address (str, int): The base address of where this pointer starts from. Can be str expression or int. + offsets_list (list): List of offsets to reach the final pointed data. Can be None for no offsets. + Last offset in list won't be dereferenced to emulate CE behaviour. """ self.base_address = base_address if offsets_list == None: @@ -479,11 +480,11 @@ def __init__(self, base_address, offsets_list=None): def serialize(self): return self.base_address, self.offsets_list - def get_hex_address(self): + def get_base_address(self): """ - Returns the text hex representation of this pointer's base address + Returns the text representation of this pointer's base address """ - return hex(self.base_address) + return hex(self.base_address) if type(self.base_address) != str else self.base_address class RegisterQueue: From b1730f49b99bd55460e530c943f0ab2b9785ccb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Wed, 27 Jul 2022 21:39:03 +0300 Subject: [PATCH 049/487] Fix GUI margin issues --- GUI/AddAddressManuallyDialog.py | 11 ++++------- GUI/AddAddressManuallyDialog.ui | 25 +++++++++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 99eb9bc9..9c980a86 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -14,26 +14,23 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(224, 360) + Dialog.resize(224, 348) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) Dialog.setSizePolicy(sizePolicy) Dialog.setMinimumSize(QtCore.QSize(0, 0)) - Dialog.setMaximumSize(QtCore.QSize(224, 360)) + Dialog.setMaximumSize(QtCore.QSize(224, 348)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.widget_Pointer = QtWidgets.QWidget(Dialog) self.widget_Pointer.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.widget_Pointer.sizePolicy().hasHeightForWidth()) - self.widget_Pointer.setSizePolicy(sizePolicy) self.widget_Pointer.setMinimumSize(QtCore.QSize(0, 0)) self.widget_Pointer.setObjectName("widget_Pointer") self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.widget_Pointer) + self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_4.setSpacing(0) self.verticalLayout_4.setObjectName("verticalLayout_4") self.verticalLayout_Pointers = QtWidgets.QVBoxLayout() self.verticalLayout_Pointers.setObjectName("verticalLayout_Pointers") diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index b85be691..24d74098 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -7,7 +7,7 @@ 0 0 224 - 360 + 348 @@ -25,7 +25,7 @@ 224 - 360 + 348 @@ -37,12 +37,6 @@ true - - - 0 - 0 - - 0 @@ -50,6 +44,21 @@ + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + From 8042c04ad8a9d08aaf275754d6ec3aa9b2847525 Mon Sep 17 00:00:00 2001 From: ForwardFeed Date: Tue, 26 Jul 2022 21:52:38 +0200 Subject: [PATCH 050/487] changed hotkeys to be global and added a new pip dependency 'keyboard' to achieve this --- PINCE.py | 23 ++++++++--------------- install_pince.sh | 2 +- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/PINCE.py b/PINCE.py index 98bd19dd..b2c7ed9b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -70,6 +70,8 @@ from GUI.CustomAbstractTableModels.AsciiModel import QAsciiModel from GUI.CustomValidators.HexValidator import QHexValidator +from keyboard import add_hotkey + instances = [] # Holds temporary instances that will be deleted later on # settings @@ -328,18 +330,11 @@ class MainForm(QMainWindow, MainWindow): def __init__(self): super().__init__() self.setupUi(self) - self.hotkey_to_shortcut = {} # Dict[str:QShortcut]-->Dict[Hotkey.name:QShortcut(QKeySequence(Hotkey.value)] - hotkey_to_func = { - Hotkeys.pause_hotkey: self.pause_hotkey_pressed, - Hotkeys.break_hotkey: self.break_hotkey_pressed, - Hotkeys.continue_hotkey: self.continue_hotkey_pressed, - Hotkeys.toggle_attach_hotkey: self.toggle_attach_hotkey_pressed - } - for hotkey, func in hotkey_to_func.items(): - current_shortcut = QShortcut(QKeySequence(hotkey.value), self) - current_shortcut.activated.connect(func) - current_shortcut.setContext(hotkey.context) - self.hotkey_to_shortcut[hotkey.name] = current_shortcut + #setting up the Global hotkeys + add_hotkey(Hotkeys.pause_hotkey.default, self.pause_hotkey_pressed) + add_hotkey(Hotkeys.break_hotkey.default, self.break_hotkey_pressed) + add_hotkey(Hotkeys.continue_hotkey.default, self.continue_hotkey_pressed) + add_hotkey(Hotkeys.toggle_attach_hotkey.default, self.toggle_attach_hotkey_pressed) GuiUtils.center(self) self.treeWidget_AddressTable.setColumnWidth(FROZEN_COL, 50) self.treeWidget_AddressTable.setColumnWidth(DESC_COL, 150) @@ -527,9 +522,7 @@ def apply_settings(self): app.setWindowIcon(QIcon(os.path.join(SysUtils.get_logo_directory(), logo_path))) auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) GDB_Engine.set_gdb_output_mode(gdb_output_mode) - for hotkey in Hotkeys.get_hotkeys(): - hotkey.value = self.settings.value("Hotkeys/" + hotkey.name) - self.hotkey_to_shortcut[hotkey.name].setKey(QKeySequence(hotkey.value)) + try: self.memory_view_window.set_dynamic_debug_hotkeys() except AttributeError: diff --git a/install_pince.sh b/install_pince.sh index d6a02e17..b1bf308d 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -69,7 +69,7 @@ PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-pyqt5 libtool libreadline-dev intltool" PKG_NAMES_SUSE="$PKG_NAMES_ALL python3-qt5" PKG_NAMES_ARCH="python-pip python-pyqt5 readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES="$PKG_NAMES_DEBIAN" -PKG_NAMES_PIP="psutil pexpect distorm3 pygdbmi" +PKG_NAMES_PIP="psutil pexpect distorm3 pygdbmi keyboard" PIP_COMMAND="pip3" LSB_RELEASE="$(command -v lsb_release)" From 85178c4482ee53a8ab70e7f149f3b83d98a84fcb Mon Sep 17 00:00:00 2001 From: ForwardFeed <76596109+ForwardFeed@users.noreply.github.com> Date: Sat, 30 Jul 2022 04:52:33 +0200 Subject: [PATCH 051/487] this time the global keybind can setup with settings --- PINCE.py | 65 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/PINCE.py b/PINCE.py index b2c7ed9b..4927a531 100755 --- a/PINCE.py +++ b/PINCE.py @@ -70,7 +70,7 @@ from GUI.CustomAbstractTableModels.AsciiModel import QAsciiModel from GUI.CustomValidators.HexValidator import QHexValidator -from keyboard import add_hotkey +from keyboard import add_hotkey, remove_hotkey instances = [] # Holds temporary instances that will be deleted later on @@ -89,12 +89,36 @@ class Hotkeys: class Hotkey: - def __init__(self, name="", desc="", default="", value="", context=Qt.ApplicationShortcut): - self.name = name - self.desc = desc - self.default = default - self.value = value - self.context = context + def __init__(self, name="", desc="", default="", func=None, custom="", handle=None): + self.name = name + self.desc = desc + self.default = default + self.func = func + self.custom = custom + if default == "" or func is None: + self.handle = handle + else: + self.handle = add_hotkey(default, func) + + def change_key(self, custom): + print(self.func) + if self.handle is not None: + remove_hotkey(self.handle) + self.handle = add_hotkey(custom.lower(), self.func) + + def change_func(self, func): + self.func = func + if self.handle is not None: + remove_hotkey(self.handle) + if self.custom != "": + self.handle = add_hotkey(self.custom, func) + else: + self.handle = add_hotkey(self.default, func) + + def get_active_key(self): + if self.custom == "": + return self.default + return self.custom pause_hotkey = Hotkey("pause_hotkey", "Pause the process", "F1") break_hotkey = Hotkey("break_hotkey", "Break the process", "F2") @@ -256,7 +280,7 @@ def except_hook(exception_type, value, tb): QMessageBox.information(focused_widget, "Error", "GDB isn't initialized yet") elif exception_type == type_defs.InferiorRunningException: error_dialog = InputDialogForm(item_list=[( - "Process is running" + "\nPress " + Hotkeys.break_hotkey.value + " to stop process" + + "Process is running" + "\nPress " + Hotkeys.break_hotkey.get_active_key() + " to stop process" + "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.Ok]) error_dialog.exec_() traceback.print_exception(exception_type, value, tb) @@ -330,11 +354,15 @@ class MainForm(QMainWindow, MainWindow): def __init__(self): super().__init__() self.setupUi(self) - #setting up the Global hotkeys - add_hotkey(Hotkeys.pause_hotkey.default, self.pause_hotkey_pressed) - add_hotkey(Hotkeys.break_hotkey.default, self.break_hotkey_pressed) - add_hotkey(Hotkeys.continue_hotkey.default, self.continue_hotkey_pressed) - add_hotkey(Hotkeys.toggle_attach_hotkey.default, self.toggle_attach_hotkey_pressed) + self.hotkey_to_shortcut = {} + hotkey_to_func = { + Hotkeys.pause_hotkey: self.pause_hotkey_pressed, + Hotkeys.break_hotkey: self.break_hotkey_pressed, + Hotkeys.continue_hotkey: self.continue_hotkey_pressed, + Hotkeys.toggle_attach_hotkey: self.toggle_attach_hotkey_pressed + } + for hotkey, func in hotkey_to_func.items(): + hotkey.change_func(func) GuiUtils.center(self) self.treeWidget_AddressTable.setColumnWidth(FROZEN_COL, 50) self.treeWidget_AddressTable.setColumnWidth(DESC_COL, 150) @@ -522,7 +550,8 @@ def apply_settings(self): app.setWindowIcon(QIcon(os.path.join(SysUtils.get_logo_directory(), logo_path))) auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) GDB_Engine.set_gdb_output_mode(gdb_output_mode) - + for hotkey in Hotkeys.get_hotkeys(): + hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) try: self.memory_view_window.set_dynamic_debug_hotkeys() except AttributeError: @@ -2271,9 +2300,9 @@ class MemoryViewWindowForm(QMainWindow, MemoryViewWindow): process_running = pyqtSignal() def set_dynamic_debug_hotkeys(self): - self.actionBreak.setText("Break[" + Hotkeys.break_hotkey.value + "]") - self.actionRun.setText("Run[" + Hotkeys.continue_hotkey.value + "]") - self.actionToggle_Attach.setText("Toggle Attach[" + Hotkeys.toggle_attach_hotkey.value + "]") + self.actionBreak.setText("Break[" + Hotkeys.break_hotkey.get_active_key() + "]") + self.actionRun.setText("Run[" + Hotkeys.continue_hotkey.get_active_key() + "]") + self.actionToggle_Attach.setText("Toggle Attach[" + Hotkeys.toggle_attach_hotkey.get_active_key() + "]") def set_debug_menu_shortcuts(self): self.shortcut_step = QShortcut(QKeySequence("F7"), self) @@ -3971,7 +4000,7 @@ def __init__(self, address, instruction, parent=None): QMessageBox.information(self, "Error", "Unable to track breakpoint at expression " + address) return self.label_Info.setText("Pause the process to refresh 'Value' part of the table(" + - Hotkeys.pause_hotkey.value + " or " + Hotkeys.break_hotkey.value + ")") + Hotkeys.pause_hotkey.get_active_key() + " or " + Hotkeys.break_hotkey.get_active_key() + ")") self.address = address self.breakpoint = breakpoint self.info = {} From f1b58631c6ff4bf82b189b93cc68703c87737b9e Mon Sep 17 00:00:00 2001 From: ForwardFeed <76596109+ForwardFeed@users.noreply.github.com> Date: Fri, 5 Aug 2022 11:05:59 +0200 Subject: [PATCH 052/487] fixed a bug and removed a useless stdout debug --- PINCE.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 4927a531..efcf3e6c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -101,9 +101,11 @@ def __init__(self, name="", desc="", default="", func=None, custom="", handle=No self.handle = add_hotkey(default, func) def change_key(self, custom): - print(self.func) if self.handle is not None: remove_hotkey(self.handle) + self.handle = None + if custom == '': + return self.handle = add_hotkey(custom.lower(), self.func) def change_func(self, func): From 0e8663bf3b09b5df427f842ef3a37eb42f115309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 Aug 2022 19:44:00 +0300 Subject: [PATCH 053/487] Hotfix global hotkeys --- PINCE.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/PINCE.py b/PINCE.py index efcf3e6c..b438492c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -75,7 +75,7 @@ instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "master-21" # Increase version by one if you change settings. Format: branch_name-version +current_settings_version = "master-22" # Increase version by one if you change settings. Format: branch_name-version update_table = bool table_update_interval = int FreezeInterval = int @@ -90,24 +90,24 @@ class Hotkeys: class Hotkey: def __init__(self, name="", desc="", default="", func=None, custom="", handle=None): - self.name = name - self.desc = desc - self.default = default - self.func = func - self.custom = custom - if default == "" or func is None: - self.handle = handle - else: - self.handle = add_hotkey(default, func) + self.name = name + self.desc = desc + self.default = default + self.func = func + self.custom = custom + if default == "" or func is None: + self.handle = handle + else: + self.handle = add_hotkey(default, func) def change_key(self, custom): if self.handle is not None: remove_hotkey(self.handle) self.handle = None if custom == '': - return + return self.handle = add_hotkey(custom.lower(), self.func) - + def change_func(self, func): self.func = func if self.handle is not None: @@ -116,7 +116,7 @@ def change_func(self, func): self.handle = add_hotkey(self.custom, func) else: self.handle = add_hotkey(self.default, func) - + def get_active_key(self): if self.custom == "": return self.default @@ -356,7 +356,7 @@ class MainForm(QMainWindow, MainWindow): def __init__(self): super().__init__() self.setupUi(self) - self.hotkey_to_shortcut = {} + self.hotkey_to_shortcut = {} hotkey_to_func = { Hotkeys.pause_hotkey: self.pause_hotkey_pressed, Hotkeys.break_hotkey: self.break_hotkey_pressed, @@ -513,6 +513,7 @@ def set_default_settings(self): self.settings.endGroup() self.apply_settings() + @GDB_Engine.execute_with_temporary_interruption def apply_after_init(self): global gdb_logging global ignored_signals From 53ea9920f3efdb7dd9866f5aa4bf00666a8b32f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 Aug 2022 22:41:21 +0300 Subject: [PATCH 054/487] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 64a48cbc..8f3728e7 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,12 @@ Pre-release screenshots: * PINCE provides a trainer auto-generated from current address table on demand by using libpince and PyQT5 together # Installing -Clone this repo by running `git clone --recursive https://github.com/korcankaraokcu/PINCE` then run ```sudo sh install_pince.sh``` in the PINCE directory. For Archlinux, you can also use the [AUR package](https://aur.archlinux.org/packages/pince-git/) as an alternative. +``` +git clone --recursive https://github.com/korcankaraokcu/PINCE +cd PINCE +sudo sh install_pince.sh +``` +For Archlinux, you can also use the [AUR package](https://aur.archlinux.org/packages/pince-git/) as an alternative. If you like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them if you want. From 84c1a0207f6e1fb5f9751f5199f307973fb282b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 12 Aug 2022 01:07:48 +0300 Subject: [PATCH 055/487] Add offset support in GUI --- GUI/AddAddressManuallyDialog.py | 60 ++++++++++------- GUI/AddAddressManuallyDialog.ui | 116 ++++++++++++++++++-------------- PINCE.py | 69 +++++++++++++++++-- 3 files changed, 163 insertions(+), 82 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 9c980a86..5387c04b 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -14,14 +14,13 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(224, 348) + Dialog.resize(224, 390) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) Dialog.setSizePolicy(sizePolicy) Dialog.setMinimumSize(QtCore.QSize(0, 0)) - Dialog.setMaximumSize(QtCore.QSize(224, 348)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.widget_Pointer = QtWidgets.QWidget(Dialog) @@ -50,8 +49,33 @@ def setupUi(self, Dialog): spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_4.addItem(spacerItem) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) + self.horizontalLayout_5 = QtWidgets.QHBoxLayout() + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.addOffsetButton = QtWidgets.QPushButton(self.widget_Pointer) + self.addOffsetButton.setObjectName("addOffsetButton") + self.horizontalLayout_5.addWidget(self.addOffsetButton) + self.removeOffsetButton = QtWidgets.QPushButton(self.widget_Pointer) + self.removeOffsetButton.setObjectName("removeOffsetButton") + self.horizontalLayout_5.addWidget(self.removeOffsetButton) + self.verticalLayout_Pointers.addLayout(self.horizontalLayout_5) self.verticalLayout_4.addLayout(self.verticalLayout_Pointers) self.gridLayout.addWidget(self.widget_Pointer, 7, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) + self.buttonBox.setSizePolicy(sizePolicy) + self.buttonBox.setMaximumSize(QtCore.QSize(16777215, 35)) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) + self.checkBox_IsPointer = QtWidgets.QCheckBox(Dialog) + self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") + self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(20, 120, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem1, 8, 0, 1, 1) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") self.horizontalLayout_3 = QtWidgets.QHBoxLayout() @@ -59,8 +83,8 @@ def setupUi(self, Dialog): self.label_5 = QtWidgets.QLabel(Dialog) self.label_5.setObjectName("label_5") self.horizontalLayout_3.addWidget(self.label_5) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_3.addItem(spacerItem1) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem2) self.checkBox_zeroterminate = QtWidgets.QCheckBox(Dialog) self.checkBox_zeroterminate.setChecked(True) self.checkBox_zeroterminate.setObjectName("checkBox_zeroterminate") @@ -77,8 +101,8 @@ def setupUi(self, Dialog): self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout_2.addWidget(self.comboBox_ValueType) - spacerItem2 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_2.addItem(spacerItem2) + spacerItem3 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem3) self.label_length = QtWidgets.QLabel(Dialog) self.label_length.setObjectName("label_length") self.horizontalLayout_2.addWidget(self.label_length) @@ -119,13 +143,10 @@ def setupUi(self, Dialog): self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.label_valueofaddress.setObjectName("label_valueofaddress") self.horizontalLayout.addWidget(self.label_valueofaddress) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem3) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem4) self.verticalLayout_2.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) - self.checkBox_IsPointer = QtWidgets.QCheckBox(Dialog) - self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") - self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.label_4 = QtWidgets.QLabel(Dialog) @@ -136,19 +157,6 @@ def setupUi(self, Dialog): self.lineEdit_description.setObjectName("lineEdit_description") self.verticalLayout.addWidget(self.lineEdit_description) self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) - self.buttonBox.setSizePolicy(sizePolicy) - self.buttonBox.setMaximumSize(QtCore.QSize(16777215, 35)) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) - self.buttonBox.setObjectName("buttonBox") - self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) - spacerItem4 = QtWidgets.QSpacerItem(20, 120, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem4, 8, 0, 1, 1) self.retranslateUi(Dialog) self.comboBox_ValueType.setCurrentIndex(-1) @@ -160,11 +168,13 @@ def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Add Address Manually")) self.label_BaseAddress.setText(_translate("Dialog", "Base Address:")) + self.addOffsetButton.setText(_translate("Dialog", "Add Offset")) + self.removeOffsetButton.setText(_translate("Dialog", "Remove Offset")) + self.checkBox_IsPointer.setText(_translate("Dialog", "Pointer")) self.label_5.setText(_translate("Dialog", "Type:")) self.checkBox_zeroterminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_length.setText(_translate("Dialog", "Length")) self.lineEdit_length.setText(_translate("Dialog", "10")) self.label.setText(_translate("Dialog", "Address:")) self.label_2.setText(_translate("Dialog", "=")) - self.checkBox_IsPointer.setText(_translate("Dialog", "Pointer")) self.label_4.setText(_translate("Dialog", "Description:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 24d74098..20038d1c 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -7,7 +7,7 @@ 0 0 224 - 348 + 390 @@ -22,12 +22,6 @@ 0 - - - 224 - 348 - - Add Address Manually @@ -95,11 +89,74 @@ + + + + + + Add Offset + + + + + + + Remove Offset + + + + + + + + + + 0 + 0 + + + + + 16777215 + 35 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Pointer + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 120 + + + + @@ -264,13 +321,6 @@ - - - - Pointer - - - @@ -289,44 +339,6 @@ - - - - - 0 - 0 - - - - - 16777215 - 35 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 120 - - - - diff --git a/PINCE.py b/PINCE.py index 3a49ebd6..c872c937 100755 --- a/PINCE.py +++ b/PINCE.py @@ -22,9 +22,10 @@ QKeyEvent, QRegExpValidator from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, \ QShortcut, QKeySequenceEdit, QTabWidget, QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, \ - QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout + QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, \ + QPushButton, QFrame from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, \ - QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegExp, QRunnable, QThreadPool, pyqtSlot + QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegExp, QRunnable, QThreadPool, QRect, pyqtSlot from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, psutil, pexpect @@ -1584,13 +1585,15 @@ def __init__(self, parent=None, description="No Description", address="0x", self.lineEdit_length.setValidator(QHexValidator(999, self)) GuiUtils.fill_value_combobox(self.comboBox_ValueType, index) self.lineEdit_description.setText(description) + self.offsetsList = [] if not isinstance(address, type_defs.PointerType): self.lineEdit_address.setText(address) self.widget_Pointer.hide() else: + self.checkBox_IsPointer.setChecked(True) self.lineEdit_address.setEnabled(False) self.lineEdit_PtrStartAddress.setText(address.get_base_address()) - self.checkBox_IsPointer.setChecked(True) + self.create_offsets_list(address) self.widget_Pointer.show() if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.label_length.show() @@ -1621,6 +1624,8 @@ def __init__(self, parent=None, description="No Description", address="0x", self.checkBox_IsPointer.stateChanged.connect(self.comboBox_ValueType_current_index_changed) self.lineEdit_PtrStartAddress.textChanged.connect(self.update_value_of_address) self.lineEdit_address.textChanged.connect(self.update_value_of_address) + self.addOffsetButton.clicked.connect(lambda: self.addOffsetLayout(True)) + self.removeOffsetButton.clicked.connect(self.removeOffsetLayout) self.label_valueofaddress.contextMenuEvent = self.label_valueofaddress_context_menu_event self.update_value_of_address() @@ -1638,9 +1643,39 @@ def label_valueofaddress_context_menu_event(self, event): except KeyError: pass + def createOffsetLayout(self): + offsetFrame = QFrame(self.widget_Pointer) + offsetLayout = QHBoxLayout(offsetFrame) + offsetFrame.setLayout(offsetLayout) + buttonLeft = QPushButton("<", offsetFrame) + buttonLeft.setGeometry(QRect(10,5,20,20)) + offsetLayout.addWidget(buttonLeft) + offsetText = QLineEdit(offsetFrame) + offsetText.setGeometry(QRect(35,5,60,20)) + offsetText.textChanged.connect(self.update_value_of_address) + offsetLayout.addWidget(offsetText) + buttonRight = QPushButton(">", offsetFrame) + buttonRight.setGeometry(QRect(100,5,20,20)) + offsetLayout.addWidget(buttonRight) + return offsetFrame + + def addOffsetLayout(self, should_update=True): + self.offsetsList.append(self.createOffsetLayout()) + self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) + if should_update: + self.update_value_of_address() + + def removeOffsetLayout(self): + frame = self.offsetsList[-1] + frame.deleteLater() + self.verticalLayout_Pointers.removeWidget(frame) + del self.offsetsList[-1] + self.update_value_of_address() + def update_value_of_address(self): if self.checkBox_IsPointer.isChecked(): - address = GDB_Engine.read_pointer(type_defs.PointerType(self.lineEdit_PtrStartAddress.text())) + pointer_type = type_defs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) + address = GDB_Engine.read_pointer(pointer_type) if address != None: address_text = hex(address) else: @@ -1720,9 +1755,33 @@ def get_values(self): zero_terminate = True value_index = self.comboBox_ValueType.currentIndex() if self.checkBox_IsPointer.isChecked(): - address = type_defs.PointerType(self.lineEdit_PtrStartAddress.text()) + address = type_defs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) return description, address, value_index, length, zero_terminate + def get_offsets_int_list(self): + offsetsIntList = [] + for i in range(0, len(self.offsetsList)): + offsetsIntList.append(None) + for idx, frame in enumerate(self.offsetsList): + layout = frame.layout() + offsetText = layout.itemAt(1).widget().text() + try: + offsetValue = int(offsetText, 16) + except ValueError: + offsetValue = 0 + offsetsIntList[idx] = offsetValue + return offsetsIntList + + def create_offsets_list(self, address): + if not isinstance(address, type_defs.PointerType): + raise TypeError("Passed non-pointer type to create_offsets_list!") + + for offset in address.offsets_list: + self.addOffsetLayout(False) + frame = self.offsetsList[-1] + layout = frame.layout() + offsetText = layout.itemAt(1).widget().setText(hex(offset)) + class EditTypeDialogForm(QDialog, EditTypeDialog): def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True): From d1118fea77b5134e66af5fbd7521f65f93398633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 12 Aug 2022 01:11:52 +0300 Subject: [PATCH 056/487] Remove useless method --- PINCE.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index c872c937..19ec60bb 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1643,7 +1643,7 @@ def label_valueofaddress_context_menu_event(self, event): except KeyError: pass - def createOffsetLayout(self): + def addOffsetLayout(self, should_update=True): offsetFrame = QFrame(self.widget_Pointer) offsetLayout = QHBoxLayout(offsetFrame) offsetFrame.setLayout(offsetLayout) @@ -1657,10 +1657,8 @@ def createOffsetLayout(self): buttonRight = QPushButton(">", offsetFrame) buttonRight.setGeometry(QRect(100,5,20,20)) offsetLayout.addWidget(buttonRight) - return offsetFrame - def addOffsetLayout(self, should_update=True): - self.offsetsList.append(self.createOffsetLayout()) + self.offsetsList.append(offsetFrame) self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) if should_update: self.update_value_of_address() From 8a0d347f250234a6aa4e08ce0304de02e6506936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 12 Aug 2022 21:05:38 +0300 Subject: [PATCH 057/487] Add offset arrow buttons functionality --- PINCE.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index 19ec60bb..af4e8a8f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -72,6 +72,7 @@ from GUI.CustomValidators.HexValidator import QHexValidator from keyboard import add_hotkey, remove_hotkey +from operator import add as opAdd, sub as opSub instances = [] # Holds temporary instances that will be deleted later on @@ -1657,6 +1658,8 @@ def addOffsetLayout(self, should_update=True): buttonRight = QPushButton(">", offsetFrame) buttonRight.setGeometry(QRect(100,5,20,20)) offsetLayout.addWidget(buttonRight) + buttonLeft.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opSub)) + buttonRight.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opAdd)) self.offsetsList.append(offsetFrame) self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) @@ -1758,16 +1761,14 @@ def get_values(self): def get_offsets_int_list(self): offsetsIntList = [] - for i in range(0, len(self.offsetsList)): - offsetsIntList.append(None) - for idx, frame in enumerate(self.offsetsList): + for frame in self.offsetsList: layout = frame.layout() offsetText = layout.itemAt(1).widget().text() try: offsetValue = int(offsetText, 16) except ValueError: offsetValue = 0 - offsetsIntList[idx] = offsetValue + offsetsIntList.append(offsetValue) return offsetsIntList def create_offsets_list(self, address): @@ -1780,6 +1781,16 @@ def create_offsets_list(self, address): layout = frame.layout() offsetText = layout.itemAt(1).widget().setText(hex(offset)) + def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): + offsetText = offsetTextWidget.text() + try: + offsetValue = int(offsetText, 16) + except ValueError: + offsetValue = 0 + sizeVal = type_defs.index_to_valuetype_dict[self.comboBox_ValueType.currentIndex()][0] + offsetValue = operator_func(offsetValue, sizeVal) + offsetTextWidget.setText(hex(offsetValue)) + class EditTypeDialogForm(QDialog, EditTypeDialog): def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True): From 90105c46be35235a04119264c94ee051a4d3c225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 12 Aug 2022 21:10:35 +0300 Subject: [PATCH 058/487] Fix removeOffsetLayout exception --- PINCE.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PINCE.py b/PINCE.py index af4e8a8f..8377b4ea 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1667,6 +1667,8 @@ def addOffsetLayout(self, should_update=True): self.update_value_of_address() def removeOffsetLayout(self): + if len(self.offsetsList) == 0: + return frame = self.offsetsList[-1] frame.deleteLater() self.verticalLayout_Pointers.removeWidget(frame) From 1fe255340842d6bec57258636bc09d3007d37059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 12 Aug 2022 21:31:53 +0300 Subject: [PATCH 059/487] Restrict dialog maximum width --- GUI/AddAddressManuallyDialog.py | 1 + GUI/AddAddressManuallyDialog.ui | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 5387c04b..51d4f4ae 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -21,6 +21,7 @@ def setupUi(self, Dialog): sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) Dialog.setSizePolicy(sizePolicy) Dialog.setMinimumSize(QtCore.QSize(0, 0)) + Dialog.setMaximumSize(QtCore.QSize(224, 16777215)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.widget_Pointer = QtWidgets.QWidget(Dialog) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 20038d1c..f9095676 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -22,6 +22,12 @@ 0 + + + 224 + 16777215 + + Add Address Manually From 5879db3335968372d62365be67878030f38cb759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 12 Aug 2022 21:34:01 +0300 Subject: [PATCH 060/487] Change vertical spacer --- GUI/AddAddressManuallyDialog.py | 2 +- GUI/AddAddressManuallyDialog.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 51d4f4ae..2bfb3e85 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -75,7 +75,7 @@ def setupUi(self, Dialog): self.checkBox_IsPointer = QtWidgets.QCheckBox(Dialog) self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 120, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem1, 8, 0, 1, 1) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index f9095676..f3e55c90 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -158,7 +158,7 @@ 20 - 120 + 40 From 0c5df2276650bfafb2315a730cf6bbf7fe2c1d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 12 Aug 2022 23:27:43 +0300 Subject: [PATCH 061/487] Fix sizing issues --- GUI/AddAddressManuallyDialog.py | 4 ++-- GUI/AddAddressManuallyDialog.ui | 9 ++++++--- PINCE.py | 14 ++++++++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 2bfb3e85..285857e8 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -14,7 +14,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(224, 390) + Dialog.resize(224, 410) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -75,7 +75,7 @@ def setupUi(self, Dialog): self.checkBox_IsPointer = QtWidgets.QCheckBox(Dialog) self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem1, 8, 0, 1, 1) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index f3e55c90..39465163 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -7,7 +7,7 @@ 0 0 224 - 390 + 410 @@ -153,12 +153,12 @@ Qt::Vertical - QSizePolicy::Expanding + QSizePolicy::Minimum 20 - 40 + 20 @@ -315,6 +315,9 @@ Qt::Horizontal + + QSizePolicy::Expanding + 40 diff --git a/PINCE.py b/PINCE.py index 8377b4ea..194b1e1f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -25,7 +25,7 @@ QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, \ QPushButton, QFrame from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, \ - QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegExp, QRunnable, QThreadPool, QRect, pyqtSlot + QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegExp, QRunnable, QThreadPool, pyqtSlot from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, psutil, pexpect @@ -1619,6 +1619,7 @@ def __init__(self, parent=None, description="No Description", address="0x", self.label_length.hide() self.lineEdit_length.hide() self.checkBox_zeroterminate.hide() + self.setFixedSize(self.layout().sizeHint()) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.lineEdit_length.textChanged.connect(self.update_value_of_address) self.checkBox_zeroterminate.stateChanged.connect(self.update_value_of_address) @@ -1649,14 +1650,14 @@ def addOffsetLayout(self, should_update=True): offsetLayout = QHBoxLayout(offsetFrame) offsetFrame.setLayout(offsetLayout) buttonLeft = QPushButton("<", offsetFrame) - buttonLeft.setGeometry(QRect(10,5,20,20)) + buttonLeft.setFixedSize(70,30) offsetLayout.addWidget(buttonLeft) offsetText = QLineEdit(offsetFrame) - offsetText.setGeometry(QRect(35,5,60,20)) + offsetText.setFixedSize(70,30) offsetText.textChanged.connect(self.update_value_of_address) offsetLayout.addWidget(offsetText) buttonRight = QPushButton(">", offsetFrame) - buttonRight.setGeometry(QRect(100,5,20,20)) + buttonRight.setFixedSize(70,30) offsetLayout.addWidget(buttonRight) buttonLeft.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opSub)) buttonRight.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opAdd)) @@ -1664,6 +1665,8 @@ def addOffsetLayout(self, should_update=True): self.offsetsList.append(offsetFrame) self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) if should_update: + app.processEvents() # @todo should probably change this once we can properly resize right after creation + self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() def removeOffsetLayout(self): @@ -1673,6 +1676,8 @@ def removeOffsetLayout(self): frame.deleteLater() self.verticalLayout_Pointers.removeWidget(frame) del self.offsetsList[-1] + app.processEvents() # @todo should probably change this once we can properly resize right after delete + self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() def update_value_of_address(self): @@ -1727,6 +1732,7 @@ def comboBox_ValueType_current_index_changed(self): else: self.lineEdit_address.setEnabled(True) self.widget_Pointer.hide() + self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() def reject(self): From 26a5ef08d95e9e6a36e1192830aa62da38529cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 13 Aug 2022 00:50:35 +0300 Subject: [PATCH 062/487] Fix offset layout margins --- PINCE.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 194b1e1f..7da4abec 100755 --- a/PINCE.py +++ b/PINCE.py @@ -713,7 +713,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): selected_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not selected_row: return - address = selected_row.text(ADDR_COL).strip("P->") + address = selected_row.text(ADDR_COL).strip("P->") # @todo Maybe rework address grabbing logic in the future value_type = selected_row.data(TYPE_COL, Qt.UserRole) if type_defs.VALUE_INDEX.is_string(value_type.value_index): value_text = selected_row.text(VALUE_COL) @@ -1401,7 +1401,7 @@ def treeWidget_AddressTable_edit_value(self): if dialog.exec_(): new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): - address = row.text(ADDR_COL).strip("P->") # strip leading pointer text if pointer + address = row.text(ADDR_COL).strip("P->") value_type = row.data(TYPE_COL, Qt.UserRole) if type_defs.VALUE_INDEX.has_length(value_type.value_index): unknown_type = SysUtils.parse_string(new_value, value_type.value_index) @@ -1648,6 +1648,7 @@ def label_valueofaddress_context_menu_event(self, event): def addOffsetLayout(self, should_update=True): offsetFrame = QFrame(self.widget_Pointer) offsetLayout = QHBoxLayout(offsetFrame) + offsetLayout.setContentsMargins(0,3,0,3) offsetFrame.setLayout(offsetLayout) buttonLeft = QPushButton("<", offsetFrame) buttonLeft.setFixedSize(70,30) From bc4a115df716e33960d3da7d7bc7ba068a488324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 13 Aug 2022 20:56:42 +0300 Subject: [PATCH 063/487] Fix offset edge case --- PINCE.py | 1 + libpince/GDB_Engine.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 7da4abec..2db95abe 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1655,6 +1655,7 @@ def addOffsetLayout(self, should_update=True): offsetLayout.addWidget(buttonLeft) offsetText = QLineEdit(offsetFrame) offsetText.setFixedSize(70,30) + offsetText.setText(hex(0)) offsetText.textChanged.connect(self.update_value_of_address) offsetLayout.addWidget(offsetText) buttonRight = QPushButton(">", offsetFrame) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 00250f9f..fc9fa480 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -789,9 +789,9 @@ def read_pointer(pointer_type): try: with memory_handle() as mem_handle: final_address = deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) - for offset in pointer_type.offsets_list: + for index, offset in enumerate(pointer_type.offsets_list): offset_address = deref_address + offset - if offset != pointer_type.offsets_list[-1]: # CE derefs every offset except for the last one + if index != len(pointer_type.offsets_list) - 1: # CE derefs every offset except for the last one deref_address = read_memory(offset_address, value_index, mem_handle=mem_handle) else: final_address = offset_address From 37b53c75af2585afc6944640708a9493615eede3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 13 Aug 2022 23:14:59 +0300 Subject: [PATCH 064/487] Fix pointer deserialize when copy pasting --- PINCE.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 2db95abe..4457c105 100755 --- a/PINCE.py +++ b/PINCE.py @@ -824,8 +824,8 @@ def insert_records(self, records, parent_row, insert_index): frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) row.setData(FROZEN_COL, Qt.UserRole, frozen) - # Deserialize the value_type param - if type(rec[1]) == list: + # Deserialize the address_expr & value_type param + if hasattr(rec[1], "__iter__"): address_expr = type_defs.PointerType(*rec[1]) else: address_expr = rec[1] From 4ae8d76eadddcfab9cadf4d261a25ce695b1b809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 13 Aug 2022 23:34:08 +0300 Subject: [PATCH 065/487] Change deserialize check for pointer types --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 4457c105..13746197 100755 --- a/PINCE.py +++ b/PINCE.py @@ -825,7 +825,7 @@ def insert_records(self, records, parent_row, insert_index): row.setData(FROZEN_COL, Qt.UserRole, frozen) # Deserialize the address_expr & value_type param - if hasattr(rec[1], "__iter__"): + if type(rec[1]) in [list, tuple]: address_expr = type_defs.PointerType(*rec[1]) else: address_expr = rec[1] From a7974cf5982cc557fee4d4fdfc93b9fba47d591a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 14 Aug 2022 00:28:52 +0300 Subject: [PATCH 066/487] Add None return for invalid memory reads in read_pointer --- libpince/GDB_Engine.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index fc9fa480..764fb68d 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -766,6 +766,7 @@ def read_pointer(pointer_type): Returns: int: Final pointed address after dereferencing this pointer and it's offsets list + None: If an error occurs while reading the given pointer """ if not isinstance(pointer_type, type_defs.PointerType): raise TypeError("Passed non-PointerType to read_pointer!") @@ -789,10 +790,15 @@ def read_pointer(pointer_type): try: with memory_handle() as mem_handle: final_address = deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) + if deref_address is None: # deref would be None if read an invalid address region + return None + for index, offset in enumerate(pointer_type.offsets_list): offset_address = deref_address + offset if index != len(pointer_type.offsets_list) - 1: # CE derefs every offset except for the last one deref_address = read_memory(offset_address, value_index, mem_handle=mem_handle) + if deref_address is None: + return None else: final_address = offset_address except OSError: From 650e63af6010b31d5a66f746322a9e037f9c6195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 14 Aug 2022 00:46:12 +0300 Subject: [PATCH 067/487] Fix is_integer --- libpince/type_defs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 87c72a37..78ea7b96 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -177,7 +177,7 @@ class VALUE_INDEX: @staticmethod def is_integer(value_index): - return VALUE_INDEX.INDEX_INT8 <= value_index <= VALUE_INDEX.INDEX_INT32 + return VALUE_INDEX.INDEX_INT8 <= value_index <= VALUE_INDEX.INDEX_INT64 @staticmethod def is_string(value_index): From 850562172342a605ab2b04ad288bb178833dd850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 14 Aug 2022 12:27:15 +0300 Subject: [PATCH 068/487] Fix keyboard exception issue --- PINCE.py | 17 ++++++++++++----- libpince/SysUtils.py | 13 +++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 13746197..e01c8969 100755 --- a/PINCE.py +++ b/PINCE.py @@ -598,15 +598,21 @@ def auto_attach(self): self.attach_to_pid(process.pid) return + # Keyboard package has an issue with exceptions, any trigger function that throws an exception stops the event loop + # Writing a custom event loop instead of ignoring exceptions could work as well but honestly, this looks cleaner + @SysUtils.ignore_exceptions def pause_hotkey_pressed(self): GDB_Engine.interrupt_inferior(type_defs.STOP_REASON.PAUSE) + @SysUtils.ignore_exceptions def break_hotkey_pressed(self): GDB_Engine.interrupt_inferior() + @SysUtils.ignore_exceptions def continue_hotkey_pressed(self): GDB_Engine.continue_inferior() + @SysUtils.ignore_exceptions def toggle_attach_hotkey_pressed(self): result = GDB_Engine.toggle_attach() if not result: @@ -735,7 +741,8 @@ def browse_region_for_selected_row(self): def disassemble_selected_row(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if row: - if self.memory_view_window.disassemble_expression(row.text(ADDR_COL).strip("P->"), append_to_travel_history=True): + if self.memory_view_window.disassemble_expression(row.text(ADDR_COL).strip("P->"), + append_to_travel_history=True): self.memory_view_window.show() self.memory_view_window.activateWindow() @@ -1648,18 +1655,18 @@ def label_valueofaddress_context_menu_event(self, event): def addOffsetLayout(self, should_update=True): offsetFrame = QFrame(self.widget_Pointer) offsetLayout = QHBoxLayout(offsetFrame) - offsetLayout.setContentsMargins(0,3,0,3) + offsetLayout.setContentsMargins(0, 3, 0, 3) offsetFrame.setLayout(offsetLayout) buttonLeft = QPushButton("<", offsetFrame) - buttonLeft.setFixedSize(70,30) + buttonLeft.setFixedSize(70, 30) offsetLayout.addWidget(buttonLeft) offsetText = QLineEdit(offsetFrame) - offsetText.setFixedSize(70,30) + offsetText.setFixedSize(70, 30) offsetText.setText(hex(0)) offsetText.textChanged.connect(self.update_value_of_address) offsetLayout.addWidget(offsetText) buttonRight = QPushButton(">", offsetFrame) - buttonRight.setFixedSize(70,30) + buttonRight.setFixedSize(70, 30) offsetLayout.addWidget(buttonRight) buttonLeft.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opSub)) buttonRight.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opAdd)) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index efe3f18d..387fed61 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -1058,3 +1058,16 @@ def search_files(directory, regex): if result: file_list.append(str(file.relative_to(directory))) return sorted(file_list) + + +#:tag:Utilities +def ignore_exceptions(func): + """A decorator to ignore exceptions""" + + def wrapper(*args, **kwargs): + try: + func(*args, **kwargs) + except: + traceback.print_exc() + + return wrapper From 61d48ec27f96d0f37063ca1a164d98a843be58ca Mon Sep 17 00:00:00 2001 From: NinjaFB Date: Sun, 28 Aug 2022 02:20:21 +1000 Subject: [PATCH 069/487] Added Fedora support with dnf --- install_pince.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/install_pince.sh b/install_pince.sh index b1bf308d..7ad5a726 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -67,6 +67,7 @@ INSTALL_COMMAND="install" PKG_NAMES_ALL="python3-pip gdb" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-pyqt5 libtool libreadline-dev intltool" PKG_NAMES_SUSE="$PKG_NAMES_ALL python3-qt5" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-qt5 libtool readline-devel intltool" PKG_NAMES_ARCH="python-pip python-pyqt5 readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES="$PKG_NAMES_DEBIAN" PKG_NAMES_PIP="psutil pexpect distorm3 pygdbmi keyboard" @@ -91,6 +92,10 @@ case "$OS_NAME" in INSTALL_COMMAND="-S" PIP_COMMAND="pip" ;; +*Fedora*) + PKG_MGR="dnf -y" + PKG_NAMES="$PKG_NAMES_FEDORA" + ;; esac sudo ${PKG_MGR} ${INSTALL_COMMAND} ${PKG_NAMES} From 99d3048a04470a3ec0a72914cd019bb6cd0b7e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 28 Aug 2022 16:41:58 +0300 Subject: [PATCH 070/487] Add python3-devel for Fedora --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index 7ad5a726..5771e709 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -67,7 +67,7 @@ INSTALL_COMMAND="install" PKG_NAMES_ALL="python3-pip gdb" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-pyqt5 libtool libreadline-dev intltool" PKG_NAMES_SUSE="$PKG_NAMES_ALL python3-qt5" -PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-qt5 libtool readline-devel intltool" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-qt5 libtool readline-devel python3-devel intltool" PKG_NAMES_ARCH="python-pip python-pyqt5 readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES="$PKG_NAMES_DEBIAN" PKG_NAMES_PIP="psutil pexpect distorm3 pygdbmi keyboard" From 9bb2410921e2db5dc0f208115294a56cf21e2075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 28 Aug 2022 16:45:03 +0300 Subject: [PATCH 071/487] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8f3728e7..cd8c7802 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ Gibus - Debian and Debian-based (Kali, Mint etc.) - Archlinux(tag [cagriulas](https://github.com/cagriulas) or [TsarFox](https://github.com/TsarFox) when creating an issue) - SUSE +- Fedora # Trusted Sources * [Official github page](https://github.com/korcankaraokcu/PINCE) From 354f962af23c38b642e31aa87eb86ad4e7fc2e08 Mon Sep 17 00:00:00 2001 From: N00byKing Date: Sat, 1 Oct 2022 15:51:11 +0200 Subject: [PATCH 072/487] PyQT6 Upgrade, Pass 1 --- GUI/AboutWidget.py | 15 +- GUI/AddAddressManuallyDialog.py | 38 +- GUI/BookmarkWidget.py | 17 +- GUI/BreakpointInfoWidget.py | 18 +- GUI/ConsoleWidget.py | 41 +-- GUI/CustomAbstractTableModels/AsciiModel.py | 6 +- GUI/CustomAbstractTableModels/HexModel.py | 6 +- GUI/CustomLabels/FlagRegisterLabel.py | 8 +- GUI/CustomLabels/RegisterLabel.py | 10 +- GUI/CustomTableViews/HexView.py | 10 +- GUI/CustomValidators/HexValidator.py | 2 +- GUI/DissectCodeDialog.py | 65 ++-- GUI/EditTypeDialog.py | 26 +- GUI/ExamineReferrersWidget.py | 19 +- GUI/FloatRegisterWidget.py | 27 +- GUI/FunctionsInfoWidget.py | 18 +- GUI/GenPyFromUI.sh | 5 + GUI/HandleSignalsDialog.py | 25 +- GUI/HexEditDialog.py | 21 +- GUI/InputDialog.py | 20 +- GUI/LibpinceReferenceWidget.py | 29 +- GUI/LoadingDialog.py | 24 +- GUI/LogFileWidget.py | 16 +- GUI/MainWindow.py | 53 ++- GUI/MemoryRegionsWidget.py | 19 +- GUI/MemoryViewerWindow.py | 140 ++++--- GUI/ReferencedCallsWidget.py | 23 +- GUI/ReferencedStringsWidget.py | 27 +- GUI/RestoreInstructionsWidget.py | 15 +- GUI/SearchOpcodeWidget.py | 18 +- GUI/SelectProcess.py | 34 +- GUI/SettingsDialog.py | 51 ++- GUI/StackTraceInfoWidget.py | 17 +- GUI/TextEditDialog.py | 20 +- GUI/TraceInstructionsPromptDialog.py | 21 +- GUI/TraceInstructionsWaitWidget.py | 19 +- GUI/TraceInstructionsWindow.py | 23 +- GUI/TrackBreakpointWidget.py | 26 +- GUI/TrackWatchpointWidget.py | 23 +- PINCE.py | 388 ++++++++++---------- README.md | 8 +- install_pince.sh | 12 +- libpince/GuiUtils.py | 17 +- libpince/type_defs.py | 12 +- 44 files changed, 702 insertions(+), 730 deletions(-) create mode 100755 GUI/GenPyFromUI.sh diff --git a/GUI/AboutWidget.py b/GUI/AboutWidget.py index 4ff0ea25..a663c969 100644 --- a/GUI/AboutWidget.py +++ b/GUI/AboutWidget.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'aboutwidget.ui' +# Form implementation generated from reading ui file 'AboutWidget.ui' # -# Created: Wed Jun 29 16:34:26 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_TabWidget(object): def setupUi(self, TabWidget): @@ -39,4 +39,3 @@ def retranslateUi(self, TabWidget): TabWidget.setWindowTitle(_translate("TabWidget", "About PINCE")) TabWidget.setTabText(TabWidget.indexOf(self.tab_Contributors), _translate("TabWidget", "Contributors")) TabWidget.setTabText(TabWidget.indexOf(self.tab_License), _translate("TabWidget", "License")) - diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 285857e8..bc16ab90 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -1,21 +1,19 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt5 UI code generator 5.15.7 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(224, 410) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) @@ -40,14 +38,14 @@ def setupUi(self, Dialog): self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.lineEdit_PtrStartAddress = QtWidgets.QLineEdit(self.widget_Pointer) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_PtrStartAddress.sizePolicy().hasHeightForWidth()) self.lineEdit_PtrStartAddress.setSizePolicy(sizePolicy) self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_4.addItem(spacerItem) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() @@ -62,20 +60,20 @@ def setupUi(self, Dialog): self.verticalLayout_4.addLayout(self.verticalLayout_Pointers) self.gridLayout.addWidget(self.widget_Pointer, 7, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) self.buttonBox.setSizePolicy(sizePolicy) self.buttonBox.setMaximumSize(QtCore.QSize(16777215, 35)) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) self.checkBox_IsPointer = QtWidgets.QCheckBox(Dialog) self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout.addItem(spacerItem1, 8, 0, 1, 1) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") @@ -84,7 +82,7 @@ def setupUi(self, Dialog): self.label_5 = QtWidgets.QLabel(Dialog) self.label_5.setObjectName("label_5") self.horizontalLayout_3.addWidget(self.label_5) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem2) self.checkBox_zeroterminate = QtWidgets.QCheckBox(Dialog) self.checkBox_zeroterminate.setChecked(True) @@ -94,21 +92,21 @@ def setupUi(self, Dialog): self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.comboBox_ValueType = QtWidgets.QComboBox(Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.comboBox_ValueType.sizePolicy().hasHeightForWidth()) self.comboBox_ValueType.setSizePolicy(sizePolicy) - self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout_2.addWidget(self.comboBox_ValueType) - spacerItem3 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem3 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem3) self.label_length = QtWidgets.QLabel(Dialog) self.label_length.setObjectName("label_length") self.horizontalLayout_2.addWidget(self.label_length) self.lineEdit_length = QtWidgets.QLineEdit(Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_length.sizePolicy().hasHeightForWidth()) @@ -127,7 +125,7 @@ def setupUi(self, Dialog): self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.lineEdit_address = QtWidgets.QLineEdit(Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_address.sizePolicy().hasHeightForWidth()) @@ -141,10 +139,10 @@ def setupUi(self, Dialog): self.horizontalLayout.addWidget(self.label_2) self.label_valueofaddress = QtWidgets.QLabel(Dialog) self.label_valueofaddress.setText("") - self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_valueofaddress.setObjectName("label_valueofaddress") self.horizontalLayout.addWidget(self.label_valueofaddress) - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem4) self.verticalLayout_2.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) diff --git a/GUI/BookmarkWidget.py b/GUI/BookmarkWidget.py index 72164235..4f843a9b 100644 --- a/GUI/BookmarkWidget.py +++ b/GUI/BookmarkWidget.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'bookmarkwidget.ui' +# Form implementation generated from reading ui file 'BookmarkWidget.ui' # -# Created: Sat Jul 9 16:03:34 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -42,7 +42,7 @@ def setupUi(self, Form): self.lineEdit_Comment.setReadOnly(True) self.lineEdit_Comment.setObjectName("lineEdit_Comment") self.verticalLayout_2.addWidget(self.lineEdit_Comment) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_2.addItem(spacerItem) self.horizontalLayout.addLayout(self.verticalLayout_2) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) @@ -56,4 +56,3 @@ def retranslateUi(self, Form): self.label.setText(_translate("Form", "Bookmarked Addresses")) self.label_2.setText(_translate("Form", "Info")) self.label_3.setText(_translate("Form", "Comment")) - diff --git a/GUI/BreakpointInfoWidget.py b/GUI/BreakpointInfoWidget.py index 88b5f101..cfd7aa59 100644 --- a/GUI/BreakpointInfoWidget.py +++ b/GUI/BreakpointInfoWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'BreakpointInfoWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_TabWidget(object): def setupUi(self, TabWidget): @@ -17,9 +18,9 @@ def setupUi(self, TabWidget): self.gridLayout_2 = QtWidgets.QGridLayout(self.tab_BreakpointInfo) self.gridLayout_2.setObjectName("gridLayout_2") self.tableWidget_BreakpointInfo = QtWidgets.QTableWidget(self.tab_BreakpointInfo) - self.tableWidget_BreakpointInfo.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_BreakpointInfo.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_BreakpointInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_BreakpointInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_BreakpointInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_BreakpointInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_BreakpointInfo.setObjectName("tableWidget_BreakpointInfo") self.tableWidget_BreakpointInfo.setColumnCount(9) self.tableWidget_BreakpointInfo.setRowCount(0) @@ -83,4 +84,3 @@ def retranslateUi(self, TabWidget): item.setText(_translate("TabWidget", "Condition")) TabWidget.setTabText(TabWidget.indexOf(self.tab_BreakpointInfo), _translate("TabWidget", "Interactive")) TabWidget.setTabText(TabWidget.indexOf(self.tab_RawBreakpointInfo), _translate("TabWidget", "Raw")) - diff --git a/GUI/ConsoleWidget.py b/GUI/ConsoleWidget.py index 29c6e48e..62ca270e 100644 --- a/GUI/ConsoleWidget.py +++ b/GUI/ConsoleWidget.py @@ -1,19 +1,19 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'consolewidget.ui' +# Form implementation generated from reading ui file 'ConsoleWidget.ui' # -# Created: Thu Jul 21 18:11:36 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") Form.resize(850, 500) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) @@ -26,23 +26,23 @@ def setupUi(self, Form): self.textBrowser = QtWidgets.QTextBrowser(Form) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 0)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Base, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 0)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Base, brush) brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Base, brush) self.textBrowser.setPalette(palette) font = QtGui.QFont() font.setFamily("Monospace") @@ -88,4 +88,3 @@ def retranslateUi(self, Form): self.pushButton_SendCtrl.setText(_translate("Form", "Send ctrl+c")) self.radioButton_CLI.setText(_translate("Form", "CLI")) self.radioButton_MI.setText(_translate("Form", "MI")) - diff --git a/GUI/CustomAbstractTableModels/AsciiModel.py b/GUI/CustomAbstractTableModels/AsciiModel.py index b43750e9..bcd42c42 100644 --- a/GUI/CustomAbstractTableModels/AsciiModel.py +++ b/GUI/CustomAbstractTableModels/AsciiModel.py @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtCore import QVariant, Qt -from PyQt5.QtGui import QColor +from PyQt6.QtCore import QVariant, Qt +from PyQt6.QtGui import QColor from GUI.CustomAbstractTableModels.HexModel import QHexModel from libpince import SysUtils, GDB_Engine @@ -28,7 +28,7 @@ def __init__(self, row_count, column_count, parent=None): def data(self, QModelIndex, int_role=None): if not QModelIndex.isValid(): return QVariant() - if int_role == Qt.BackgroundColorRole: + if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: return QVariant(QColor(Qt.red)) diff --git a/GUI/CustomAbstractTableModels/HexModel.py b/GUI/CustomAbstractTableModels/HexModel.py index dc2fcb3f..5cb0ef18 100644 --- a/GUI/CustomAbstractTableModels/HexModel.py +++ b/GUI/CustomAbstractTableModels/HexModel.py @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtCore import QAbstractTableModel, QVariant, Qt -from PyQt5.QtGui import QColor +from PyQt6.QtCore import QAbstractTableModel, QVariant, Qt +from PyQt6.QtGui import QColor from libpince import SysUtils, GDB_Engine @@ -38,7 +38,7 @@ def columnCount(self, QModelIndex_parent=None, *args, **kwargs): def data(self, QModelIndex, int_role=None): if not QModelIndex.isValid(): return QVariant() - if int_role == Qt.BackgroundColorRole: + if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: return QVariant(QColor(Qt.red)) diff --git a/GUI/CustomLabels/FlagRegisterLabel.py b/GUI/CustomLabels/FlagRegisterLabel.py index f08980f5..58c91090 100644 --- a/GUI/CustomLabels/FlagRegisterLabel.py +++ b/GUI/CustomLabels/FlagRegisterLabel.py @@ -14,9 +14,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtWidgets import QLabel -from PyQt5.QtGui import QCursor -from PyQt5.QtCore import Qt +from PyQt6.QtWidgets import QLabel +from PyQt6.QtGui import QCursor +from PyQt6.QtCore import Qt from libpince import GDB_Engine from PINCE import InputDialogForm @@ -42,6 +42,6 @@ def mouseDoubleClickEvent(self, QMouseEvent): current_flag = self.objectName().lower() label_text = "Enter the new value of flag " + self.objectName() register_dialog = InputDialogForm(item_list=[(label_text, ["0", "1", int(registers[current_flag])])]) - if register_dialog.exec_(): + if register_dialog.exec(): GDB_Engine.set_register_flag(current_flag, register_dialog.get_values()) self.set_value(GDB_Engine.read_registers()[current_flag]) diff --git a/GUI/CustomLabels/RegisterLabel.py b/GUI/CustomLabels/RegisterLabel.py index 107b35d9..93a5fc40 100644 --- a/GUI/CustomLabels/RegisterLabel.py +++ b/GUI/CustomLabels/RegisterLabel.py @@ -14,9 +14,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtWidgets import QLabel, QMenu -from PyQt5.QtGui import QCursor -from PyQt5.QtCore import Qt +from PyQt6.QtWidgets import QLabel, QMenu +from PyQt6.QtGui import QCursor +from PyQt6.QtCore import Qt from libpince import GDB_Engine from libpince import GuiUtils from PINCE import InputDialogForm @@ -43,7 +43,7 @@ def mouseDoubleClickEvent(self, QMouseEvent): current_register = self.objectName().lower() register_dialog = InputDialogForm( item_list=[("Enter the new value of register " + self.objectName(), registers[current_register])]) - if register_dialog.exec_(): + if register_dialog.exec(): GDB_Engine.set_convenience_variable(current_register, register_dialog.get_values()) self.set_value(GDB_Engine.read_registers()[current_register]) @@ -53,7 +53,7 @@ def contextMenuEvent(self, QContextMenuEvent): show_in_disassembler = menu.addAction("Show in Disassembler") font_size = self.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(QContextMenuEvent.globalPos()) + action = menu.exec(QContextMenuEvent.globalPos()) if action == show_in_hex_view: parent = GuiUtils.search_parents_by_function(self, "hex_dump_address") if parent.objectName() == "MainWindow_MemoryView": diff --git a/GUI/CustomTableViews/HexView.py b/GUI/CustomTableViews/HexView.py index afcf1760..213a0445 100644 --- a/GUI/CustomTableViews/HexView.py +++ b/GUI/CustomTableViews/HexView.py @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtWidgets import QTableView, QAbstractItemView -from PyQt5.QtCore import Qt +from PyQt6.QtWidgets import QTableView, QAbstractItemView +from PyQt6.QtCore import Qt from libpince import SysUtils, GDB_Engine @@ -29,9 +29,9 @@ def __init__(self, parent=None): self.horizontalHeader().setDefaultSectionSize(self.horizontalHeader().minimumSectionSize()) self.setStyleSheet("QTableView {background-color: transparent;}") self.setShowGrid(False) - self.setSelectionMode(QAbstractItemView.SingleSelection) - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) + self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setAutoScroll(False) def wheelEvent(self, QWheelEvent): diff --git a/GUI/CustomValidators/HexValidator.py b/GUI/CustomValidators/HexValidator.py index a2dd386b..ee06a33a 100644 --- a/GUI/CustomValidators/HexValidator.py +++ b/GUI/CustomValidators/HexValidator.py @@ -1,4 +1,4 @@ -from PyQt5.QtGui import QValidator +from PyQt6.QtGui import QValidator class QHexValidator(QValidator): diff --git a/GUI/DissectCodeDialog.py b/GUI/DissectCodeDialog.py index 84cb236b..ab2e6a0f 100644 --- a/GUI/DissectCodeDialog.py +++ b/GUI/DissectCodeDialog.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'DissectCodeDialog.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): @@ -15,11 +16,11 @@ def setupUi(self, Dialog): self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.splitter = QtWidgets.QSplitter(Dialog) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.tableWidget_ExecutableMemoryRegions = QtWidgets.QTableWidget(self.splitter) - self.tableWidget_ExecutableMemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_ExecutableMemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_ExecutableMemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_ExecutableMemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_ExecutableMemoryRegions.setObjectName("tableWidget_ExecutableMemoryRegions") self.tableWidget_ExecutableMemoryRegions.setColumnCount(2) self.tableWidget_ExecutableMemoryRegions.setRowCount(0) @@ -34,70 +35,71 @@ def setupUi(self, Dialog): self.layoutWidget = QtWidgets.QWidget(self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.layoutWidget) + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.label_ScanInfo = QtWidgets.QLabel(self.layoutWidget) - self.label_ScanInfo.setAlignment(QtCore.Qt.AlignCenter) - self.label_ScanInfo.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_ScanInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label_ScanInfo.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_ScanInfo.setObjectName("label_ScanInfo") self.verticalLayout.addWidget(self.label_ScanInfo) self.label_RegionInfo = QtWidgets.QLabel(self.layoutWidget) - self.label_RegionInfo.setAlignment(QtCore.Qt.AlignCenter) - self.label_RegionInfo.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_RegionInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label_RegionInfo.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_RegionInfo.setObjectName("label_RegionInfo") self.verticalLayout.addWidget(self.label_RegionInfo) self.label_RegionCountInfo = QtWidgets.QLabel(self.layoutWidget) - self.label_RegionCountInfo.setAlignment(QtCore.Qt.AlignCenter) - self.label_RegionCountInfo.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_RegionCountInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label_RegionCountInfo.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_RegionCountInfo.setObjectName("label_RegionCountInfo") self.verticalLayout.addWidget(self.label_RegionCountInfo) self.label_4 = QtWidgets.QLabel(self.layoutWidget) - self.label_4.setAlignment(QtCore.Qt.AlignCenter) - self.label_4.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_4.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label_4.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_4.setObjectName("label_4") self.verticalLayout.addWidget(self.label_4) self.label_CurrentRange = QtWidgets.QLabel(self.layoutWidget) - self.label_CurrentRange.setAlignment(QtCore.Qt.AlignCenter) - self.label_CurrentRange.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_CurrentRange.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label_CurrentRange.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_CurrentRange.setObjectName("label_CurrentRange") self.verticalLayout.addWidget(self.label_CurrentRange) self.verticalLayout_2.addLayout(self.verticalLayout) self.line = QtWidgets.QFrame(self.layoutWidget) - self.line.setFrameShape(QtWidgets.QFrame.HLine) - self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line.setObjectName("line") self.verticalLayout_2.addWidget(self.line) self.label = QtWidgets.QLabel(self.layoutWidget) - self.label.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label.setObjectName("label") self.verticalLayout_2.addWidget(self.label) self.label_StringReferenceCount = QtWidgets.QLabel(self.layoutWidget) self.label_StringReferenceCount.setText("") - self.label_StringReferenceCount.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_StringReferenceCount.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_StringReferenceCount.setObjectName("label_StringReferenceCount") self.verticalLayout_2.addWidget(self.label_StringReferenceCount) self.label_2 = QtWidgets.QLabel(self.layoutWidget) - self.label_2.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_2.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_2.setObjectName("label_2") self.verticalLayout_2.addWidget(self.label_2) self.label_JumpReferenceCount = QtWidgets.QLabel(self.layoutWidget) self.label_JumpReferenceCount.setText("") - self.label_JumpReferenceCount.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_JumpReferenceCount.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_JumpReferenceCount.setObjectName("label_JumpReferenceCount") self.verticalLayout_2.addWidget(self.label_JumpReferenceCount) self.label_3 = QtWidgets.QLabel(self.layoutWidget) - self.label_3.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_3.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_3.setObjectName("label_3") self.verticalLayout_2.addWidget(self.label_3) self.label_CallReferenceCount = QtWidgets.QLabel(self.layoutWidget) self.label_CallReferenceCount.setText("") - self.label_CallReferenceCount.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_CallReferenceCount.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_CallReferenceCount.setObjectName("label_CallReferenceCount") self.verticalLayout_2.addWidget(self.label_CallReferenceCount) self.line_2 = QtWidgets.QFrame(self.layoutWidget) - self.line_2.setFrameShape(QtWidgets.QFrame.HLine) - self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_2.setObjectName("line_2") self.verticalLayout_2.addWidget(self.line_2) self.checkBox_DiscardInvalidStrings = QtWidgets.QCheckBox(self.layoutWidget) @@ -106,16 +108,16 @@ def setupUi(self, Dialog): self.verticalLayout_2.addWidget(self.checkBox_DiscardInvalidStrings) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) self.pushButton_StartCancel = QtWidgets.QPushButton(self.layoutWidget) self.pushButton_StartCancel.setText("") self.pushButton_StartCancel.setObjectName("pushButton_StartCancel") self.horizontalLayout.addWidget(self.pushButton_StartCancel) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.verticalLayout_2.addLayout(self.horizontalLayout) - spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_2.addItem(spacerItem2) self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) @@ -140,4 +142,3 @@ def retranslateUi(self, Dialog): self.checkBox_DiscardInvalidStrings.setToolTip(_translate("Dialog", "Entries that can\'t be decoded as utf-8 won\'t be included in referenced strings\n" "Unchecking it makes ReferencedStringsWidget load slower but allows you to examine non-string pointers on it")) self.checkBox_DiscardInvalidStrings.setText(_translate("Dialog", "Discard invalid strings")) - diff --git a/GUI/EditTypeDialog.py b/GUI/EditTypeDialog.py index fc4d0a5d..1254888c 100644 --- a/GUI/EditTypeDialog.py +++ b/GUI/EditTypeDialog.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'EditTypeDialog.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): @@ -36,13 +37,13 @@ def setupUi(self, Dialog): self.lineEdit_Length = QtWidgets.QLineEdit(Dialog) self.lineEdit_Length.setObjectName("lineEdit_Length") self.horizontalLayout_2.addWidget(self.lineEdit_Length) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem) self.verticalLayout_3.addLayout(self.horizontalLayout_2) self.horizontalLayout_3.addLayout(self.verticalLayout_3) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_2.addItem(spacerItem1) self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(Dialog) self.checkBox_ZeroTerminate.setChecked(True) @@ -53,17 +54,17 @@ def setupUi(self, Dialog): self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.horizontalLayout.addWidget(self.buttonBox) - spacerItem2 = QtWidgets.QSpacerItem(37, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem(37, 17, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem2) self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) self.retranslateUi(Dialog) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): @@ -73,4 +74,3 @@ def retranslateUi(self, Dialog): self.label_Length.setText(_translate("Dialog", "Length")) self.lineEdit_Length.setText(_translate("Dialog", "10")) self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) - diff --git a/GUI/ExamineReferrersWidget.py b/GUI/ExamineReferrersWidget.py index c6c61691..31224403 100644 --- a/GUI/ExamineReferrersWidget.py +++ b/GUI/ExamineReferrersWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'ExamineReferrersWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -16,11 +17,12 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.splitter = QtWidgets.QSplitter(Form) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.layoutWidget = QtWidgets.QWidget(self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") @@ -38,11 +40,11 @@ def setupUi(self, Form): self.horizontalLayout_2.addWidget(self.pushButton_Search) self.verticalLayout.addLayout(self.horizontalLayout_2) self.listWidget_Referrers = QtWidgets.QListWidget(self.layoutWidget) - self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.listWidget_Referrers.setObjectName("listWidget_Referrers") self.verticalLayout.addWidget(self.listWidget_Referrers) self.textBrowser_DisasInfo = QtWidgets.QTextBrowser(self.splitter) - self.textBrowser_DisasInfo.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) + self.textBrowser_DisasInfo.setLineWrapMode(QtWidgets.QTextEdit.LineWrapMode.NoWrap) self.textBrowser_DisasInfo.setObjectName("textBrowser_DisasInfo") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) @@ -59,4 +61,3 @@ def retranslateUi(self, Form): self.checkBox_Regex.setToolTip(_translate("Form", "Your string will be treated as a regex if checked")) self.checkBox_Regex.setText(_translate("Form", "Regex")) self.pushButton_Search.setText(_translate("Form", "Search(Enter)")) - diff --git a/GUI/FloatRegisterWidget.py b/GUI/FloatRegisterWidget.py index 35aa8a46..73798d37 100644 --- a/GUI/FloatRegisterWidget.py +++ b/GUI/FloatRegisterWidget.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'floatregisterwidget.ui' +# Form implementation generated from reading ui file 'FloatRegisterWidget.ui' # -# Created: Tue Jul 19 01:12:53 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_TabWidget(object): def setupUi(self, TabWidget): @@ -18,9 +18,9 @@ def setupUi(self, TabWidget): self.gridLayout = QtWidgets.QGridLayout(self.FPU) self.gridLayout.setObjectName("gridLayout") self.tableWidget_FPU = QtWidgets.QTableWidget(self.FPU) - self.tableWidget_FPU.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_FPU.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_FPU.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_FPU.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_FPU.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_FPU.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_FPU.setObjectName("tableWidget_FPU") self.tableWidget_FPU.setColumnCount(2) self.tableWidget_FPU.setRowCount(0) @@ -37,9 +37,9 @@ def setupUi(self, TabWidget): self.gridLayout_2 = QtWidgets.QGridLayout(self.XMM) self.gridLayout_2.setObjectName("gridLayout_2") self.tableWidget_XMM = QtWidgets.QTableWidget(self.XMM) - self.tableWidget_XMM.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_XMM.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_XMM.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_XMM.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_XMM.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_XMM.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_XMM.setObjectName("tableWidget_XMM") self.tableWidget_XMM.setColumnCount(2) self.tableWidget_XMM.setRowCount(0) @@ -69,4 +69,3 @@ def retranslateUi(self, TabWidget): item = self.tableWidget_XMM.horizontalHeaderItem(1) item.setText(_translate("TabWidget", "Value")) TabWidget.setTabText(TabWidget.indexOf(self.XMM), _translate("TabWidget", "XMM")) - diff --git a/GUI/FunctionsInfoWidget.py b/GUI/FunctionsInfoWidget.py index e63e39a4..cab5405f 100644 --- a/GUI/FunctionsInfoWidget.py +++ b/GUI/FunctionsInfoWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'FunctionsInfoWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -15,9 +16,9 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.tableWidget_SymbolInfo = QtWidgets.QTableWidget(Form) - self.tableWidget_SymbolInfo.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_SymbolInfo.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_SymbolInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_SymbolInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_SymbolInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_SymbolInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_SymbolInfo.setObjectName("tableWidget_SymbolInfo") self.tableWidget_SymbolInfo.setColumnCount(2) self.tableWidget_SymbolInfo.setRowCount(0) @@ -65,4 +66,3 @@ def retranslateUi(self, Form): self.checkBox_CaseSensitive.setToolTip(_translate("Form", "Ignore case if checked")) self.checkBox_CaseSensitive.setText(_translate("Form", "Case sensitive")) self.pushButton_Search.setText(_translate("Form", "Search(Enter)")) - diff --git a/GUI/GenPyFromUI.sh b/GUI/GenPyFromUI.sh new file mode 100755 index 00000000..8fe7b4c0 --- /dev/null +++ b/GUI/GenPyFromUI.sh @@ -0,0 +1,5 @@ +for uifile in *.ui +do + outfile=$(echo $uifile | sed 's/\.ui/\.py/g') + pyuic6 $uifile -o $outfile +done \ No newline at end of file diff --git a/GUI/HandleSignalsDialog.py b/GUI/HandleSignalsDialog.py index 2993bf1b..9cdf3e3f 100644 --- a/GUI/HandleSignalsDialog.py +++ b/GUI/HandleSignalsDialog.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'HandleSignalsDialog.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): @@ -17,9 +16,9 @@ def setupUi(self, Dialog): self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.tableWidget_Signals = QtWidgets.QTableWidget(Dialog) - self.tableWidget_Signals.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_Signals.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_Signals.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Signals.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_Signals.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_Signals.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Signals.setObjectName("tableWidget_Signals") self.tableWidget_Signals.setColumnCount(2) self.tableWidget_Signals.setRowCount(0) @@ -33,14 +32,14 @@ def setupUi(self, Dialog): self.tableWidget_Signals.verticalHeader().setMinimumSectionSize(16) self.gridLayout.addWidget(self.tableWidget_Signals, 0, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) self.retranslateUi(Dialog) - self.buttonBox.rejected.connect(Dialog.reject) - self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): @@ -59,4 +58,4 @@ def retranslateUi(self, Dialog): ui = Ui_Dialog() ui.setupUi(Dialog) Dialog.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) diff --git a/GUI/HexEditDialog.py b/GUI/HexEditDialog.py index 179ff306..305c866c 100644 --- a/GUI/HexEditDialog.py +++ b/GUI/HexEditDialog.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'HexEditDialog.ui' # -# Created: Fri Dec 9 21:31:02 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): @@ -40,14 +40,14 @@ def setupUi(self, Dialog): self.lineEdit_HexView.setObjectName("lineEdit_HexView") self.gridLayout.addWidget(self.lineEdit_HexView, 2, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 1) self.retranslateUi(Dialog) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): @@ -56,4 +56,3 @@ def retranslateUi(self, Dialog): self.label.setText(_translate("Dialog", "Address:")) self.label_2.setText(_translate("Dialog", "Length:")) self.pushButton_Refresh.setText(_translate("Dialog", "Refresh")) - diff --git a/GUI/InputDialog.py b/GUI/InputDialog.py index 5424a658..aa26a5a7 100644 --- a/GUI/InputDialog.py +++ b/GUI/InputDialog.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'InputDialog.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): @@ -18,18 +19,17 @@ def setupUi(self, Dialog): self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.NoButton) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.NoButton) self.buttonBox.setCenterButtons(True) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) self.horizontalLayout.addLayout(self.verticalLayout) self.retranslateUi(Dialog) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): pass - diff --git a/GUI/LibpinceReferenceWidget.py b/GUI/LibpinceReferenceWidget.py index 686845f7..d9604239 100644 --- a/GUI/LibpinceReferenceWidget.py +++ b/GUI/LibpinceReferenceWidget.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'LibpinceReferenceWidget.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Form(object): @@ -19,7 +18,7 @@ def setupUi(self, Form): self.gridLayout_2.setSpacing(0) self.gridLayout_2.setObjectName("gridLayout_2") self.splitter = QtWidgets.QSplitter(Form) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setHandleWidth(10) self.splitter.setObjectName("splitter") self.widget_TypeDefs = QtWidgets.QWidget(self.splitter) @@ -33,14 +32,14 @@ def setupUi(self, Form): self.label_5.setObjectName("label_5") self.horizontalLayout_4.addWidget(self.label_5) self.line = QtWidgets.QFrame(self.widget_TypeDefs) - self.line.setFrameShape(QtWidgets.QFrame.VLine) - self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine) + self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line.setObjectName("line") self.horizontalLayout_4.addWidget(self.line) self.label_3 = QtWidgets.QLabel(self.widget_TypeDefs) self.label_3.setObjectName("label_3") self.horizontalLayout_4.addWidget(self.label_3) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_4.addItem(spacerItem) self.gridLayout.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() @@ -77,7 +76,7 @@ def setupUi(self, Form): self.gridLayout_4.setSpacing(0) self.gridLayout_4.setObjectName("gridLayout_4") self.treeWidget_ResourceTree = QtWidgets.QTreeWidget(self.page) - self.treeWidget_ResourceTree.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.treeWidget_ResourceTree.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.treeWidget_ResourceTree.setObjectName("treeWidget_ResourceTree") self.treeWidget_ResourceTree.headerItem().setText(0, "Item Name") self.gridLayout_4.addWidget(self.treeWidget_ResourceTree, 0, 0, 1, 1) @@ -89,9 +88,9 @@ def setupUi(self, Form): self.gridLayout_5.setSpacing(0) self.gridLayout_5.setObjectName("gridLayout_5") self.tableWidget_ResourceTable = QtWidgets.QTableWidget(self.page_2) - self.tableWidget_ResourceTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_ResourceTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_ResourceTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_ResourceTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_ResourceTable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_ResourceTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_ResourceTable.setObjectName("tableWidget_ResourceTable") self.tableWidget_ResourceTable.setColumnCount(2) self.tableWidget_ResourceTable.setRowCount(0) @@ -132,7 +131,7 @@ def setupUi(self, Form): self.label_2 = QtWidgets.QLabel(self.widget_Resources) self.label_2.setObjectName("label_2") self.horizontalLayout_3.addWidget(self.label_2) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem1) self.pushButton_ShowTypeDefs = QtWidgets.QPushButton(self.widget_Resources) self.pushButton_ShowTypeDefs.setObjectName("pushButton_ShowTypeDefs") @@ -169,4 +168,4 @@ def retranslateUi(self, Form): ui = Ui_Form() ui.setupUi(Form) Form.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) diff --git a/GUI/LoadingDialog.py b/GUI/LoadingDialog.py index 5efff741..15858c26 100644 --- a/GUI/LoadingDialog.py +++ b/GUI/LoadingDialog.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'LoadingDialog.ui' # -# Created: Tue Feb 21 22:38:30 2017 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): @@ -17,10 +17,10 @@ def setupUi(self, 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) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) self.label_Animated = QtWidgets.QLabel(Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_Animated.sizePolicy().hasHeightForWidth()) @@ -32,20 +32,19 @@ def setupUi(self, Dialog): self.label_StatusText = QtWidgets.QLabel(Dialog) self.label_StatusText.setObjectName("label_StatusText") self.horizontalLayout.addWidget(self.label_StatusText) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem1) 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) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.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) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout.addItem(spacerItem3, 0, 2, 1, 1) self.gridLayout_2.addWidget(self.widget_Cancel, 1, 0, 1, 1) @@ -57,4 +56,3 @@ def retranslateUi(self, Dialog): Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.label_StatusText.setText(_translate("Dialog", "Processing")) self.pushButton_Cancel.setText(_translate("Dialog", "Cancel")) - diff --git a/GUI/LogFileWidget.py b/GUI/LogFileWidget.py index 8ed0d9da..21e8edc2 100644 --- a/GUI/LogFileWidget.py +++ b/GUI/LogFileWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'LogFileWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -17,7 +18,7 @@ def setupUi(self, Form): self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.label_FilePath = QtWidgets.QLabel(Form) - self.label_FilePath.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_FilePath.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_FilePath.setObjectName("label_FilePath") self.horizontalLayout.addWidget(self.label_FilePath) self.label_LoggingStatus = QtWidgets.QLabel(Form) @@ -25,7 +26,7 @@ def setupUi(self, Form): self.horizontalLayout.addWidget(self.label_LoggingStatus) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) self.textBrowser_LogContent = QtWidgets.QTextBrowser(Form) - self.textBrowser_LogContent.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) + self.textBrowser_LogContent.setLineWrapMode(QtWidgets.QTextEdit.LineWrapMode.NoWrap) self.textBrowser_LogContent.setObjectName("textBrowser_LogContent") self.gridLayout.addWidget(self.textBrowser_LogContent, 1, 0, 1, 1) @@ -37,4 +38,3 @@ def retranslateUi(self, Form): Form.setWindowTitle(_translate("Form", "Form")) self.label_FilePath.setText(_translate("Form", "TextLabel")) self.label_LoggingStatus.setText(_translate("Form", "TextLabel")) - diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index dfe4a8ca..cd48774a 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'MainWindow.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): @@ -19,21 +18,21 @@ def setupUi(self, MainWindow): self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.treeWidget_AddressTable = QtWidgets.QTreeWidget(self.centralwidget) - self.treeWidget_AddressTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.treeWidget_AddressTable.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop) - self.treeWidget_AddressTable.setDefaultDropAction(QtCore.Qt.MoveAction) - self.treeWidget_AddressTable.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + self.treeWidget_AddressTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.treeWidget_AddressTable.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.DragDrop) + self.treeWidget_AddressTable.setDefaultDropAction(QtCore.Qt.DropAction.MoveAction) + self.treeWidget_AddressTable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection) self.treeWidget_AddressTable.setIndentation(12) self.treeWidget_AddressTable.setExpandsOnDoubleClick(False) self.treeWidget_AddressTable.setObjectName("treeWidget_AddressTable") self.gridLayout.addWidget(self.treeWidget_AddressTable, 3, 0, 1, 1) self.horizontalLayout_8 = QtWidgets.QHBoxLayout() - self.horizontalLayout_8.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize) + self.horizontalLayout_8.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinAndMaxSize) self.horizontalLayout_8.setObjectName("horizontalLayout_8") self.pushButton_MemoryView = QtWidgets.QPushButton(self.centralwidget) self.pushButton_MemoryView.setObjectName("pushButton_MemoryView") self.horizontalLayout_8.addWidget(self.pushButton_MemoryView) - spacerItem = QtWidgets.QSpacerItem(120, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(120, 20, QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem) self.pushButton_CopyToAddressTable = QtWidgets.QPushButton(self.centralwidget) self.pushButton_CopyToAddressTable.setText("") @@ -43,23 +42,23 @@ def setupUi(self, MainWindow): self.pushButton_CleanAddressTable.setText("") self.pushButton_CleanAddressTable.setObjectName("pushButton_CleanAddressTable") self.horizontalLayout_8.addWidget(self.pushButton_CleanAddressTable) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem1) self.pushButton_RefreshAdressTable = QtWidgets.QPushButton(self.centralwidget) self.pushButton_RefreshAdressTable.setText("") self.pushButton_RefreshAdressTable.setObjectName("pushButton_RefreshAdressTable") self.horizontalLayout_8.addWidget(self.pushButton_RefreshAdressTable) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem2) self.pushButton_AddAddressManually = QtWidgets.QPushButton(self.centralwidget) self.pushButton_AddAddressManually.setObjectName("pushButton_AddAddressManually") self.horizontalLayout_8.addWidget(self.pushButton_AddAddressManually) self.gridLayout.addLayout(self.horizontalLayout_8, 2, 0, 1, 1) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() - self.horizontalLayout_5.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) + self.horizontalLayout_5.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetFixedSize) self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.pushButton_AttachProcess = QtWidgets.QPushButton(self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_AttachProcess.sizePolicy().hasHeightForWidth()) @@ -68,7 +67,7 @@ def setupUi(self, MainWindow): self.pushButton_AttachProcess.setObjectName("pushButton_AttachProcess") self.horizontalLayout_5.addWidget(self.pushButton_AttachProcess) self.pushButton_Open = QtWidgets.QPushButton(self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_Open.sizePolicy().hasHeightForWidth()) @@ -77,7 +76,7 @@ def setupUi(self, MainWindow): self.pushButton_Open.setObjectName("pushButton_Open") self.horizontalLayout_5.addWidget(self.pushButton_Open) self.pushButton_Save = QtWidgets.QPushButton(self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_Save.sizePolicy().hasHeightForWidth()) @@ -102,7 +101,7 @@ def setupUi(self, MainWindow): self.horizontalLayout_5.addWidget(self.label_InferiorStatus) self.progressBar = QtWidgets.QProgressBar(self.centralwidget) self.progressBar.setProperty("value", 0) - self.progressBar.setOrientation(QtCore.Qt.Horizontal) + self.progressBar.setOrientation(QtCore.Qt.Orientation.Horizontal) self.progressBar.setObjectName("progressBar") self.horizontalLayout_5.addWidget(self.progressBar) self.pushButton_Console = QtWidgets.QPushButton(self.centralwidget) @@ -110,7 +109,7 @@ def setupUi(self, MainWindow): self.pushButton_Console.setObjectName("pushButton_Console") self.horizontalLayout_5.addWidget(self.pushButton_Console) self.pushButton_Settings = QtWidgets.QPushButton(self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton_Settings.sizePolicy().hasHeightForWidth()) @@ -129,11 +128,11 @@ def setupUi(self, MainWindow): self.tableWidget_valuesearchtable = QtWidgets.QTableWidget(self.centralwidget) self.tableWidget_valuesearchtable.setEnabled(True) self.tableWidget_valuesearchtable.setAutoFillBackground(False) - self.tableWidget_valuesearchtable.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.tableWidget_valuesearchtable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableWidget_valuesearchtable.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.tableWidget_valuesearchtable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_valuesearchtable.setAlternatingRowColors(True) - self.tableWidget_valuesearchtable.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.tableWidget_valuesearchtable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_valuesearchtable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection) + self.tableWidget_valuesearchtable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_valuesearchtable.setShowGrid(False) self.tableWidget_valuesearchtable.setObjectName("tableWidget_valuesearchtable") self.tableWidget_valuesearchtable.setColumnCount(3) @@ -164,7 +163,7 @@ def setupUi(self, MainWindow): self.pushButton_NextScan = QtWidgets.QPushButton(self.QWidget_Toolbox) self.pushButton_NextScan.setObjectName("pushButton_NextScan") self.horizontalLayout_6.addWidget(self.pushButton_NextScan) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_6.addItem(spacerItem3) self.pushButton_UndoScan = QtWidgets.QPushButton(self.QWidget_Toolbox) self.pushButton_UndoScan.setObjectName("pushButton_UndoScan") @@ -176,7 +175,7 @@ def setupUi(self, MainWindow): self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_7.setObjectName("horizontalLayout_7") self.widget_3 = QtWidgets.QWidget(self.widget_Scan) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widget_3.sizePolicy().hasHeightForWidth()) @@ -239,7 +238,7 @@ def setupUi(self, MainWindow): self.comboBox_ScanScope.setObjectName("comboBox_ScanScope") self.horizontalLayout_10.addWidget(self.comboBox_ScanScope) self.verticalLayout_4.addLayout(self.horizontalLayout_10) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_4.addItem(spacerItem4) self.horizontalLayout_4.addWidget(self.widget) self.widget_2 = QtWidgets.QWidget(self.QWidget_Toolbox) @@ -270,7 +269,7 @@ def setupUi(self, MainWindow): self.verticalLayout.addWidget(self.checkBox_CaseSensitive) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") - spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_3.addItem(spacerItem5) self.checkBox_Unrandomizer = QtWidgets.QCheckBox(self.widget_2) self.checkBox_Unrandomizer.setEnabled(False) diff --git a/GUI/MemoryRegionsWidget.py b/GUI/MemoryRegionsWidget.py index dc3ffb09..2b36c88c 100644 --- a/GUI/MemoryRegionsWidget.py +++ b/GUI/MemoryRegionsWidget.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'MemoryRegionsWidget.ui' # -# Created: Fri Feb 24 20:41:26 2017 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -16,9 +16,9 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.tableWidget_MemoryRegions = QtWidgets.QTableWidget(Form) - self.tableWidget_MemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_MemoryRegions.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_MemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_MemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_MemoryRegions.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_MemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_MemoryRegions.setObjectName("tableWidget_MemoryRegions") self.tableWidget_MemoryRegions.setColumnCount(13) self.tableWidget_MemoryRegions.setRowCount(0) @@ -87,4 +87,3 @@ def retranslateUi(self, Form): item.setText(_translate("Form", "Anonymous")) item = self.tableWidget_MemoryRegions.horizontalHeaderItem(12) item.setText(_translate("Form", "Swap")) - diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 5b16a0c1..ca6caae4 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -1,14 +1,12 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'MemoryViewerWindow.ui' # -# Created by: PyQt5 UI code generator 5.15.7 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_MainWindow_MemoryView(object): @@ -23,13 +21,13 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_5.setObjectName("gridLayout_5") self.splitter_MainMiddle = QtWidgets.QSplitter(self.centralwidget) self.splitter_MainMiddle.setLineWidth(1) - self.splitter_MainMiddle.setOrientation(QtCore.Qt.Vertical) + self.splitter_MainMiddle.setOrientation(QtCore.Qt.Orientation.Vertical) self.splitter_MainMiddle.setOpaqueResize(True) self.splitter_MainMiddle.setHandleWidth(10) self.splitter_MainMiddle.setChildrenCollapsible(True) self.splitter_MainMiddle.setObjectName("splitter_MainMiddle") self.splitter_Disassemble_Registers = QtWidgets.QSplitter(self.splitter_MainMiddle) - self.splitter_Disassemble_Registers.setOrientation(QtCore.Qt.Horizontal) + self.splitter_Disassemble_Registers.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter_Disassemble_Registers.setHandleWidth(10) self.splitter_Disassemble_Registers.setObjectName("splitter_Disassemble_Registers") self.widget_Disassemble = QtWidgets.QWidget(self.splitter_Disassemble_Registers) @@ -42,12 +40,12 @@ def setupUi(self, MainWindow_MemoryView): font = QtGui.QFont() font.setPointSize(9) self.tableWidget_Disassemble.setFont(font) - self.tableWidget_Disassemble.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.tableWidget_Disassemble.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_Disassemble.setAutoScroll(False) - self.tableWidget_Disassemble.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableWidget_Disassemble.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Disassemble.setAlternatingRowColors(True) - self.tableWidget_Disassemble.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_Disassemble.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Disassemble.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_Disassemble.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Disassemble.setShowGrid(False) self.tableWidget_Disassemble.setObjectName("tableWidget_Disassemble") self.tableWidget_Disassemble.setColumnCount(4) @@ -67,7 +65,7 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_Disassemble.verticalHeader().setStretchLastSection(False) self.gridLayout_2.addWidget(self.tableWidget_Disassemble, 0, 0, 1, 1) self.verticalScrollBar_Disassemble = QtWidgets.QScrollBar(self.widget_Disassemble) - self.verticalScrollBar_Disassemble.setOrientation(QtCore.Qt.Vertical) + self.verticalScrollBar_Disassemble.setOrientation(QtCore.Qt.Orientation.Vertical) self.verticalScrollBar_Disassemble.setObjectName("verticalScrollBar_Disassemble") self.gridLayout_2.addWidget(self.verticalScrollBar_Disassemble, 0, 1, 1, 1) self.widget_Registers = QtWidgets.QWidget(self.splitter_Disassemble_Registers) @@ -100,12 +98,12 @@ def setupUi(self, MainWindow_MemoryView): self.label_3.setObjectName("label_3") self.verticalLayout_19.addWidget(self.label_3) self.line = QtWidgets.QFrame(self.scrollAreaWidgetContents_Registers) - self.line.setFrameShape(QtWidgets.QFrame.HLine) - self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line.setObjectName("line") self.verticalLayout_19.addWidget(self.line) self.stackedWidget = QtWidgets.QStackedWidget(self.scrollAreaWidgetContents_Registers) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.stackedWidget.sizePolicy().hasHeightForWidth()) @@ -177,7 +175,7 @@ def setupUi(self, MainWindow_MemoryView): self.RSP.setObjectName("RSP") self.verticalLayout_16.addWidget(self.RSP) self.horizontalLayout.addLayout(self.verticalLayout_16) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setSpacing(0) @@ -241,10 +239,10 @@ def setupUi(self, MainWindow_MemoryView): self.RIP.setFont(font) self.RIP.setObjectName("RIP") self.horizontalLayout_18.addWidget(self.RIP) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_18.addItem(spacerItem1) self.verticalLayout_17.addLayout(self.horizontalLayout_18) - spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_17.addItem(spacerItem2) self.gridLayout_7.addLayout(self.verticalLayout_17, 0, 0, 1, 1) self.stackedWidget.addWidget(self.registers_64) @@ -318,7 +316,7 @@ def setupUi(self, MainWindow_MemoryView): self.EIP.setObjectName("EIP") self.verticalLayout_2.addWidget(self.EIP) self.horizontalLayout_3.addLayout(self.verticalLayout_2) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem3) self.verticalLayout_14.addLayout(self.horizontalLayout_3) self.gridLayout_6.addLayout(self.verticalLayout_14, 0, 0, 1, 1) @@ -331,8 +329,8 @@ def setupUi(self, MainWindow_MemoryView): self.label_29.setObjectName("label_29") self.verticalLayout_19.addWidget(self.label_29) self.line_2 = QtWidgets.QFrame(self.scrollAreaWidgetContents_Registers) - self.line_2.setFrameShape(QtWidgets.QFrame.HLine) - self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_2.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_2.setObjectName("line_2") self.verticalLayout_19.addWidget(self.line_2) self.horizontalLayout_21 = QtWidgets.QHBoxLayout() @@ -483,7 +481,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_13.addWidget(self.OF) self.horizontalLayout_21.addLayout(self.verticalLayout_13) self.verticalLayout_19.addLayout(self.horizontalLayout_21) - spacerItem4 = QtWidgets.QSpacerItem(20, 15, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + spacerItem4 = QtWidgets.QSpacerItem(20, 15, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) self.verticalLayout_19.addItem(spacerItem4) self.label_30 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() @@ -492,8 +490,8 @@ def setupUi(self, MainWindow_MemoryView): self.label_30.setObjectName("label_30") self.verticalLayout_19.addWidget(self.label_30) self.line_3 = QtWidgets.QFrame(self.scrollAreaWidgetContents_Registers) - self.line_3.setFrameShape(QtWidgets.QFrame.HLine) - self.line_3.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_3.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_3.setObjectName("line_3") self.verticalLayout_19.addWidget(self.line_3) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() @@ -515,7 +513,7 @@ def setupUi(self, MainWindow_MemoryView): self.ES.setObjectName("ES") self.verticalLayout_4.addWidget(self.ES) self.horizontalLayout_2.addLayout(self.verticalLayout_4) - spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem5) self.verticalLayout_15 = QtWidgets.QVBoxLayout() self.verticalLayout_15.setSpacing(0) @@ -533,7 +531,7 @@ def setupUi(self, MainWindow_MemoryView): self.GS.setObjectName("GS") self.verticalLayout_15.addWidget(self.GS) self.horizontalLayout_2.addLayout(self.verticalLayout_15) - spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem6) self.verticalLayout_18 = QtWidgets.QVBoxLayout() self.verticalLayout_18.setSpacing(0) @@ -558,16 +556,16 @@ def setupUi(self, MainWindow_MemoryView): self.pushButton_ShowFloatRegisters.setFont(font) self.pushButton_ShowFloatRegisters.setObjectName("pushButton_ShowFloatRegisters") self.verticalLayout_19.addWidget(self.pushButton_ShowFloatRegisters) - spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_19.addItem(spacerItem7) self.horizontalLayout_4.addLayout(self.verticalLayout_19) - spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_4.addItem(spacerItem8) self.gridLayout_8.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) self.scrollArea_Registers.setWidget(self.scrollAreaWidgetContents_Registers) self.gridLayout_4.addWidget(self.scrollArea_Registers, 0, 0, 1, 1) self.splitter_HexView_StackView = QtWidgets.QSplitter(self.splitter_MainMiddle) - self.splitter_HexView_StackView.setOrientation(QtCore.Qt.Horizontal) + self.splitter_HexView_StackView.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter_HexView_StackView.setHandleWidth(10) self.splitter_HexView_StackView.setObjectName("splitter_HexView_StackView") self.widget_HexView = QtWidgets.QWidget(self.splitter_HexView_StackView) @@ -591,9 +589,9 @@ def setupUi(self, MainWindow_MemoryView): self.horizontalLayout_5.setSpacing(0) self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.tableWidget_HexView_Address = QtWidgets.QTableWidget(self.scrollAreaWidgetContents_2) - self.tableWidget_HexView_Address.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_HexView_Address.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_HexView_Address.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_HexView_Address.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_HexView_Address.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_HexView_Address.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_HexView_Address.setShowGrid(False) self.tableWidget_HexView_Address.setObjectName("tableWidget_HexView_Address") self.tableWidget_HexView_Address.setColumnCount(1) @@ -604,24 +602,24 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_HexView_Address.verticalHeader().setVisible(False) self.horizontalLayout_5.addWidget(self.tableWidget_HexView_Address) self.line_5 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) - self.line_5.setFrameShape(QtWidgets.QFrame.VLine) - self.line_5.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_5.setFrameShape(QtWidgets.QFrame.Shape.VLine) + self.line_5.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_5.setObjectName("line_5") self.horizontalLayout_5.addWidget(self.line_5) self.tableView_HexView_Hex = QHexView(self.scrollAreaWidgetContents_2) - self.tableView_HexView_Hex.setTextElideMode(QtCore.Qt.ElideNone) + self.tableView_HexView_Hex.setTextElideMode(QtCore.Qt.TextElideMode.ElideNone) self.tableView_HexView_Hex.setObjectName("tableView_HexView_Hex") self.horizontalLayout_5.addWidget(self.tableView_HexView_Hex) self.line_4 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) - self.line_4.setFrameShape(QtWidgets.QFrame.VLine) - self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_4.setFrameShape(QtWidgets.QFrame.Shape.VLine) + self.line_4.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_4.setObjectName("line_4") self.horizontalLayout_5.addWidget(self.line_4) self.tableView_HexView_Ascii = QAsciiView(self.scrollAreaWidgetContents_2) - self.tableView_HexView_Ascii.setTextElideMode(QtCore.Qt.ElideNone) + self.tableView_HexView_Ascii.setTextElideMode(QtCore.Qt.TextElideMode.ElideNone) self.tableView_HexView_Ascii.setObjectName("tableView_HexView_Ascii") self.horizontalLayout_5.addWidget(self.tableView_HexView_Ascii) - spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_5.addItem(spacerItem9) self.gridLayout_11.addLayout(self.horizontalLayout_5, 2, 0, 1, 1) self.label_HexView_Information = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) @@ -629,8 +627,8 @@ def setupUi(self, MainWindow_MemoryView): self.label_HexView_Information.setObjectName("label_HexView_Information") self.gridLayout_11.addWidget(self.label_HexView_Information, 0, 0, 1, 1) self.line_6 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) - self.line_6.setFrameShape(QtWidgets.QFrame.HLine) - self.line_6.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line_6.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_6.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_6.setObjectName("line_6") self.gridLayout_11.addWidget(self.line_6, 1, 0, 1, 1) self.label_HexView_Information.raise_() @@ -638,7 +636,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Hex.setWidget(self.scrollAreaWidgetContents_2) self.gridLayout.addWidget(self.scrollArea_Hex, 0, 0, 1, 1) self.verticalScrollBar_HexView = QtWidgets.QScrollBar(self.widget_HexView) - self.verticalScrollBar_HexView.setOrientation(QtCore.Qt.Vertical) + self.verticalScrollBar_HexView.setOrientation(QtCore.Qt.Orientation.Vertical) self.verticalScrollBar_HexView.setObjectName("verticalScrollBar_HexView") self.gridLayout.addWidget(self.verticalScrollBar_HexView, 0, 1, 1, 1) self.widget_StackView = QtWidgets.QWidget(self.splitter_HexView_StackView) @@ -659,9 +657,9 @@ def setupUi(self, MainWindow_MemoryView): font = QtGui.QFont() font.setPointSize(9) self.tableWidget_StackTrace.setFont(font) - self.tableWidget_StackTrace.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_StackTrace.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_StackTrace.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_StackTrace.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_StackTrace.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_StackTrace.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_StackTrace.setObjectName("tableWidget_StackTrace") self.tableWidget_StackTrace.setColumnCount(2) self.tableWidget_StackTrace.setRowCount(0) @@ -685,9 +683,9 @@ def setupUi(self, MainWindow_MemoryView): font = QtGui.QFont() font.setPointSize(9) self.tableWidget_Stack.setFont(font) - self.tableWidget_Stack.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_Stack.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_Stack.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Stack.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_Stack.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_Stack.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Stack.setObjectName("tableWidget_Stack") self.tableWidget_Stack.setColumnCount(3) self.tableWidget_Stack.setRowCount(0) @@ -723,51 +721,51 @@ def setupUi(self, MainWindow_MemoryView): self.statusbar = QtWidgets.QStatusBar(MainWindow_MemoryView) self.statusbar.setObjectName("statusbar") MainWindow_MemoryView.setStatusBar(self.statusbar) - self.actionBookmarks = QtWidgets.QAction(MainWindow_MemoryView) + self.actionBookmarks = QtGui.QAction(MainWindow_MemoryView) self.actionBookmarks.setObjectName("actionBookmarks") - self.actionStackTrace_Info = QtWidgets.QAction(MainWindow_MemoryView) + self.actionStackTrace_Info = QtGui.QAction(MainWindow_MemoryView) self.actionStackTrace_Info.setObjectName("actionStackTrace_Info") - self.actionInject_so_file = QtWidgets.QAction(MainWindow_MemoryView) + self.actionInject_so_file = QtGui.QAction(MainWindow_MemoryView) self.actionInject_so_file.setObjectName("actionInject_so_file") - self.actionRun = QtWidgets.QAction(MainWindow_MemoryView) + self.actionRun = QtGui.QAction(MainWindow_MemoryView) self.actionRun.setObjectName("actionRun") - self.actionBreak = QtWidgets.QAction(MainWindow_MemoryView) + self.actionBreak = QtGui.QAction(MainWindow_MemoryView) self.actionBreak.setObjectName("actionBreak") - self.actionStep = QtWidgets.QAction(MainWindow_MemoryView) + self.actionStep = QtGui.QAction(MainWindow_MemoryView) self.actionStep.setObjectName("actionStep") - self.actionStep_Over = QtWidgets.QAction(MainWindow_MemoryView) + self.actionStep_Over = QtGui.QAction(MainWindow_MemoryView) self.actionStep_Over.setObjectName("actionStep_Over") - self.actionExecute_Till_Return = QtWidgets.QAction(MainWindow_MemoryView) + self.actionExecute_Till_Return = QtGui.QAction(MainWindow_MemoryView) self.actionExecute_Till_Return.setObjectName("actionExecute_Till_Return") - self.actionToggle_Breakpoint = QtWidgets.QAction(MainWindow_MemoryView) + self.actionToggle_Breakpoint = QtGui.QAction(MainWindow_MemoryView) self.actionToggle_Breakpoint.setObjectName("actionToggle_Breakpoint") - self.actionBreakpoints = QtWidgets.QAction(MainWindow_MemoryView) + self.actionBreakpoints = QtGui.QAction(MainWindow_MemoryView) self.actionBreakpoints.setObjectName("actionBreakpoints") - self.actionFunctions = QtWidgets.QAction(MainWindow_MemoryView) + self.actionFunctions = QtGui.QAction(MainWindow_MemoryView) self.actionFunctions.setObjectName("actionFunctions") - self.actionSet_Address = QtWidgets.QAction(MainWindow_MemoryView) + self.actionSet_Address = QtGui.QAction(MainWindow_MemoryView) self.actionSet_Address.setObjectName("actionSet_Address") - self.actionCall_Function = QtWidgets.QAction(MainWindow_MemoryView) + self.actionCall_Function = QtGui.QAction(MainWindow_MemoryView) self.actionCall_Function.setObjectName("actionCall_Function") - self.actionLoad_Trace = QtWidgets.QAction(MainWindow_MemoryView) + self.actionLoad_Trace = QtGui.QAction(MainWindow_MemoryView) self.actionLoad_Trace.setObjectName("actionLoad_Trace") - self.actionlibpince = QtWidgets.QAction(MainWindow_MemoryView) + self.actionlibpince = QtGui.QAction(MainWindow_MemoryView) self.actionlibpince.setObjectName("actionlibpince") - self.actionGDB_Log_File = QtWidgets.QAction(MainWindow_MemoryView) + self.actionGDB_Log_File = QtGui.QAction(MainWindow_MemoryView) self.actionGDB_Log_File.setObjectName("actionGDB_Log_File") - self.actionSearch_Opcode = QtWidgets.QAction(MainWindow_MemoryView) + self.actionSearch_Opcode = QtGui.QAction(MainWindow_MemoryView) self.actionSearch_Opcode.setObjectName("actionSearch_Opcode") - self.actionMemory_Regions = QtWidgets.QAction(MainWindow_MemoryView) + self.actionMemory_Regions = QtGui.QAction(MainWindow_MemoryView) self.actionMemory_Regions.setObjectName("actionMemory_Regions") - self.actionDissect_Code = QtWidgets.QAction(MainWindow_MemoryView) + self.actionDissect_Code = QtGui.QAction(MainWindow_MemoryView) self.actionDissect_Code.setObjectName("actionDissect_Code") - self.actionReferenced_Strings = QtWidgets.QAction(MainWindow_MemoryView) + self.actionReferenced_Strings = QtGui.QAction(MainWindow_MemoryView) self.actionReferenced_Strings.setObjectName("actionReferenced_Strings") - self.actionReferenced_Calls = QtWidgets.QAction(MainWindow_MemoryView) + self.actionReferenced_Calls = QtGui.QAction(MainWindow_MemoryView) self.actionReferenced_Calls.setObjectName("actionReferenced_Calls") - self.actionToggle_Attach = QtWidgets.QAction(MainWindow_MemoryView) + self.actionToggle_Attach = QtGui.QAction(MainWindow_MemoryView) self.actionToggle_Attach.setObjectName("actionToggle_Attach") - self.actionRestore_Instructions = QtWidgets.QAction(MainWindow_MemoryView) + self.actionRestore_Instructions = QtGui.QAction(MainWindow_MemoryView) self.actionRestore_Instructions.setObjectName("actionRestore_Instructions") self.menuView.addAction(self.actionBookmarks) self.menuView.addAction(self.actionStackTrace_Info) diff --git a/GUI/ReferencedCallsWidget.py b/GUI/ReferencedCallsWidget.py index bfb8539e..9a5dc757 100644 --- a/GUI/ReferencedCallsWidget.py +++ b/GUI/ReferencedCallsWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'ReferencedCallsWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -16,11 +17,12 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.splitter = QtWidgets.QSplitter(Form) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.layoutWidget = QtWidgets.QWidget(self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") @@ -38,9 +40,9 @@ def setupUi(self, Form): self.horizontalLayout_2.addWidget(self.pushButton_Search) self.verticalLayout.addLayout(self.horizontalLayout_2) self.tableWidget_References = QtWidgets.QTableWidget(self.layoutWidget) - self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_References.setObjectName("tableWidget_References") self.tableWidget_References.setColumnCount(2) self.tableWidget_References.setRowCount(0) @@ -54,7 +56,7 @@ def setupUi(self, Form): self.tableWidget_References.verticalHeader().setMinimumSectionSize(16) self.verticalLayout.addWidget(self.tableWidget_References) self.listWidget_Referrers = QtWidgets.QListWidget(self.splitter) - self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.listWidget_Referrers.setObjectName("listWidget_Referrers") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) @@ -75,4 +77,3 @@ def retranslateUi(self, Form): item.setText(_translate("Form", "Address")) item = self.tableWidget_References.horizontalHeaderItem(1) item.setText(_translate("Form", "Refcount")) - diff --git a/GUI/ReferencedStringsWidget.py b/GUI/ReferencedStringsWidget.py index 2aa8ba7e..e451ebfa 100644 --- a/GUI/ReferencedStringsWidget.py +++ b/GUI/ReferencedStringsWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'ReferencedStringsWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -16,11 +17,12 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.splitter = QtWidgets.QSplitter(Form) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.layoutWidget = QtWidgets.QWidget(self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") @@ -38,9 +40,9 @@ def setupUi(self, Form): self.horizontalLayout_2.addWidget(self.pushButton_Search) self.verticalLayout.addLayout(self.horizontalLayout_2) self.tableWidget_References = QtWidgets.QTableWidget(self.layoutWidget) - self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_References.setObjectName("tableWidget_References") self.tableWidget_References.setColumnCount(3) self.tableWidget_References.setRowCount(0) @@ -57,15 +59,15 @@ def setupUi(self, Form): self.verticalLayout.addWidget(self.tableWidget_References) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) self.comboBox_ValueType = QtWidgets.QComboBox(self.layoutWidget) - self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout.addWidget(self.comboBox_ValueType) self.verticalLayout.addLayout(self.horizontalLayout) self.listWidget_Referrers = QtWidgets.QListWidget(self.splitter) - self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.listWidget_Referrers.setObjectName("listWidget_Referrers") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) @@ -89,4 +91,3 @@ def retranslateUi(self, Form): item.setText(_translate("Form", "Refcount")) item = self.tableWidget_References.horizontalHeaderItem(2) item.setText(_translate("Form", "Value")) - diff --git a/GUI/RestoreInstructionsWidget.py b/GUI/RestoreInstructionsWidget.py index 1501dee7..4e7ad335 100644 --- a/GUI/RestoreInstructionsWidget.py +++ b/GUI/RestoreInstructionsWidget.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'RestoreInstructionsWidget.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Form(object): @@ -17,9 +16,9 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.tableWidget_Instructions = QtWidgets.QTableWidget(Form) - self.tableWidget_Instructions.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_Instructions.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_Instructions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Instructions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_Instructions.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_Instructions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Instructions.setObjectName("tableWidget_Instructions") self.tableWidget_Instructions.setColumnCount(2) self.tableWidget_Instructions.setRowCount(0) diff --git a/GUI/SearchOpcodeWidget.py b/GUI/SearchOpcodeWidget.py index 9a71efdd..a72b0391 100644 --- a/GUI/SearchOpcodeWidget.py +++ b/GUI/SearchOpcodeWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'SearchOpcodeWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -52,9 +53,9 @@ def setupUi(self, Form): self.horizontalLayout.addWidget(self.lineEdit_End) self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) self.tableWidget_Opcodes = QtWidgets.QTableWidget(Form) - self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Opcodes.setObjectName("tableWidget_Opcodes") self.tableWidget_Opcodes.setColumnCount(2) self.tableWidget_Opcodes.setRowCount(0) @@ -88,4 +89,3 @@ def retranslateUi(self, Form): item.setText(_translate("Form", "Address")) item = self.tableWidget_Opcodes.horizontalHeaderItem(1) item.setText(_translate("Form", "Opcodes")) - diff --git a/GUI/SelectProcess.py b/GUI/SelectProcess.py index 30f9f3fb..739b9128 100644 --- a/GUI/SelectProcess.py +++ b/GUI/SelectProcess.py @@ -1,17 +1,18 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'SelectProcess.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.setWindowModality(QtCore.Qt.WindowModal) + MainWindow.setWindowModality(QtCore.Qt.WindowModality.WindowModal) MainWindow.resize(443, 420) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") @@ -27,16 +28,16 @@ def setupUi(self, MainWindow): self.horizontalLayout.addWidget(self.lineEdit_SearchProcess) self.verticalLayout.addLayout(self.horizontalLayout) self.tableWidget_ProcessTable = QtWidgets.QTableWidget(self.centralwidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.tableWidget_ProcessTable.sizePolicy().hasHeightForWidth()) self.tableWidget_ProcessTable.setSizePolicy(sizePolicy) self.tableWidget_ProcessTable.setAutoFillBackground(False) - self.tableWidget_ProcessTable.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) - self.tableWidget_ProcessTable.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_ProcessTable.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_ProcessTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_ProcessTable.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored) + self.tableWidget_ProcessTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_ProcessTable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_ProcessTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_ProcessTable.setObjectName("tableWidget_ProcessTable") self.tableWidget_ProcessTable.setColumnCount(3) self.tableWidget_ProcessTable.setRowCount(0) @@ -45,7 +46,7 @@ def setupUi(self, MainWindow): item = QtWidgets.QTableWidgetItem() self.tableWidget_ProcessTable.setHorizontalHeaderItem(1, item) item = QtWidgets.QTableWidgetItem() - item.setTextAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignVCenter) + item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter) self.tableWidget_ProcessTable.setHorizontalHeaderItem(2, item) self.tableWidget_ProcessTable.horizontalHeader().setDefaultSectionSize(70) self.tableWidget_ProcessTable.horizontalHeader().setStretchLastSection(True) @@ -54,7 +55,7 @@ def setupUi(self, MainWindow): self.verticalLayout.addWidget(self.tableWidget_ProcessTable) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem) self.pushButton_Open = QtWidgets.QPushButton(self.centralwidget) self.pushButton_Open.setObjectName("pushButton_Open") @@ -62,17 +63,17 @@ def setupUi(self, MainWindow): self.pushButton_Close = QtWidgets.QPushButton(self.centralwidget) self.pushButton_Close.setObjectName("pushButton_Close") self.horizontalLayout_2.addWidget(self.pushButton_Close) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem1) self.verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem2) self.pushButton_CreateProcess = QtWidgets.QPushButton(self.centralwidget) self.pushButton_CreateProcess.setObjectName("pushButton_CreateProcess") self.horizontalLayout_3.addWidget(self.pushButton_CreateProcess) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem3) self.verticalLayout.addLayout(self.horizontalLayout_3) MainWindow.setCentralWidget(self.centralwidget) @@ -96,4 +97,3 @@ def retranslateUi(self, MainWindow): self.pushButton_Close.setText(_translate("MainWindow", "Cancel")) self.pushButton_CreateProcess.setToolTip(_translate("MainWindow", "Open an executable")) self.pushButton_CreateProcess.setText(_translate("MainWindow", "Create Process[F1]")) - diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index e5caed2a..46065b61 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'SettingsDialog.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): @@ -21,7 +20,7 @@ def setupUi(self, Dialog): self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.listWidget_Options = QtWidgets.QListWidget(Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.listWidget_Options.sizePolicy().hasHeightForWidth()) @@ -81,7 +80,7 @@ def setupUi(self, Dialog): self.horizontalLayout_14.setContentsMargins(-1, 0, -1, -1) self.horizontalLayout_14.setObjectName("horizontalLayout_14") self.label_12 = QtWidgets.QLabel(self.LockInterval) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_12.sizePolicy().hasHeightForWidth()) @@ -91,7 +90,7 @@ def setupUi(self, Dialog): self.label_12.setObjectName("label_12") self.horizontalLayout_14.addWidget(self.label_12) self.lineEdit_FreezeInterval = QtWidgets.QLineEdit(self.LockInterval) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_FreezeInterval.sizePolicy().hasHeightForWidth()) @@ -104,7 +103,7 @@ def setupUi(self, Dialog): self.horizontalLayout_14.addWidget(self.label_10) self.verticalLayout_3.addWidget(self.LockInterval) self.horizontalLayout_7.addLayout(self.verticalLayout_3) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_7.addItem(spacerItem) self.verticalLayout_5.addLayout(self.horizontalLayout_7) self.checkBox_MessageBoxOnException = QtWidgets.QCheckBox(self.page) @@ -132,7 +131,7 @@ def setupUi(self, Dialog): self.checkBox_OutputModeCommandInfo.setChecked(True) self.checkBox_OutputModeCommandInfo.setObjectName("checkBox_OutputModeCommandInfo") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeCommandInfo) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem1) self.verticalLayout_5.addLayout(self.horizontalLayout_3) self.horizontalLayout_12 = QtWidgets.QHBoxLayout() @@ -156,10 +155,10 @@ def setupUi(self, Dialog): self.comboBox_Logo = QtWidgets.QComboBox(self.page) self.comboBox_Logo.setObjectName("comboBox_Logo") self.horizontalLayout_15.addWidget(self.comboBox_Logo) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_15.addItem(spacerItem2) self.verticalLayout_5.addLayout(self.horizontalLayout_15) - spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_5.addItem(spacerItem3) self.gridLayout_2.addLayout(self.verticalLayout_5, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page) @@ -188,13 +187,13 @@ def setupUi(self, Dialog): self.verticalLayout_6.addLayout(self.verticalLayout_Hotkey) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_4.addItem(spacerItem4) self.pushButton_ClearHotkey = QtWidgets.QPushButton(self.page_2) self.pushButton_ClearHotkey.setObjectName("pushButton_ClearHotkey") self.horizontalLayout_4.addWidget(self.pushButton_ClearHotkey) self.verticalLayout_6.addLayout(self.horizontalLayout_4) - spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_6.addItem(spacerItem5) self.horizontalLayout_5.addLayout(self.verticalLayout_6) self.gridLayout_3.addLayout(self.horizontalLayout_5, 0, 0, 1, 1) @@ -214,7 +213,7 @@ def setupUi(self, Dialog): self.verticalLayout_8.addWidget(self.label_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") - spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_6.addItem(spacerItem6) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setObjectName("verticalLayout_7") @@ -229,10 +228,10 @@ def setupUi(self, Dialog): self.horizontalLayout_6.addLayout(self.verticalLayout_7) self.verticalLayout_8.addLayout(self.horizontalLayout_6) self.horizontalLayout_8.addLayout(self.verticalLayout_8) - spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem7) self.verticalLayout_9.addLayout(self.horizontalLayout_8) - spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_9.addItem(spacerItem8) self.gridLayout_4.addLayout(self.verticalLayout_9, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_3) @@ -257,10 +256,10 @@ def setupUi(self, Dialog): self.lineEdit_InstructionsPerScroll.setObjectName("lineEdit_InstructionsPerScroll") self.horizontalLayout_9.addWidget(self.lineEdit_InstructionsPerScroll) self.horizontalLayout_10.addLayout(self.horizontalLayout_9) - spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_10.addItem(spacerItem9) self.verticalLayout_10.addLayout(self.horizontalLayout_10) - spacerItem10 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem10 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_10.addItem(spacerItem10) self.gridLayout_5.addLayout(self.verticalLayout_10, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_4) @@ -294,10 +293,10 @@ def setupUi(self, Dialog): self.pushButton_HandleSignals = QtWidgets.QPushButton(self.page_5) self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) - spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_16.addItem(spacerItem11) self.verticalLayout_11.addLayout(self.horizontalLayout_16) - spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_11.addItem(spacerItem12) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) @@ -308,11 +307,11 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem13) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.horizontalLayout.addWidget(self.buttonBox) self.verticalLayout.addLayout(self.horizontalLayout) @@ -321,8 +320,8 @@ def setupUi(self, Dialog): self.retranslateUi(Dialog) self.stackedWidget.setCurrentIndex(0) self.listWidget_Functions.setCurrentRow(-1) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): diff --git a/GUI/StackTraceInfoWidget.py b/GUI/StackTraceInfoWidget.py index e9877bcc..b923e7a1 100644 --- a/GUI/StackTraceInfoWidget.py +++ b/GUI/StackTraceInfoWidget.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'stacktraceinfowidget.ui' +# Form implementation generated from reading ui file 'StackTraceInfoWidget.ui' # -# Created: Tue Jul 26 21:56:27 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -16,7 +16,7 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.splitter = QtWidgets.QSplitter(Form) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.widget = QtWidgets.QWidget(self.splitter) self.widget.setObjectName("widget") @@ -50,4 +50,3 @@ def retranslateUi(self, Form): Form.setWindowTitle(_translate("Form", "StackTrace Information")) self.label.setText(_translate("Form", "Return Address")) self.label_2.setText(_translate("Form", "Info")) - diff --git a/GUI/TextEditDialog.py b/GUI/TextEditDialog.py index 332de62c..32741a5d 100644 --- a/GUI/TextEditDialog.py +++ b/GUI/TextEditDialog.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'TextEditDialog.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): @@ -18,18 +19,17 @@ def setupUi(self, Dialog): self.textEdit.setObjectName("textEdit") self.gridLayout.addWidget(self.textEdit, 0, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) self.retranslateUi(Dialog) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.textEdit.setPlaceholderText(_translate("Dialog", "Hit Esc to cancel and Ctrl+Enter to accept")) - diff --git a/GUI/TraceInstructionsPromptDialog.py b/GUI/TraceInstructionsPromptDialog.py index 4d0dd8d6..a35b47bc 100644 --- a/GUI/TraceInstructionsPromptDialog.py +++ b/GUI/TraceInstructionsPromptDialog.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'TraceInstructionsPromptDialog.ui' # -# Created: Tue Jan 10 18:45:42 2017 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): @@ -58,15 +58,15 @@ def setupUi(self, Dialog): self.checkBox_FloatRegisters.setObjectName("checkBox_FloatRegisters") self.verticalLayout.addWidget(self.checkBox_FloatRegisters) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) self.retranslateUi(Dialog) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): @@ -85,4 +85,3 @@ def retranslateUi(self, Dialog): self.checkBox_FlagRegisters.setText(_translate("Dialog", "Collect flag registers")) self.checkBox_SegmentRegisters.setText(_translate("Dialog", "Collect segment registers")) self.checkBox_FloatRegisters.setText(_translate("Dialog", "Collect float registers")) - diff --git a/GUI/TraceInstructionsWaitWidget.py b/GUI/TraceInstructionsWaitWidget.py index c3dfc3cf..36e20d81 100644 --- a/GUI/TraceInstructionsWaitWidget.py +++ b/GUI/TraceInstructionsWaitWidget.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'TraceInstructionsWaitWidget.ui' # -# Created: Sun Dec 25 15:05:53 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -23,17 +23,17 @@ def setupUi(self, Form): self.verticalLayout.addWidget(self.label_Animated) self.label_StatusText = QtWidgets.QLabel(Form) self.label_StatusText.setText("") - self.label_StatusText.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) + self.label_StatusText.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_StatusText.setObjectName("label_StatusText") self.verticalLayout.addWidget(self.label_StatusText) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) self.pushButton_Cancel = QtWidgets.QPushButton(Form) self.pushButton_Cancel.setObjectName("pushButton_Cancel") self.horizontalLayout.addWidget(self.pushButton_Cancel) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.verticalLayout.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) @@ -45,4 +45,3 @@ def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) self.pushButton_Cancel.setText(_translate("Form", "Cancel")) - diff --git a/GUI/TraceInstructionsWindow.py b/GUI/TraceInstructionsWindow.py index 59ac231d..3d422800 100644 --- a/GUI/TraceInstructionsWindow.py +++ b/GUI/TraceInstructionsWindow.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'TraceInstructionsWindow.ui' # -# Created: Mon Jan 16 19:23:48 2017 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): @@ -18,10 +18,10 @@ def setupUi(self, MainWindow): self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.splitter = QtWidgets.QSplitter(self.centralwidget) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.treeWidget_InstructionInfo = QtWidgets.QTreeWidget(self.splitter) - self.treeWidget_InstructionInfo.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.treeWidget_InstructionInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.treeWidget_InstructionInfo.setObjectName("treeWidget_InstructionInfo") self.treeWidget_InstructionInfo.headerItem().setText(0, "1") self.treeWidget_InstructionInfo.header().setVisible(False) @@ -38,11 +38,11 @@ def setupUi(self, MainWindow): self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) - self.actionOpen = QtWidgets.QAction(MainWindow) + self.actionOpen = QtGui.QAction(MainWindow) self.actionOpen.setObjectName("actionOpen") - self.actionSave = QtWidgets.QAction(MainWindow) + self.actionSave = QtGui.QAction(MainWindow) self.actionSave.setObjectName("actionSave") - self.actionSave_as_a_text_file = QtWidgets.QAction(MainWindow) + self.actionSave_as_a_text_file = QtGui.QAction(MainWindow) self.actionSave_as_a_text_file.setObjectName("actionSave_as_a_text_file") self.menuFile.addAction(self.actionOpen) self.menuFile.addAction(self.actionSave) @@ -58,4 +58,3 @@ def retranslateUi(self, MainWindow): self.actionOpen.setText(_translate("MainWindow", "Open")) self.actionSave.setText(_translate("MainWindow", "Save")) self.actionSave_as_a_text_file.setText(_translate("MainWindow", "Save as a text file")) - diff --git a/GUI/TrackBreakpointWidget.py b/GUI/TrackBreakpointWidget.py index 26dd6cd1..f4204b86 100644 --- a/GUI/TrackBreakpointWidget.py +++ b/GUI/TrackBreakpointWidget.py @@ -1,12 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'TrackBreakpointWidget.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -19,18 +20,18 @@ def setupUi(self, Form): self.pushButton_Stop = QtWidgets.QPushButton(Form) self.pushButton_Stop.setObjectName("pushButton_Stop") self.horizontalLayout.addWidget(self.pushButton_Stop) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) self.comboBox_ValueType = QtWidgets.QComboBox(Form) self.comboBox_ValueType.setToolTip("") - self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) + self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout.addWidget(self.comboBox_ValueType) self.gridLayout.addLayout(self.horizontalLayout, 3, 0, 1, 1) self.tableWidget_TrackInfo = QtWidgets.QTableWidget(Form) - self.tableWidget_TrackInfo.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_TrackInfo.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_TrackInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_TrackInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_TrackInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_TrackInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_TrackInfo.setObjectName("tableWidget_TrackInfo") self.tableWidget_TrackInfo.setColumnCount(4) self.tableWidget_TrackInfo.setRowCount(0) @@ -49,11 +50,11 @@ def setupUi(self, Form): self.gridLayout.addWidget(self.tableWidget_TrackInfo, 0, 0, 1, 1) self.label_Info = QtWidgets.QLabel(Form) self.label_Info.setText("") - self.label_Info.setAlignment(QtCore.Qt.AlignCenter) + self.label_Info.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_Info.setObjectName("label_Info") self.gridLayout.addWidget(self.label_Info, 1, 0, 1, 1) self.label_AdditionalInfo = QtWidgets.QLabel(Form) - self.label_AdditionalInfo.setAlignment(QtCore.Qt.AlignCenter) + self.label_AdditionalInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_AdditionalInfo.setObjectName("label_AdditionalInfo") self.gridLayout.addWidget(self.label_AdditionalInfo, 2, 0, 1, 1) @@ -74,4 +75,3 @@ def retranslateUi(self, Form): item = self.tableWidget_TrackInfo.horizontalHeaderItem(3) item.setText(_translate("Form", "Source")) self.label_AdditionalInfo.setText(_translate("Form", "Try changing combobox index if the \'Value\' part of table still isn\'t updated")) - diff --git a/GUI/TrackWatchpointWidget.py b/GUI/TrackWatchpointWidget.py index 7791008d..08de4097 100644 --- a/GUI/TrackWatchpointWidget.py +++ b/GUI/TrackWatchpointWidget.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'TrackWatchpointWidget.ui' # -# Created: Fri Dec 2 21:30:54 2016 -# by: PyQt5 UI code generator 5.2.1 +# Created by: PyQt6 UI code generator 6.3.1 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): @@ -16,10 +16,10 @@ def setupUi(self, Form): self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.splitter_2 = QtWidgets.QSplitter(Form) - self.splitter_2.setOrientation(QtCore.Qt.Vertical) + self.splitter_2.setOrientation(QtCore.Qt.Orientation.Vertical) self.splitter_2.setObjectName("splitter_2") self.splitter = QtWidgets.QSplitter(self.splitter_2) - self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.layoutWidget = QtWidgets.QWidget(self.splitter) self.layoutWidget.setObjectName("layoutWidget") @@ -27,9 +27,9 @@ def setupUi(self, Form): self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.tableWidget_Opcodes = QtWidgets.QTableWidget(self.layoutWidget) - self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Opcodes.setObjectName("tableWidget_Opcodes") self.tableWidget_Opcodes.setColumnCount(2) self.tableWidget_Opcodes.setRowCount(0) @@ -69,4 +69,3 @@ def retranslateUi(self, Form): item.setText(_translate("Form", "Address")) self.pushButton_Refresh.setText(_translate("Form", "Refresh")) self.pushButton_Stop.setText(_translate("Form", "Stop")) - diff --git a/PINCE.py b/PINCE.py index e01c8969..b6e01b4f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -18,14 +18,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt5.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ - QKeyEvent, QRegExpValidator -from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, \ - QShortcut, QKeySequenceEdit, QTabWidget, QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, \ +from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ + QKeyEvent, QRegularExpressionValidator, QShortcut, QColorConstants +from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, \ + QKeySequenceEdit, QTabWidget, QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, \ QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, \ QPushButton, QFrame -from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, \ - QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegExp, QRunnable, QThreadPool, pyqtSlot +from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, \ + QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QThreadPool, pyqtSlot from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, psutil, pexpect @@ -159,11 +159,11 @@ def get_hotkeys(): BREAK_COND_COL = 8 # row colours for disassemble qtablewidget -PC_COLOUR = Qt.blue -BOOKMARK_COLOUR = Qt.cyan -DEFAULT_COLOUR = Qt.white -BREAKPOINT_COLOUR = Qt.red -REF_COLOUR = Qt.lightGray +PC_COLOUR = QColorConstants.Blue +BOOKMARK_COLOUR = QColorConstants.Cyan +DEFAULT_COLOUR = QColorConstants.White +BREAKPOINT_COLOUR = QColorConstants.Red +REF_COLOUR = QColorConstants.LightGray # represents the index of columns in address table FROZEN_COL = 0 # Frozen @@ -286,7 +286,7 @@ def except_hook(exception_type, value, tb): error_dialog = InputDialogForm(item_list=[( "Process is running" + "\nPress " + Hotkeys.break_hotkey.get_active_key() + " to stop process" + "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.Ok]) - error_dialog.exec_() + error_dialog.exec() traceback.print_exception(exception_type, value, tb) @@ -377,7 +377,7 @@ def __init__(self): app.setOrganizationName("PINCE") app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") app.setApplicationName("PINCE") - QSettings.setPath(QSettings.NativeFormat, QSettings.UserScope, + QSettings.setPath(QSettings.Format.NativeFormat, QSettings.Scope.UserScope, SysUtils.get_user_path(type_defs.USER_PATHS.CONFIG_PATH)) self.settings = QSettings() if not SysUtils.is_path_valid(self.settings.fileName()): @@ -403,7 +403,7 @@ def __init__(self): text = "Unable to initialize GDB\n" \ "You might want to reinstall GDB or use the system GDB\n" \ "To change the current GDB path, check Settings->Debug" - InputDialogForm(item_list=[(text, None)], buttons=[QDialogButtonBox.Ok]).exec_() + InputDialogForm(item_list=[(text, None)], buttons=[QDialogButtonBox.Ok]).exec() else: self.apply_after_init() # this should be changed, only works if you use the current directory, fails if you for example install it to some place like bin @@ -449,8 +449,8 @@ def __init__(self): self.comboBox_ValueType_init() self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) - self.lineEdit_Scan.setValidator(QRegExpValidator(QRegExp("-?[0-9]*"), parent=self.lineEdit_Scan)) - self.lineEdit_Scan2.setValidator(QRegExpValidator(QRegExp("-?[0-9]*"), parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.setValidator(QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan)) + self.lineEdit_Scan2.setValidator(QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan2)) self.comboBox_ScanType.currentIndexChanged.connect(self.comboBox_ScanType_current_index_changed) self.comboBox_ScanType_current_index_changed() self.pushButton_Settings.clicked.connect(self.pushButton_Settings_clicked) @@ -625,7 +625,7 @@ def toggle_attach_hotkey_pressed(self): if show_messagebox_on_toggle_attach: dialog = InputDialogForm(item_list=[( dialog_text + "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.Ok]) - dialog.exec_() + dialog.exec() def treeWidget_AddressTable_context_menu_event(self, event): current_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) @@ -666,7 +666,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): what_accesses] GuiUtils.delete_menu_entries(menu, deletion_list) else: - value_type = current_row.data(TYPE_COL, Qt.UserRole) + value_type = current_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) if type_defs.VALUE_INDEX.is_integer(value_type.value_index): if value_type.value_repr is type_defs.VALUE_REPR.HEX: GuiUtils.delete_menu_entries(menu, [show_unsigned, show_signed, show_hex]) @@ -674,14 +674,14 @@ def treeWidget_AddressTable_context_menu_event(self, event): GuiUtils.delete_menu_entries(menu, [show_unsigned, show_dec]) elif value_type.value_repr is type_defs.VALUE_REPR.SIGNED: GuiUtils.delete_menu_entries(menu, [show_signed, show_dec]) - if current_row.checkState(FROZEN_COL) == Qt.Unchecked: + if current_row.checkState(FROZEN_COL) == Qt.CheckState.Unchecked: GuiUtils.delete_menu_entries(menu, [freeze_menu.menuAction()]) else: GuiUtils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed, freeze_menu.menuAction()]) font_size = self.treeWidget_AddressTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { edit_desc: self.treeWidget_AddressTable_edit_desc, edit_address: self.treeWidget_AddressTable_edit_address, @@ -720,7 +720,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): if not selected_row: return address = selected_row.text(ADDR_COL).strip("P->") # @todo Maybe rework address grabbing logic in the future - value_type = selected_row.data(TYPE_COL, Qt.UserRole) + value_type = selected_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) if type_defs.VALUE_INDEX.is_string(value_type.value_index): value_text = selected_row.text(VALUE_COL) encoding, option = type_defs.string_index_to_encoding_dict[value_type.value_index] @@ -748,7 +748,7 @@ def disassemble_selected_row(self): def change_freeze_type(self, freeze_type): for row in self.treeWidget_AddressTable.selectedItems(): - frozen = row.data(FROZEN_COL, Qt.UserRole) + frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) frozen.freeze_type = freeze_type # TODO: Create a QWidget subclass with signals so freeze type can be changed by clicking on the cell @@ -766,7 +766,7 @@ def toggle_selected_records(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if row: check_state = row.checkState(FROZEN_COL) - new_check_state = Qt.Checked if check_state == Qt.Unchecked else Qt.Unchecked + new_check_state = Qt.CheckState.Checked if check_state == Qt.CheckState.Unchecked else Qt.CheckState.Unchecked for row in self.treeWidget_AddressTable.selectedItems(): row.setCheckState(FROZEN_COL, new_check_state) self.treeWidget_AddressTable_item_clicked(row, FROZEN_COL) @@ -827,9 +827,9 @@ def insert_records(self, records, parent_row, insert_index): rows = [] for rec in records: row = QTreeWidgetItem() - row.setCheckState(FROZEN_COL, Qt.Unchecked) + row.setCheckState(FROZEN_COL, Qt.CheckState.Unchecked) frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) - row.setData(FROZEN_COL, Qt.UserRole, frozen) + row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) # Deserialize the address_expr & value_type param if type(rec[1]) in [list, tuple]: @@ -868,25 +868,25 @@ def delete_selected_records(self): def treeWidget_AddressTable_key_press_event(self, event): actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.NoModifier, Qt.Key_Delete), self.delete_selected_records), - ((Qt.ControlModifier, Qt.Key_B), self.browse_region_for_selected_row), - ((Qt.ControlModifier, Qt.Key_D), self.disassemble_selected_row), - ((Qt.NoModifier, Qt.Key_R), self.update_address_table), - ((Qt.NoModifier, Qt.Key_Space), self.toggle_selected_records), - ((Qt.ControlModifier, Qt.Key_X), self.cut_selected_records), - ((Qt.ControlModifier, Qt.Key_C), self.copy_selected_records), - ((Qt.NoModifier, Qt.Key_X), self.cut_selected_records_recursively), - ((Qt.NoModifier, Qt.Key_C), self.copy_selected_records_recursively), - ((Qt.ControlModifier, Qt.Key_V), lambda: self.paste_records(insert_after=False)), - ((Qt.NoModifier, Qt.Key_V), lambda: self.paste_records(insert_after=True)), - ((Qt.NoModifier, Qt.Key_I), lambda: self.paste_records(insert_inside=True)), - ((Qt.NoModifier, Qt.Key_Return), self.treeWidget_AddressTable_edit_value), - ((Qt.ControlModifier, Qt.Key_Return), self.treeWidget_AddressTable_edit_desc), - ((Qt.ControlModifier | Qt.AltModifier, Qt.Key_Return), self.treeWidget_AddressTable_edit_address), - ((Qt.AltModifier, Qt.Key_Return), self.treeWidget_AddressTable_edit_type) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_selected_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), self.browse_region_for_selected_row), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_address_table), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_selected_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_X), self.cut_selected_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_selected_records), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_X), self.cut_selected_records_recursively), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_C), self.copy_selected_records_recursively), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), lambda: self.paste_records(insert_after=False)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), lambda: self.paste_records(insert_after=True)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_I), lambda: self.paste_records(insert_inside=True)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_value), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_desc), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_address), + (QKeyCombination(Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_type) ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: self.treeWidget_AddressTable.keyPressEvent_original(event) @@ -902,7 +902,7 @@ def update_address_table(self): if not row: break it += 1 - address_data = row.data(ADDR_COL, Qt.UserRole) + address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) if isinstance(address_data, type_defs.PointerType): pointer_address = GDB_Engine.read_pointer(address_data) if pointer_address == None: @@ -916,13 +916,13 @@ def update_address_table(self): except type_defs.InferiorRunningException: address_list = address_expr_list for index, row in enumerate(rows): - value_type = row.data(TYPE_COL, Qt.UserRole) + value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) address = address_list[index] signed = True if value_type.value_repr == type_defs.VALUE_REPR.SIGNED else False value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, value_type.zero_terminate, signed, mem_handle=mem_handle) - address_data = row.data(ADDR_COL, Qt.UserRole) + address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) if isinstance(address_data, type_defs.PointerType): address_text = f'P->{address}' else: @@ -943,7 +943,7 @@ def resize_address_table(self): # gets the information from the dialog then adds it to addresstable def pushButton_AddAddressManually_clicked(self): manual_address_dialog = ManualAddressDialogForm() - if manual_address_dialog.exec_(): + if manual_address_dialog.exec(): desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() self.add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate) @@ -960,7 +960,7 @@ def pushButton_About_clicked(self): def pushButton_Settings_clicked(self): settings_dialog = SettingsDialogForm(self.set_default_settings) - if settings_dialog.exec_(): + if settings_dialog.exec(): self.apply_settings() def pushButton_Console_clicked(self): @@ -968,7 +968,7 @@ def pushButton_Console_clicked(self): console_widget.showMaximized() def checkBox_Hex_stateChanged(self, state): - if state == Qt.Checked: + if state == Qt.CheckState.Checked: # allows only things that are hex, can also start with 0x self.lineEdit_Scan.setValidator(QRegExpValidator(QRegExp("(0x)?[A-Fa-f0-9]*$"), parent=self.lineEdit_Scan)) self.lineEdit_Scan2.setValidator( @@ -994,7 +994,7 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_NewFirstScan.setText("New Scan") self.comboBox_ValueType.setEnabled(False) self.pushButton_NextScan.setEnabled(True) - search_scope = self.comboBox_ScanScope.currentData(Qt.UserRole) + search_scope = self.comboBox_ScanScope.currentData(Qt.ItemDataRole.UserRole) self.backend.send_command("option region_scan_level " + str(search_scope)) self.backend.send_command("reset") self.comboBox_ScanScope.setEnabled(False) @@ -1004,11 +1004,11 @@ def pushButton_NewFirstScan_clicked(self): def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, type_defs.SCAN_TYPE.UNCHANGED, type_defs.SCAN_TYPE.UNKNOWN] - if self.comboBox_ScanType.currentData(Qt.UserRole) in hidden_types: + if self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) in hidden_types: self.widget_Scan.setEnabled(False) else: self.widget_Scan.setEnabled(True) - if self.comboBox_ScanType.currentData(Qt.UserRole) == type_defs.SCAN_TYPE.BETWEEN: + if self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) == type_defs.SCAN_TYPE.BETWEEN: self.label_Between.setVisible(True) self.lineEdit_Scan2.setVisible(True) else: @@ -1016,7 +1016,7 @@ def comboBox_ScanType_current_index_changed(self): self.lineEdit_Scan2.setVisible(False) def comboBox_ScanType_init(self): - current_type = self.comboBox_ScanType.currentData(Qt.UserRole) + current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() if self.scan_mode == type_defs.SCAN_MODE.NEW: items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.LESS, type_defs.SCAN_TYPE.MORE, @@ -1049,7 +1049,7 @@ def comboBox_ValueType_init(self): # adds things like 0x when searching for etc, basically just makes the line valid for scanmem # this should cover most things, more things might be added later if need be def validate_search(self, search_for, search_for2): - type_index = self.comboBox_ScanType.currentData(Qt.UserRole) + type_index = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) symbol_map = { type_defs.SCAN_TYPE.INCREASED: "+", type_defs.SCAN_TYPE.DECREASED: "-", @@ -1061,7 +1061,7 @@ def validate_search(self, search_for, search_for2): return symbol_map[type_index] # none of these should be possible to be true at the same time - scan_index = self.comboBox_ValueType.currentData(Qt.UserRole) + scan_index = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) if scan_index == type_defs.SCAN_INDEX.INDEX_FLOAT32 or scan_index == type_defs.SCAN_INDEX.INDEX_FLOAT64: # this is odd, since when searching for floats from command line it uses `.` and not `,` search_for = search_for.replace(".", ",") @@ -1101,7 +1101,7 @@ def pushButton_NextScan_clicked(self): else: self.label_MatchCount.setText("Match count: {}".format(match_count)) self.tableWidget_valuesearchtable.setRowCount(0) - current_type = self.comboBox_ValueType.currentData(Qt.UserRole) + current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) length = self._scan_to_length(current_type) mem_handle = GDB_Engine.memory_handle() for n, address, offset, region_type, val, result_type in matches: @@ -1113,7 +1113,7 @@ def pushButton_NextScan_clicked(self): signed = False if type_defs.VALUE_INDEX.is_integer(value_index) and result.endswith("s"): signed = True - current_item.setData(Qt.UserRole, (value_index, signed)) + current_item.setData(Qt.ItemDataRole.UserRole, (value_index, signed)) value = str(GDB_Engine.read_memory(address, value_index, length, signed=signed, mem_handle=mem_handle)) self.tableWidget_valuesearchtable.insertRow(self.tableWidget_valuesearchtable.rowCount()) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_ADDRESS_COL, current_item) @@ -1132,16 +1132,16 @@ def _scan_to_length(self, type_index): @GDB_Engine.execute_with_temporary_interruption def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) - length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) - self.add_entry_to_addresstable("No Description", current_item.text(), current_item.data(Qt.UserRole)[0], length) + length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) + self.add_entry_to_addresstable("No Description", current_item.text(), current_item.data(Qt.ItemDataRole.UserRole)[0], length) def comboBox_ValueType_current_index_changed(self): - current_type = self.comboBox_ValueType.currentData(Qt.UserRole) + current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) validator_map = { - "int": QRegExpValidator(QRegExp("-?[0-9]*"), parent=self.lineEdit_Scan), # integers - "float": QRegExpValidator(QRegExp("-?[0-9]+[.,]?[0-9]*")), + "int": QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan), # integers + "float": QRegularExpressionValidator(QRegularExpression("-?[0-9]+[.,]?[0-9]*")), # floats, should work fine with the small amount of testing I did - "bytearray": QRegExpValidator(QRegExp("^(([A-Fa-f0-9?]{2} +)+)$"), parent=self.lineEdit_Scan), + "bytearray": QRegularExpressionValidator(QRegularExpression("^(([A-Fa-f0-9?]{2} +)+)$"), parent=self.lineEdit_Scan), # array of bytes "string": None } @@ -1175,7 +1175,7 @@ def pushButton_Open_clicked(self): if not file_paths: return if self.treeWidget_AddressTable.topLevelItemCount() > 0: - if InputDialogForm(item_list=[("Clear existing address table?",)]).exec_(): + if InputDialogForm(item_list=[("Clear existing address table?",)]).exec(): self.treeWidget_AddressTable.clear() for file_path in file_paths: @@ -1242,16 +1242,16 @@ def on_new_process(self): def delete_address_table_contents(self): confirm_dialog = InputDialogForm(item_list=[("This will clear the contents of address table\nProceed?",)]) - if confirm_dialog.exec_(): + if confirm_dialog.exec(): self.treeWidget_AddressTable.clear() def copy_to_address_table(self): i = -1 - length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) + length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) for row in self.tableWidget_valuesearchtable.selectedItems(): i = i + 1 if i % 3 == 0: - self.add_entry_to_addresstable("", row.text(), row.data(Qt.UserRole)[0], length) + self.add_entry_to_addresstable("", row.text(), row.data(Qt.ItemDataRole.UserRole)[0], length) def on_inferior_exit(self): if GDB_Engine.currentpid == -1: @@ -1284,9 +1284,9 @@ def closeEvent(self, event): def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True): current_row = QTreeWidgetItem() - current_row.setCheckState(FROZEN_COL, Qt.Unchecked) + current_row.setCheckState(FROZEN_COL, Qt.CheckState.Unchecked) frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) - current_row.setData(FROZEN_COL, Qt.UserRole, frozen) + current_row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) value_type = type_defs.ValueType(value_index, length, zero_terminate) self.treeWidget_AddressTable.addTopLevelItem(current_row) self.change_address_table_entries(current_row, description, address_expr, value_type) @@ -1346,12 +1346,12 @@ def freeze_loop(self): def update_search_table(self): row_count = self.tableWidget_valuesearchtable.rowCount() if row_count > 0: - length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.UserRole)) + length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) mem_handle = GDB_Engine.memory_handle() for row_index in range(row_count): address_item = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_ADDRESS_COL) previous_text = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_PREVIOUS_COL).text() - value_index, signed = address_item.data(Qt.UserRole) + value_index, signed = address_item.data(Qt.ItemDataRole.UserRole) address = address_item.text() new_value = str(GDB_Engine.read_memory(address, value_index, length, signed=signed, mem_handle=mem_handle)) @@ -1364,10 +1364,10 @@ def freeze(self): it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) while it.value(): row = it.value() - if row.checkState(FROZEN_COL) == Qt.Checked: - value_index = row.data(TYPE_COL, Qt.UserRole).value_index + if row.checkState(FROZEN_COL) == Qt.CheckState.Checked: + value_index = row.data(TYPE_COL, Qt.ItemDataRole.UserRole).value_index address = row.text(ADDR_COL).strip("P->") - frozen = row.data(FROZEN_COL, Qt.UserRole) + frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) value = frozen.value freeze_type = frozen.freeze_type if type_defs.VALUE_INDEX.is_integer(value_index): @@ -1382,18 +1382,18 @@ def freeze(self): def treeWidget_AddressTable_item_clicked(self, row, column): if column == FROZEN_COL: - if row.checkState(FROZEN_COL) == Qt.Checked: - frozen = row.data(FROZEN_COL, Qt.UserRole) + if row.checkState(FROZEN_COL) == Qt.CheckState.Checked: + frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) frozen.value = row.text(VALUE_COL) else: row.setText(FROZEN_COL, "") row.setForeground(FROZEN_COL, QBrush(QColor(0, 0, 0))) def treeWidget_AddressTable_change_repr(self, new_repr): - value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.UserRole) + value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) value_type.value_repr = new_repr for row in self.treeWidget_AddressTable.selectedItems(): - row.setData(TYPE_COL, Qt.UserRole, value_type) + row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) self.update_address_table() @@ -1402,22 +1402,22 @@ def treeWidget_AddressTable_edit_value(self): if not row: return value = row.text(VALUE_COL) - value_index = row.data(TYPE_COL, Qt.UserRole).value_index + value_index = row.data(TYPE_COL, Qt.ItemDataRole.UserRole).value_index label_text = "Enter the new value" dialog = InputDialogForm(item_list=[(label_text, value)], parsed_index=0, value_index=value_index) - if dialog.exec_(): + if dialog.exec(): new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): address = row.text(ADDR_COL).strip("P->") - value_type = row.data(TYPE_COL, Qt.UserRole) + value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) if type_defs.VALUE_INDEX.has_length(value_type.value_index): unknown_type = SysUtils.parse_string(new_value, value_type.value_index) if unknown_type is not None: value_type.length = len(unknown_type) row.setText(TYPE_COL, value_type.text()) - frozen = row.data(FROZEN_COL, Qt.UserRole) + frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) frozen.value = new_value - row.setData(FROZEN_COL, Qt.UserRole, frozen) + row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) GDB_Engine.write_memory(address, value_type.value_index, new_value) self.update_address_table() @@ -1427,7 +1427,7 @@ def treeWidget_AddressTable_edit_desc(self): return description = row.text(DESC_COL) dialog = InputDialogForm(item_list=[("Enter the new description", description)]) - if dialog.exec_(): + if dialog.exec(): description_text = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): row.setText(DESC_COL, description_text) @@ -1441,7 +1441,7 @@ def treeWidget_AddressTable_edit_address(self): index=value_type.value_index, length=value_type.length, zero_terminate=value_type.zero_terminate) manual_address_dialog.setWindowTitle("Edit Address") - if manual_address_dialog.exec_(): + if manual_address_dialog.exec(): desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() value_type = type_defs.ValueType(value_index, length, zero_terminate, value_type.value_repr) self.change_address_table_entries(row, desc, address_expr, value_type) @@ -1450,14 +1450,14 @@ def treeWidget_AddressTable_edit_type(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not row: return - value_type = row.data(TYPE_COL, Qt.UserRole) + value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) dialog = EditTypeDialogForm(index=value_type.value_index, length=value_type.length, zero_terminate=value_type.zero_terminate) - if dialog.exec_(): + if dialog.exec(): value_index, length, zero_terminate = dialog.get_values() value_type = type_defs.ValueType(value_index, length, zero_terminate, value_type.value_repr) for row in self.treeWidget_AddressTable.selectedItems(): - row.setData(TYPE_COL, Qt.UserRole, value_type) + row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) self.update_address_table() @@ -1479,9 +1479,9 @@ def change_address_table_entries(self, row, description="No Description", addres assert isinstance(row, QTreeWidgetItem) row.setText(DESC_COL, description) - row.setData(ADDR_COL, Qt.UserRole, address_expr) + row.setData(ADDR_COL, Qt.ItemDataRole.UserRole, address_expr) row.setText(ADDR_COL, address_text or address_expr) - row.setData(TYPE_COL, Qt.UserRole, value_type) + row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) row.setText(VALUE_COL, "" if value is None else str(value)) @@ -1489,15 +1489,15 @@ def change_address_table_entries(self, row, description="No Description", addres def read_address_table_entries(self, row, serialize=False): description = row.text(DESC_COL) if serialize: - address_data = row.data(ADDR_COL, Qt.UserRole) + address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) if isinstance(address_data, type_defs.PointerType): address_expr = address_data.serialize() else: address_expr = address_data - value_type = row.data(TYPE_COL, Qt.UserRole).serialize() + value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole).serialize() else: - address_expr = row.data(ADDR_COL, Qt.UserRole) - value_type = row.data(TYPE_COL, Qt.UserRole) + address_expr = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) + value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) return description, address_expr, value_type # Returns the values inside the given row and all of its descendants. @@ -1528,14 +1528,14 @@ def generate_new_list(self): self.refresh_process_table(self.tableWidget_ProcessTable, processlist) def keyPressEvent(self, e): - if e.key() == Qt.Key_Escape: + if e.key() == Qt.Key.Key_Escape: # closes the window whenever ESC key is pressed self.close() - elif e.key() == Qt.Key_Return: + elif e.key() == Qt.Key.Key_Return: self.pushButton_Open_clicked() - elif e.key() == Qt.Key_F1: + elif e.key() == Qt.Key.Key_F1: self.pushButton_CreateProcess_clicked() - elif e.key() == Qt.Key_Down or e.key() == Qt.Key_Up: + elif e.key() == Qt.Key.Key_Down or e.key() == Qt.Key.Key_Up: self.tableWidget_ProcessTable.keyPressEvent(QKeyEvent(QEvent.KeyPress, e.key(), Qt.NoModifier)) # lists currently working processes to table @@ -1561,24 +1561,24 @@ def pushButton_Open_clicked(self): QMessageBox.information(self, "Error", "Please select a process first") else: pid = int(current_item.text()) - self.setCursor(QCursor(Qt.WaitCursor)) + self.setCursor(QCursor(Qt.CursorShape.WaitCursor)) if self.parent().attach_to_pid(pid): self.close() - self.setCursor(QCursor(Qt.ArrowCursor)) + self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) def pushButton_CreateProcess_clicked(self): file_path = QFileDialog.getOpenFileName(self, "Select the target binary")[0] if file_path: items = [("Enter the optional arguments", ""), ("LD_PRELOAD .so path (optional)", "")] arg_dialog = InputDialogForm(item_list=items) - if arg_dialog.exec_(): + if arg_dialog.exec(): args, ld_preload_path = arg_dialog.get_values() else: return - self.setCursor(QCursor(Qt.WaitCursor)) + self.setCursor(QCursor(Qt.CursorShape.WaitCursor)) if self.parent().create_new_process(file_path, args, ld_preload_path): self.close() - self.setCursor(QCursor(Qt.ArrowCursor)) + self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) # Add Address Manually Dialog @@ -1643,7 +1643,7 @@ def label_valueofaddress_context_menu_event(self, event): refresh = menu.addAction("Refresh") font_size = self.label_valueofaddress.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { refresh: self.update_value_of_address } @@ -1914,9 +1914,9 @@ def __init__(self, parent=None): def cancel_thread(self): GDB_Engine.cancel_last_command() - def exec_(self): + def exec(self): self.background_thread.start() - super(LoadingDialogForm, self).exec_() + super(LoadingDialogForm, self).exec() class BackgroundThread(QThread): output_ready = pyqtSignal(object) @@ -1942,7 +1942,7 @@ class InputDialogForm(QDialog, InputDialog): # "0" and "1" then will set current index to 1 (which is the item "1") # label_alignment is optional def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=type_defs.VALUE_INDEX.INDEX_INT32, - buttons=(QDialogButtonBox.Ok, QDialogButtonBox.Cancel)): + buttons=(QDialogButtonBox.StandardButton.Ok, QDialogButtonBox.StandardButton.Cancel)): super().__init__(parent=parent) self.setupUi(self) for button in buttons: @@ -1954,9 +1954,9 @@ def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typ try: label.setAlignment(item[2]) except IndexError: - label.setAlignment(Qt.AlignCenter) + label.setAlignment(Qt.AlignmentFlag.AlignCenter) label.setText(item[0]) - label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.TextSelectableByMouse) + label.setTextInteractionFlags(Qt.TextInteractionFlag.LinksAccessibleByMouse | Qt.TextInteractionFlag.TextSelectableByMouse) self.verticalLayout.addWidget(label) try: item_data = item[1] @@ -2019,7 +2019,7 @@ def get_values(self): return self.textEdit.toPlainText() def keyPressEvent(self, QKeyEvent): - if QKeyEvent.key() == Qt.Key_Enter: + if QKeyEvent.key() == Qt.Key.Key_Enter: pass else: super(TextEditDialogForm, self).keyPressEvent(QKeyEvent) @@ -2079,12 +2079,12 @@ def accept(self): elif current_table_update_interval == 0 or freezeinterval == 0: # Easter egg #2 - if not InputDialogForm(item_list=[("You are asking for it, aren't you?",)]).exec_(): + if not InputDialogForm(item_list=[("You are asking for it, aren't you?",)]).exec(): return elif current_table_update_interval < 100: if not InputDialogForm(item_list=[("Update interval should be bigger than 100 ms" + "\nSetting update interval less than 100 ms may cause slowdown" - "\nProceed?",)]).exec_(): + "\nProceed?",)]).exec(): return self.settings.setValue("General/auto_update_address_table", self.checkBox_AutoUpdateAddressTable.isChecked()) @@ -2120,7 +2120,7 @@ def accept(self): selected_gdb_path = self.lineEdit_GDBPath.text() current_gdb_path = self.settings.value("Debug/gdb_path", type=str) if selected_gdb_path != current_gdb_path: - if InputDialogForm(item_list=[("You have changed the GDB path, reset GDB now?",)]).exec_(): + if InputDialogForm(item_list=[("You have changed the GDB path, reset GDB now?",)]).exec(): GDB_Engine.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) @@ -2188,7 +2188,7 @@ def pushButton_ClearHotkey_clicked(self): def pushButton_ResetSettings_clicked(self): confirm_dialog = InputDialogForm(item_list=[("This will reset to the default settings\nProceed?",)]) - if confirm_dialog.exec_(): + if confirm_dialog.exec(): self.set_default_settings() self.handle_signals_data = None self.config_gui() @@ -2220,7 +2220,7 @@ def pushButton_HandleSignals_clicked(self): if self.handle_signals_data is None: self.handle_signals_data = self.settings.value("Debug/ignored_signals", type=str).split(",") signal_dialog = HandleSignalsDialogForm(self.handle_signals_data) - if signal_dialog.exec_(): + if signal_dialog.exec(): self.handle_signals_data = signal_dialog.get_values() @@ -2235,20 +2235,20 @@ def __init__(self, signal_data, parent=None): checkbox = QCheckBox() layout = QHBoxLayout(widget) layout.addWidget(checkbox) - layout.setAlignment(Qt.AlignCenter) + layout.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.setContentsMargins(0, 0, 0, 0) self.tableWidget_Signals.setCellWidget(index, 1, widget) if state == "1": - checkbox.setCheckState(Qt.Checked) + checkbox.setCheckState(Qt.CheckState.Checked) else: - checkbox.setCheckState(Qt.Unchecked) + checkbox.setCheckState(Qt.CheckState.Unchecked) def get_values(self): final_state = [] for index in range(len(signal_list)): widget = self.tableWidget_Signals.cellWidget(index, 1) checkbox = widget.findChild(QCheckBox) - if checkbox.checkState() == Qt.Checked: + if checkbox.checkState() == Qt.CheckState.Checked: final_state.append("1") else: final_state.append("0") @@ -2366,7 +2366,7 @@ def scroll_to_bottom(self): def enter_multiline_mode(self): multiline_dialog = TextEditDialogForm(text=self.lineEdit.text()) - if multiline_dialog.exec_(): + if multiline_dialog.exec(): self.lineEdit.setText(multiline_dialog.get_values()) self.communicate() @@ -2392,8 +2392,8 @@ def scroll_forwards_history(self): def lineEdit_key_press_event(self, event): actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.NoModifier, Qt.Key_Up), self.scroll_backwards_history), - ((Qt.NoModifier, Qt.Key_Down), self.scroll_forwards_history) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), self.scroll_backwards_history), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), self.scroll_forwards_history) ]) try: actions[event.modifiers(), event.key()]() @@ -2596,7 +2596,7 @@ def initialize_hex_view(self): self.scrollArea_Hex.keyPressEvent = QEvent.ignore self.tableWidget_HexView_Address.setAutoScroll(False) self.tableWidget_HexView_Address.setStyleSheet("QTableWidget {background-color: transparent;}") - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.NoSelection) + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) self.hex_model = QHexModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) self.ascii_model = QAsciiModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) @@ -2606,10 +2606,10 @@ def initialize_hex_view(self): self.tableView_HexView_Hex.selectionModel().currentChanged.connect(self.on_hex_view_current_changed) self.tableView_HexView_Ascii.selectionModel().currentChanged.connect(self.on_ascii_view_current_changed) - self.scrollArea_Hex.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.scrollArea_Hex.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.tableWidget_HexView_Address.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.tableWidget_HexView_Address.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.scrollArea_Hex.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.scrollArea_Hex.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.tableWidget_HexView_Address.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.tableWidget_HexView_Address.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_HexView_Address.verticalHeader().setDefaultSectionSize( self.tableView_HexView_Hex.verticalHeader().defaultSectionSize()) @@ -2673,7 +2673,7 @@ def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.B GDB_Engine.delete_breakpoint(hex(address)) else: watchpoint_dialog = InputDialogForm(item_list=[("Enter the watchpoint length in size of bytes", "")]) - if watchpoint_dialog.exec_(): + if watchpoint_dialog.exec(): user_input = watchpoint_dialog.get_values() user_input_int = SysUtils.parse_string(user_input, type_defs.VALUE_INDEX.INDEX_INT32) if user_input_int is None: @@ -2694,7 +2694,7 @@ def copy_to_clipboard(): copy_label = menu.addAction("Copy to Clipboard") font_size = self.label_HexView_Information.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_label: copy_to_clipboard } @@ -2727,7 +2727,7 @@ def widget_HexView_context_menu_event(self, event): GuiUtils.delete_menu_entries(menu, [watchpoint_menu.menuAction()]) font_size = self.widget_HexView.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { edit: self.exec_hex_view_edit_dialog, go_to: self.exec_hex_view_go_to_dialog, @@ -2747,13 +2747,13 @@ def widget_HexView_context_menu_event(self, event): def exec_hex_view_edit_dialog(self): selected_address = self.tableView_HexView_Hex.get_selected_address() - HexEditDialogForm(hex(selected_address)).exec_() + HexEditDialogForm(hex(selected_address)).exec() self.refresh_hex_view() def exec_hex_view_go_to_dialog(self): current_address = hex(self.tableView_HexView_Hex.get_selected_address()) go_to_dialog = InputDialogForm(item_list=[("Enter the expression", current_address)]) - if go_to_dialog.exec_(): + if go_to_dialog.exec(): expression = go_to_dialog.get_values() dest_address = GDB_Engine.examine_expression(expression).address if not dest_address: @@ -2765,7 +2765,7 @@ def exec_hex_view_add_address_dialog(self): selected_address = self.tableView_HexView_Hex.get_selected_address() manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), index=type_defs.VALUE_INDEX.INDEX_AOB) - if manual_address_dialog.exec_(): + if manual_address_dialog.exec(): desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() self.parent().add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate) @@ -3042,7 +3042,7 @@ def handle_colours(self, row_colour): # color parameter should be Qt.colour def set_row_colour(self, row, colour): for col in range(self.tableWidget_Disassemble.columnCount()): - self.tableWidget_Disassemble.item(row, col).setData(Qt.BackgroundColorRole, QColor(colour)) + self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, QColor(colour)) def on_process_stop(self): if GDB_Engine.stop_reason == type_defs.STOP_REASON.PAUSE: @@ -3094,8 +3094,8 @@ def add_breakpoint_condition(self, int_address): condition_line_edit_text = breakpoint.condition else: condition_line_edit_text = "" - condition_dialog = InputDialogForm(item_list=[(condition_text, condition_line_edit_text, Qt.AlignLeft)]) - if condition_dialog.exec_(): + condition_dialog = InputDialogForm(item_list=[(condition_text, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) + if condition_dialog.exec(): condition = condition_dialog.get_values() if not GDB_Engine.modify_breakpoint(hex(int_address), type_defs.BREAKPOINT_MODIFY.CONDITION, condition=condition): @@ -3182,7 +3182,7 @@ def copy_to_clipboard(row, column): refresh = menu.addAction("Refresh[R]") font_size = self.tableWidget_StackTrace.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { switch_to_stack: lambda: self.set_stack_widget(self.Stack), copy_return: lambda: copy_to_clipboard(selected_row, STACKTRACE_RETURN_ADDRESS_COL), @@ -3211,10 +3211,10 @@ def tableWidget_Stack_key_press_event(self, event): current_address = SysUtils.extract_address(current_address_text) actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.NoModifier, Qt.Key_R), self.update_stack), - ((Qt.ControlModifier, Qt.Key_D), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), lambda: self.disassemble_expression(current_address, append_to_travel_history=True)), - ((Qt.ControlModifier, Qt.Key_H), lambda: self.hex_dump_address(int(current_address, 16))) + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), lambda: self.hex_dump_address(int(current_address, 16))) ]) try: actions[event.modifiers(), event.key()]() @@ -3245,7 +3245,7 @@ def copy_to_clipboard(row, column): GuiUtils.delete_menu_entries(menu, [clipboard_menu.menuAction(), show_in_disas, show_in_hex]) font_size = self.tableWidget_Stack.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { switch_to_stacktrace: lambda: self.set_stack_widget(self.StackTrace), copy_address: lambda: copy_to_clipboard(selected_row, STACK_POINTER_ADDRESS_COL), @@ -3288,7 +3288,7 @@ def tableWidget_StackTrace_double_click(self, index): def tableWidget_StackTrace_key_press_event(self, event): actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.NoModifier, Qt.Key_R), self.update_stacktrace) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stacktrace) ]) try: actions[event.modifiers(), event.key()]() @@ -3341,11 +3341,11 @@ def widget_HexView_key_press_event(self, event): selected_address = self.tableView_HexView_Hex.get_selected_address() actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.ControlModifier, Qt.Key_G), self.exec_hex_view_go_to_dialog), - ((Qt.ControlModifier, Qt.Key_D), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_hex_view_go_to_dialog), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), lambda: self.disassemble_expression(hex(selected_address), append_to_travel_history=True)), - ((Qt.ControlModifier, Qt.Key_A), self.exec_hex_view_add_address_dialog), - ((Qt.NoModifier, Qt.Key_R), self.refresh_hex_view) + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_A), self.exec_hex_view_add_address_dialog), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_hex_view) ]) try: actions[event.modifiers(), event.key()]() @@ -3360,16 +3360,16 @@ def tableWidget_Disassemble_key_press_event(self, event): current_address_int = int(current_address, 16) actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.NoModifier, Qt.Key_Space), lambda: self.follow_instruction(selected_row)), - ((Qt.ControlModifier, Qt.Key_E), lambda: self.exec_examine_referrers_widget(current_address_text)), - ((Qt.ControlModifier, Qt.Key_G), self.exec_disassemble_go_to_dialog), - ((Qt.ControlModifier, Qt.Key_H), lambda: self.hex_dump_address(current_address_int)), - ((Qt.ControlModifier, Qt.Key_B), lambda: self.bookmark_address(current_address_int)), - ((Qt.ControlModifier, Qt.Key_D), self.dissect_current_region), - ((Qt.ControlModifier, Qt.Key_T), self.exec_trace_instructions_dialog), - ((Qt.NoModifier, Qt.Key_R), self.refresh_disassemble_view), - ((Qt.NoModifier, Qt.Key_Down), lambda: self.disassemble_check_viewport("next", 1)), - ((Qt.NoModifier, Qt.Key_Up), lambda: self.disassemble_check_viewport("previous", 1)) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), lambda: self.follow_instruction(selected_row)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_E), lambda: self.exec_examine_referrers_widget(current_address_text)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_disassemble_go_to_dialog), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), lambda: self.hex_dump_address(current_address_int)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), lambda: self.bookmark_address(current_address_int)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.dissect_current_region), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_T), self.exec_trace_instructions_dialog), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_disassemble_view), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), lambda: self.disassemble_check_viewport("next", 1)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), lambda: self.disassemble_check_viewport("previous", 1)) ]) try: actions[event.modifiers(), event.key()]() @@ -3472,7 +3472,7 @@ def copy_all_columns(row): copy_all = clipboard_menu.addAction("Copy All") font_size = self.tableWidget_Disassemble.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { go_to: self.exec_disassemble_go_to_dialog, back: self.disassemble_go_back, @@ -3508,7 +3508,7 @@ def dissect_current_region(self): current_address = SysUtils.extract_address(current_address_text) dissect_code_dialog = DissectCodeDialogForm(int_address=int(current_address, 16)) dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) - dissect_code_dialog.exec_() + dissect_code_dialog.exec() self.refresh_disassemble_view() def exec_examine_referrers_widget(self, current_address_text): @@ -3540,7 +3540,7 @@ def exec_disassemble_go_to_dialog(self): current_address = SysUtils.extract_address(current_address_text) go_to_dialog = InputDialogForm(item_list=[("Enter the expression", current_address)]) - if go_to_dialog.exec_(): + if go_to_dialog.exec(): traveled_exp = go_to_dialog.get_values() self.disassemble_expression(traveled_exp, append_to_travel_history=True) @@ -3549,7 +3549,7 @@ def bookmark_address(self, int_address): QMessageBox.information(app.focusWidget(), "Error", "This address has already been bookmarked") return comment_dialog = InputDialogForm(item_list=[("Enter the comment for bookmarked address", "")]) - if comment_dialog.exec_(): + if comment_dialog.exec(): comment = comment_dialog.get_values() else: return @@ -3559,7 +3559,7 @@ def bookmark_address(self, int_address): def change_bookmark_comment(self, int_address): current_comment = self.tableWidget_Disassemble.bookmarks[int_address] comment_dialog = InputDialogForm(item_list=[("Enter the comment for bookmarked address", current_comment)]) - if comment_dialog.exec_(): + if comment_dialog.exec(): new_comment = comment_dialog.get_values() else: return @@ -3628,7 +3628,7 @@ def actionCall_Function_triggered(self): '\n4 is the result' \ '\nYou can use the assigned variable from the GDB Console' call_dialog = InputDialogForm(item_list=[(label_text, "")]) - if call_dialog.exec_(): + if call_dialog.exec(): result = GDB_Engine.call_function_from_inferior(call_dialog.get_values()) if result[0]: QMessageBox.information(self, "Success!", result[0] + " = " + result[1]) @@ -3643,7 +3643,7 @@ def actionSearch_Opcode_triggered(self): def actionDissect_Code_triggered(self): self.dissect_code_dialog = DissectCodeDialogForm() - self.dissect_code_dialog.exec_() + self.dissect_code_dialog.exec() self.refresh_disassemble_view() def actionlibpince_triggered(self): @@ -3689,7 +3689,7 @@ def listWidget_item_double_clicked(self, item): def exec_add_entry_dialog(self): entry_dialog = InputDialogForm(item_list=[("Enter the expression", "")]) - if entry_dialog.exec_(): + if entry_dialog.exec(): text = entry_dialog.get_values() address = GDB_Engine.examine_expression(text).address if not address: @@ -3722,7 +3722,7 @@ def listWidget_context_menu_event(self, event): refresh = menu.addAction("Refresh[R]") font_size = self.listWidget.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { add_entry: self.exec_add_entry_dialog, change_comment: lambda: self.exec_change_comment_dialog(current_address), @@ -3780,7 +3780,7 @@ def set_register(self, index): current_value = current_table_widget.item(current_row, FLOAT_REGISTERS_VALUE_COL).text() label_text = "Enter the new value of register " + current_register.upper() register_dialog = InputDialogForm(item_list=[(label_text, current_value)]) - if register_dialog.exec_(): + if register_dialog.exec(): if self.currentWidget() == self.XMM: current_register += ".v4_float" GDB_Engine.set_convenience_variable(current_register, register_dialog.get_values()) @@ -3837,7 +3837,7 @@ def tableWidget_Instructions_context_menu_event(self, event): refresh = menu.addAction("Refresh[R]") font_size = self.tableWidget_Instructions.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { restore_instruction: lambda: self.restore_instruction(selected_address_int), refresh: self.refresh @@ -3866,7 +3866,7 @@ def refresh_all(self): def tableWidget_Instructions_key_press_event(self, event): actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.NoModifier, Qt.Key_R), self.refresh) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) ]) try: actions[event.modifiers(), event.key()]() @@ -3928,8 +3928,8 @@ def tableWidget_BreakpointInfo_key_press_event(self, event): current_address = None actions = type_defs.KeyboardModifiersTupleDict([ - ((Qt.NoModifier, Qt.Key_Delete), lambda: self.delete_breakpoint(current_address)), - ((Qt.NoModifier, Qt.Key_R), self.refresh) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), lambda: self.delete_breakpoint(current_address)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) ]) try: actions[event.modifiers(), event.key()]() @@ -3939,7 +3939,7 @@ def tableWidget_BreakpointInfo_key_press_event(self, event): def exec_enable_count_dialog(self, current_address): hit_count_dialog = InputDialogForm(item_list=[("Enter the hit count(1 or higher)", "")]) - if hit_count_dialog.exec_(): + if hit_count_dialog.exec(): count = hit_count_dialog.get_values() try: count = int(count) @@ -3979,7 +3979,7 @@ def tableWidget_BreakpointInfo_context_menu_event(self, event): refresh = menu.addAction("Refresh[R]") font_size = self.tableWidget_BreakpointInfo.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { change_condition: lambda: self.parent().add_breakpoint_condition(current_address_int), enable: lambda: GDB_Engine.modify_breakpoint(current_address, type_defs.BREAKPOINT_MODIFY.ENABLE), @@ -4135,7 +4135,7 @@ def __init__(self, address, instruction, parent=None): "\nIf you enter '$rax,$rbx*$rcx+4,$rbp'(without quotes)" \ "\nPINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]" register_expression_dialog = InputDialogForm(item_list=[(label_text, "")]) - if register_expression_dialog.exec_(): + if register_expression_dialog.exec(): register_expressions = register_expression_dialog.get_values() else: return @@ -4201,7 +4201,7 @@ def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() self.parent().parent().add_entry_to_addresstable("Accessed by " + self.address, address, - self.comboBox_ValueType.currentData(Qt.UserRole), 10, True) + self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole), 10, True) def pushButton_Stop_clicked(self): if self.stopped: @@ -4328,7 +4328,7 @@ def __init__(self, address="", prompt_dialog=True, parent=None): if not prompt_dialog: return prompt_dialog = TraceInstructionsPromptDialogForm() - if prompt_dialog.exec_(): + if prompt_dialog.exec(): params = (address,) + prompt_dialog.get_values() breakpoint = GDB_Engine.trace_instructions(*params) if not breakpoint: @@ -4406,7 +4406,7 @@ def treeWidget_InstructionInfo_context_menu_event(self, event): collapse_all = menu.addAction("Collapse All") font_size = self.treeWidget_InstructionInfo.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { expand_all: self.treeWidget_InstructionInfo.expandAll, collapse_all: self.treeWidget_InstructionInfo.collapseAll @@ -4456,7 +4456,7 @@ def refresh_table(self): self.background_thread = self.loading_dialog.background_thread self.background_thread.overrided_func = lambda: self.process_data(input_text, case_sensitive) self.background_thread.output_ready.connect(self.apply_data) - self.loading_dialog.exec_() + self.loading_dialog.exec() def process_data(self, gdb_input, case_sensitive): return GDB_Engine.search_functions(gdb_input, case_sensitive) @@ -4503,7 +4503,7 @@ def copy_to_clipboard(row, column): GuiUtils.delete_menu_entries(menu, [copy_address, copy_symbol]) font_size = self.tableWidget_SymbolInfo.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row, FUNCTIONS_INFO_ADDR_COL), copy_symbol: lambda: copy_to_clipboard(selected_row, FUNCTIONS_INFO_SYMBOL_COL) @@ -4528,7 +4528,7 @@ def pushButton_Help_clicked(self): "\n@plt means this function is a subroutine for the original one" \ "\nThere can be more than one of the same function" \ "\nIt means that the function is overloaded" - InputDialogForm(item_list=[(text, None, Qt.AlignLeft)], buttons=[QDialogButtonBox.Ok]).exec_() + InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.Ok]).exec() def closeEvent(self, QCloseEvent): global instances @@ -4669,7 +4669,7 @@ def copy_to_clipboard(row, column): GuiUtils.delete_menu_entries(menu, [copy_item, copy_value]) font_size = self.tableWidget_ResourceTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { refresh: self.fill_resource_table, copy_item: lambda: copy_to_clipboard(selected_row, LIBPINCE_REFERENCE_ITEM_COL), @@ -4708,7 +4708,7 @@ def collapse_all(): collapse_all_items = menu.addAction("Collapse All") font_size = self.treeWidget_ResourceTree.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { refresh: self.fill_resource_tree, copy_item: lambda: copy_to_clipboard(LIBPINCE_REFERENCE_ITEM_COL), @@ -4953,7 +4953,7 @@ def refresh_table(self): self.background_thread.overrided_func = lambda: self.process_data(regex, start_address, end_address, case_sensitive, enable_regex) self.background_thread.output_ready.connect(self.apply_data) - self.loading_dialog.exec_() + self.loading_dialog.exec() def process_data(self, regex, start_address, end_address, case_sensitive, enable_regex): return GDB_Engine.search_opcode(regex, start_address, end_address, case_sensitive, enable_regex) @@ -4976,7 +4976,7 @@ def pushButton_Help_clicked(self): "\n'[re]cx' searches for both 'rcx' and 'ecx'" \ "\nUse the char '\\' to escape special chars such as '['" \ "\n'\[rsp\]' searches for opcodes that contain '[rsp]'" - InputDialogForm(item_list=[(text, None, Qt.AlignLeft)], buttons=[QDialogButtonBox.Ok]).exec_() + InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.Ok]).exec() def tableWidget_Opcodes_item_double_clicked(self, index): row = index.row() @@ -4996,7 +4996,7 @@ def copy_to_clipboard(row, column): GuiUtils.delete_menu_entries(menu, [copy_address, copy_opcode]) font_size = self.tableWidget_Opcodes.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row, SEARCH_OPCODE_ADDR_COL), copy_opcode: lambda: copy_to_clipboard(selected_row, SEARCH_OPCODE_OPCODES_COL) @@ -5068,7 +5068,7 @@ def copy_to_clipboard(row, column): GuiUtils.delete_menu_entries(menu, [copy_addresses, copy_size, copy_path]) font_size = self.tableWidget_MemoryRegions.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { refresh: self.refresh_table, copy_addresses: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_ADDR_COL), @@ -5237,10 +5237,10 @@ def __init__(self, parent=None): call_dict.close() if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: confirm_dialog = InputDialogForm(item_list=[("You need to dissect code first\nProceed?",)]) - if confirm_dialog.exec_(): + if confirm_dialog.exec(): dissect_code_dialog = DissectCodeDialogForm() dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) - dissect_code_dialog.exec_() + dissect_code_dialog.exec() self.refresh_table() self.tableWidget_References.sortByColumn(REF_STR_ADDR_COL, Qt.AscendingOrder) self.tableWidget_References.selectionModel().currentChanged.connect(self.tableWidget_References_current_changed) @@ -5316,7 +5316,7 @@ def copy_to_clipboard(row, column): GuiUtils.delete_menu_entries(menu, [copy_address, copy_value]) font_size = self.tableWidget_References.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row, REF_STR_ADDR_COL), copy_value: lambda: copy_to_clipboard(selected_row, REF_STR_VAL_COL) @@ -5338,7 +5338,7 @@ def copy_to_clipboard(row): GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row) } @@ -5372,10 +5372,10 @@ def __init__(self, parent=None): call_dict.close() if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: confirm_dialog = InputDialogForm(item_list=[("You need to dissect code first\nProceed?",)]) - if confirm_dialog.exec_(): + if confirm_dialog.exec(): dissect_code_dialog = DissectCodeDialogForm() dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) - dissect_code_dialog.exec_() + dissect_code_dialog.exec() self.refresh_table() self.tableWidget_References.sortByColumn(REF_CALL_ADDR_COL, Qt.AscendingOrder) self.tableWidget_References.selectionModel().currentChanged.connect(self.tableWidget_References_current_changed) @@ -5445,7 +5445,7 @@ def copy_to_clipboard(row, column): GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.tableWidget_References.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row, REF_CALL_ADDR_COL) } @@ -5466,7 +5466,7 @@ def copy_to_clipboard(row): GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row) } @@ -5590,7 +5590,7 @@ def copy_to_clipboard(row): GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec_(event.globalPos()) + action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row) } @@ -5614,4 +5614,4 @@ def exitHandler(): app.aboutToQuit.connect(exitHandler) window = MainForm() window.show() - sys.exit(app.exec_()) + sys.exit(app.exec()) diff --git a/README.md b/README.md index cd8c7802..9b1c8d7b 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Pre-release screenshots: - **Extendable with .so files at runtime** * See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) - **Automatic Trainer Generation:** **[Planned]** - * PINCE provides a trainer auto-generated from current address table on demand by using libpince and PyQT5 together + * PINCE provides a trainer auto-generated from current address table on demand by using libpince and PyQT6 together # Installing ``` @@ -79,14 +79,14 @@ Just run ```sh PINCE.sh``` in the PINCE directory ### For developers: ``` -sudo apt-get install qttools5-dev-tools (qt5 form designer) -sudo apt-get install pyqt5-dev-tools (pyuic5) +sudo apt-get install qttools5-dev-tools (qt6 form designer) +sudo apt-get install pyqt6-dev-tools (pyuic5) sudo pip3 install line_profiler (for performance testing) ``` How to use line_profiler: Add ```@profile``` tag to the desired function and run PINCE with ```sudo kernprof -l -v PINCE.py``` # History - A few weeks till 17/01/2016 : Learned GDB, process of analysis -- 17/01/2016-22/01/2016 : Basic design, grasping of Python3 and Pyqt5, proof-testing +- 17/01/2016-22/01/2016 : Basic design, grasping of Python3 and Pyqt6, proof-testing - 22/01/2016 : First commit - 19/02/2016 : Moved to Github from Bitbucket - 25/02/2016 : First successful implementation of thread injection[Update-08/05/2016 : PINCE now uses ```linux-inject``` as a secondary injection method] diff --git a/install_pince.sh b/install_pince.sh index 5771e709..63578cfd 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -51,10 +51,10 @@ install_scanmem() { else compile_scanmem fi - cp --preserve .libs/libscanmem.so ../libpince/libscanmem/libscanmem.so + cp --preserve .libs/libscanmem.so ../libpince/libscanmem/ cp --preserve gui/scanmem.py ../libpince/libscanmem cp --preserve gui/misc.py ../libpince/libscanmem - echo "Exitting scanmem" + echo "Exiting scanmem" ) # required for relative import, since it will throw an import error if it's just `import misc` sed -i 's/import misc/from \. import misc/g' libpince/libscanmem/scanmem.py @@ -65,10 +65,10 @@ PKG_MGR="apt-get" INSTALL_COMMAND="install" PKG_NAMES_ALL="python3-pip gdb" -PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-pyqt5 libtool libreadline-dev intltool" -PKG_NAMES_SUSE="$PKG_NAMES_ALL python3-qt5" -PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-qt5 libtool readline-devel python3-devel intltool" -PKG_NAMES_ARCH="python-pip python-pyqt5 readline intltool gdb lsb-release" # arch defaults to py3 nowadays +PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-pyqt6 libtool libreadline-dev intltool" +PKG_NAMES_SUSE="$PKG_NAMES_ALL python3-qt6" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-qt6 libtool readline-devel python3-devel intltool" +PKG_NAMES_ARCH="python-pip python-pyqt6 readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES="$PKG_NAMES_DEBIAN" PKG_NAMES_PIP="psutil pexpect distorm3 pygdbmi keyboard" PIP_COMMAND="pip3" diff --git a/libpince/GuiUtils.py b/libpince/GuiUtils.py index d8566268..48ee8dcf 100644 --- a/libpince/GuiUtils.py +++ b/libpince/GuiUtils.py @@ -15,12 +15,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -# PyQt5 isn't needed to run tests with travis. To reduce the testing time and complexity, we ignore the PyQt5 imports -# There'll be no tests for PyQt5 related functions in GuiUtils.py -try: - from PyQt5.QtWidgets import QDesktopWidget -except ImportError: - pass from . import SysUtils, type_defs, common_regexes @@ -41,7 +35,7 @@ def center(window): Args: window (QMainWindow, QWidget etc.): The window that'll be centered to desktop """ - window.move(QDesktopWidget().availableGeometry().center() - window.frameGeometry().center()) + window.frameGeometry().moveCenter(window.screen().availableGeometry().center()) #:tag:GUI @@ -169,18 +163,13 @@ def remove_entries(menu): try: QAction_list.index(action) except ValueError: - if action.menu(): - remove_entries(action.menu()) + pass else: menu.removeAction(action) def clean_entries(menu): for action in menu.actions(): - if action.menu(): - clean_entries(action.menu()) - if not action.menu().actions(): - menu.removeAction(action.menu().menuAction()) - elif action.isSeparator(): + if action.isSeparator(): actions = menu.actions() current_index = actions.index(action) if len(actions) == 1 or (current_index == 0 and actions[1].isSeparator()) or \ diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 78ea7b96..84b7bc5f 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -20,7 +20,6 @@ import collections.abc, queue, sys - class CONST_TIME: GDB_INPUT_SLEEP = sys.float_info.min @@ -508,17 +507,14 @@ def delete_queue(self, queue_instance): class KeyboardModifiersTupleDict(collections.abc.Mapping): - def _convert_to_int(self, tuple_key): - return tuple(int(x) for x in tuple_key) - def __init__(self, OrderedDict_like_list): new_dict = {} - for tuple_key, value in OrderedDict_like_list: - new_dict[self._convert_to_int(tuple_key)] = value + for keycomb, value in OrderedDict_like_list: + new_dict[keycomb.toCombined()] = value self._storage = new_dict - def __getitem__(self, tuple_key): - return self._storage[self._convert_to_int(tuple_key)] + def __getitem__(self, keycomb): + return self._storage[keycomb.toCombined()] def __iter__(self): return iter(self._storage) From f6a930918b0594daada4a512edc8b15fb1e012d9 Mon Sep 17 00:00:00 2001 From: N00byKing Date: Sat, 1 Oct 2022 20:29:42 +0200 Subject: [PATCH 073/487] PyQT6 Upgrade, Pass 2 --- PINCE.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/PINCE.py b/PINCE.py index b6e01b4f..2de2eaaf 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3664,7 +3664,7 @@ def __init__(self, parent=None): global instances instances.append(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.listWidget.contextMenuEvent = self.listWidget_context_menu_event self.listWidget.currentRowChanged.connect(self.change_display) self.listWidget.itemDoubleClicked.connect(self.listWidget_item_double_clicked) @@ -3751,7 +3751,7 @@ class FloatRegisterWidgetForm(QTabWidget, FloatRegisterWidget): def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.update_registers() self.tableWidget_FPU.itemDoubleClicked.connect(self.set_register) self.tableWidget_XMM.itemDoubleClicked.connect(self.set_register) @@ -3792,7 +3792,7 @@ def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.listWidget_ReturnAddresses.currentRowChanged.connect(self.update_frame_info) self.update_stacktrace() @@ -3814,7 +3814,7 @@ def __init__(self, parent=None): global instances instances.append(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) # Saving the original function because super() doesn't work when we override functions like this self.tableWidget_Instructions.keyPressEvent_original = self.tableWidget_Instructions.keyPressEvent @@ -3887,7 +3887,7 @@ def __init__(self, parent=None): global instances instances.append(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_BreakpointInfo.contextMenuEvent = self.tableWidget_BreakpointInfo_context_menu_event # Saving the original function because super() doesn't work when we override functions like this @@ -4031,7 +4031,7 @@ def __init__(self, address, length, watchpoint_type, parent=None): global instances instances.append(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) if watchpoint_type == type_defs.WATCHPOINT_TYPE.WRITE_ONLY: string = "writing to" elif watchpoint_type == type_defs.WATCHPOINT_TYPE.READ_ONLY: @@ -4121,7 +4121,7 @@ def __init__(self, address, instruction, parent=None): self.parent = lambda: parent global instances instances.append(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) GuiUtils.center_to_parent(self) self.setWindowTitle("Addresses accessed by instruction '" + instruction + "'") label_text = "Enter the register expression(s) you want to track" \ @@ -4437,7 +4437,7 @@ def __init__(self, parent=None): global instances instances.append(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.textBrowser_AddressInfo.setFixedHeight(100) self.pushButton_Search.clicked.connect(self.refresh_table) self.shortcut_search = QShortcut(QKeySequence("Return"), self) @@ -4628,7 +4628,7 @@ def __init__(self, is_window=False, parent=None): instances.append(self) if is_window: GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.show_type_defs() self.splitter.setStretchFactor(0, 1) self.widget_Resources.resize(700, self.widget_Resources.height()) @@ -4873,7 +4873,7 @@ def __init__(self, parent=None): GuiUtils.center(self) global instances instances.append(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.contents = "" self.refresh_contents() self.refresh_timer = QTimer() @@ -4929,7 +4929,7 @@ def __init__(self, start="", end="", parent=None): global instances instances.append(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.lineEdit_Start.setText(start) self.lineEdit_End.setText(end) self.tableWidget_Opcodes.setColumnWidth(SEARCH_OPCODE_ADDR_COL, 250) @@ -5019,7 +5019,7 @@ def __init__(self, parent=None): global instances instances.append(self) GuiUtils.center(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.refresh_table() self.tableWidget_MemoryRegions.contextMenuEvent = self.tableWidget_MemoryRegions_context_menu_event self.tableWidget_MemoryRegions.itemDoubleClicked.connect(self.tableWidget_MemoryRegions_item_double_clicked) @@ -5224,7 +5224,7 @@ def __init__(self, parent=None): global instances instances.append(self) GuiUtils.center_to_parent(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_References.setColumnWidth(REF_STR_ADDR_COL, 150) self.tableWidget_References.setColumnWidth(REF_STR_COUNT_COL, 80) self.splitter.setStretchFactor(0, 1) @@ -5360,7 +5360,7 @@ def __init__(self, parent=None): global instances instances.append(self) GuiUtils.center_to_parent(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_References.setColumnWidth(REF_CALL_ADDR_COL, 480) self.splitter.setStretchFactor(0, 1) self.listWidget_Referrers.resize(400, self.listWidget_Referrers.height()) @@ -5488,7 +5488,7 @@ def __init__(self, int_address, parent=None): global instances instances.append(self) GuiUtils.center_to_parent(self) - self.setWindowFlags(Qt.Window) + self.setWindowFlags(Qt.WindowType.Window) self.splitter.setStretchFactor(0, 1) self.textBrowser_DisasInfo.resize(600, self.textBrowser_DisasInfo.height()) self.referenced_hex = hex(int_address) From a82756bcfcfd6835085f35a078bc070c4828b5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 6 Oct 2022 01:31:00 +0300 Subject: [PATCH 074/487] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd8c7802..f0153c53 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,8 @@ If you like to uninstall PINCE, just delete this folder, almost everything is in - Check https://github.com/korcankaraokcu/PINCE/issues/116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` # Running PINCE -Just run ```sh PINCE.sh``` in the PINCE directory +Just run ```sh PINCE.sh``` in the PINCE directory +In some cases, ```sudo sh PINCE.sh``` works too, as reported in https://github.com/korcankaraokcu/PINCE/issues/138 ### For developers: ``` From 109e7b72ca2dfc5b345bb1af00931443fc77629c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 8 Oct 2022 16:41:55 +0300 Subject: [PATCH 075/487] Update pince.sh comments --- PINCE.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/PINCE.sh b/PINCE.sh index e89fe068..6c4dcaf6 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -22,5 +22,6 @@ OS=$(lsb_release -si) if [ $OS = "Debian" ] && [ -x "$(command -v gksudo)" ]; then gksudo python3 PINCE.py else + # Preserve env vars to keep settings like theme preferences sudo -E python3 PINCE.py fi From 57b34caa2e2fecbefef4dd21d08fd2be4bad7ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 8 Oct 2022 19:04:02 +0300 Subject: [PATCH 076/487] Fix dark theme issues with Hex Edit dialog --- PINCE.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index e01c8969..a9cac8d8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4575,7 +4575,7 @@ def lineEdit_HexView_text_edited(self): aob_array = aob_string.split() try: self.lineEdit_AsciiView.setText(SysUtils.aob_to_str(aob_array, "utf-8")) - self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: white;}") + self.lineEdit_HexView.setStyleSheet("") # This should set background color back to QT default except ValueError: self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: red;}") @@ -4583,7 +4583,7 @@ def lineEdit_AsciiView_text_edited(self): ascii_str = self.lineEdit_AsciiView.text() try: self.lineEdit_HexView.setText(SysUtils.str_to_aob(ascii_str, "utf-8")) - self.lineEdit_AsciiView.setStyleSheet("QLineEdit {background-color: white;}") + self.lineEdit_AsciiView.setStyleSheet("") except ValueError: self.lineEdit_AsciiView.setStyleSheet("QLineEdit {background-color: red;}") From 84053a0de321ab8121e774070788b4d896e27dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 8 Oct 2022 20:47:26 +0300 Subject: [PATCH 077/487] Change hex edit to use GDB_Engine modify_instruction function --- PINCE.py | 13 +++++++++---- libpince/GDB_Engine.py | 41 ++++++++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/PINCE.py b/PINCE.py index a9cac8d8..5ba512a9 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3852,9 +3852,9 @@ def restore_instruction(self, selected_address_int): self.refresh_all() def refresh(self): - noped_instructions = GDB_Engine.get_noped_instructions() - self.tableWidget_Instructions.setRowCount(len(noped_instructions)) - for row, (address, aob) in enumerate(noped_instructions.items()): + modified_instructions = GDB_Engine.get_modified_instructions() + self.tableWidget_Instructions.setRowCount(len(modified_instructions)) + for row, (address, aob) in enumerate(modified_instructions.items()): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) GuiUtils.resize_to_contents(self.tableWidget_Instructions) @@ -4611,7 +4611,12 @@ def accept(self): QMessageBox.information(self, "Error", expression + " isn't a valid expression") return value = self.lineEdit_HexView.text() - GDB_Engine.write_memory(address, type_defs.VALUE_INDEX.INDEX_AOB, value) + + try: + address = int(address, 0) + except ValueError: + return + GDB_Engine.modify_instruction(address, value) super(HexEditDialogForm, self).accept() diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 764fb68d..86d95c39 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -59,7 +59,7 @@ #:doc: # A dictionary. Holds address and aob of instructions that were nop'ed out # Format: {address1:orig_instruction1_aob, address2:orig_instruction2_aob, ...} -noped_instructions_dict = {} +modified_instructions_dict = {} #:tag:GDBInformation #:doc: @@ -1304,15 +1304,15 @@ def hex_dump(address, offset): #:tag:MemoryRW -def get_noped_instructions(): - """Returns currently NOP'ed out instructions +def get_modified_instructions(): + """Returns currently modified instructions Returns: - dict: A dictionary where the key is the start address of instruction and value is the aob before NOP'ing + dict: A dictionary where the key is the start address of instruction and value is the aob before modifying """ - global noped_instructions_dict - return noped_instructions_dict + global modified_instructions_dict + return modified_instructions_dict #:tag:MemoryRW @@ -1326,16 +1326,35 @@ def nop_instruction(start_address, array_of_bytes): Returns: None """ - global noped_instructions_dict - noped_instructions_dict[start_address] = array_of_bytes + global modified_instructions_dict + modified_instructions_dict[start_address] = array_of_bytes nop_aob = '90 ' * len(array_of_bytes.split()) write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, nop_aob) +#:tag:MemoryRW +def modify_instruction(start_address, array_of_bytes): + """Replaces an instruction's opcodes with a new AOB + + Args: + start_address (int): Self-explanatory + array_of_bytes (str): String that contains the replacement bytes of the instruction + + Returns: + None + """ + length = len(array_of_bytes.split()) + old_aob = " ".join(hex_dump(start_address, length)) + + global modified_instructions_dict + modified_instructions_dict[start_address] = old_aob + write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, array_of_bytes) + + #:tag:MemoryRW def restore_instruction(start_address): - """Restores a NOP'ed out instruction to it's original opcodes + """Restores a modified instruction to it's original opcodes Args: start_address (int): Self-explanatory @@ -1343,8 +1362,8 @@ def restore_instruction(start_address): Returns: None """ - global noped_instructions_dict - array_of_bytes = noped_instructions_dict.pop(start_address) + global modified_instructions_dict + array_of_bytes = modified_instructions_dict.pop(start_address) write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, array_of_bytes) From 24ed57641dc907eb022f57d63f390ecb79241421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 8 Oct 2022 20:57:13 +0300 Subject: [PATCH 078/487] Change nop_instruction function signature to prevent API misuse --- PINCE.py | 2 +- libpince/GDB_Engine.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 5ba512a9..3adc1b3d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2652,7 +2652,7 @@ def nop_instruction(self): current_address = SysUtils.extract_address(current_address_text) current_address_int = int(current_address, 16) array_of_bytes = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() - GDB_Engine.nop_instruction(current_address_int, array_of_bytes) + GDB_Engine.nop_instruction(current_address_int, len(array_of_bytes.split())) self.refresh_disassemble_view() @GDB_Engine.execute_with_temporary_interruption diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 86d95c39..20164b68 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -1316,20 +1316,21 @@ def get_modified_instructions(): #:tag:MemoryRW -def nop_instruction(start_address, array_of_bytes): +def nop_instruction(start_address, length_of_instr): """Replaces an instruction's opcodes with NOPs Args: start_address (int): Self-explanatory - array_of_bytes (str): String that contains the bytes of the instruction + length_of_instr (int): Length of the instruction that'll be NOP'ed Returns: None """ + old_aob = " ".join(hex_dump(start_address, length_of_instr)) global modified_instructions_dict - modified_instructions_dict[start_address] = array_of_bytes + modified_instructions_dict[start_address] = old_aob - nop_aob = '90 ' * len(array_of_bytes.split()) + nop_aob = '90 ' * length_of_instr write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, nop_aob) From d5859b6ee161421c8a7bfd8b323039e859f98c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 9 Oct 2022 02:43:52 +0300 Subject: [PATCH 079/487] Add new Edit Instruction dialog in disassembly view --- GUI/EditInstructionDialog.py | 60 ++++++++++++++++ GUI/EditInstructionDialog.ui | 117 +++++++++++++++++++++++++++++++ GUI/RestoreInstructionsWidget.py | 11 ++- GUI/RestoreInstructionsWidget.ui | 5 ++ PINCE.py | 74 +++++++++++++++++++ libpince/SysUtils.py | 26 ++++++- 6 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 GUI/EditInstructionDialog.py create mode 100644 GUI/EditInstructionDialog.ui diff --git a/GUI/EditInstructionDialog.py b/GUI/EditInstructionDialog.py new file mode 100644 index 00000000..3bdbe8e8 --- /dev/null +++ b/GUI/EditInstructionDialog.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'EditInstructionDialog.ui' +# +# Created by: PyQt5 UI code generator 5.15.7 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.setEnabled(True) + Dialog.resize(500, 124) + Dialog.setMaximumSize(QtCore.QSize(16777215, 124)) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.lineEdit_OpCodes = QtWidgets.QLineEdit(Dialog) + self.lineEdit_OpCodes.setObjectName("lineEdit_OpCodes") + self.gridLayout.addWidget(self.lineEdit_OpCodes, 1, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(Dialog) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.lineEdit_Address = QtWidgets.QLineEdit(Dialog) + self.lineEdit_Address.setEnabled(False) + self.lineEdit_Address.setAutoFillBackground(False) + self.lineEdit_Address.setReadOnly(True) + self.lineEdit_Address.setObjectName("lineEdit_Address") + self.horizontalLayout.addWidget(self.lineEdit_Address) + self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.lineEdit_Instruction = QtWidgets.QLineEdit(Dialog) + self.lineEdit_Instruction.setEnabled(False) + self.lineEdit_Instruction.setReadOnly(True) + self.lineEdit_Instruction.setObjectName("lineEdit_Instruction") + self.horizontalLayout.addWidget(self.lineEdit_Instruction) + self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Edit Instruction")) + self.label.setText(_translate("Dialog", "Address:")) + self.label_2.setText(_translate("Dialog", "Instruction:")) diff --git a/GUI/EditInstructionDialog.ui b/GUI/EditInstructionDialog.ui new file mode 100644 index 00000000..fedf26cf --- /dev/null +++ b/GUI/EditInstructionDialog.ui @@ -0,0 +1,117 @@ + + + Dialog + + + true + + + + 0 + 0 + 500 + 124 + + + + + 16777215 + 124 + + + + Edit Instruction + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + Address: + + + + + + + false + + + false + + + true + + + + + + + Instruction: + + + + + + + false + + + true + + + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/GUI/RestoreInstructionsWidget.py b/GUI/RestoreInstructionsWidget.py index 1501dee7..3b4c37af 100644 --- a/GUI/RestoreInstructionsWidget.py +++ b/GUI/RestoreInstructionsWidget.py @@ -2,9 +2,10 @@ # Form implementation generated from reading ui file 'RestoreInstructionsWidget.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt5 UI code generator 5.15.7 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets @@ -21,12 +22,14 @@ def setupUi(self, Form): self.tableWidget_Instructions.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.tableWidget_Instructions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.tableWidget_Instructions.setObjectName("tableWidget_Instructions") - self.tableWidget_Instructions.setColumnCount(2) + self.tableWidget_Instructions.setColumnCount(3) self.tableWidget_Instructions.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.tableWidget_Instructions.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() self.tableWidget_Instructions.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Instructions.setHorizontalHeaderItem(2, item) self.tableWidget_Instructions.horizontalHeader().setStretchLastSection(True) self.tableWidget_Instructions.verticalHeader().setVisible(False) self.tableWidget_Instructions.verticalHeader().setDefaultSectionSize(16) @@ -43,4 +46,6 @@ def retranslateUi(self, Form): item = self.tableWidget_Instructions.horizontalHeaderItem(0) item.setText(_translate("Form", "Address")) item = self.tableWidget_Instructions.horizontalHeaderItem(1) + item.setText(_translate("Form", "Original OpCode")) + item = self.tableWidget_Instructions.horizontalHeaderItem(2) item.setText(_translate("Form", "Original Instruction")) diff --git a/GUI/RestoreInstructionsWidget.ui b/GUI/RestoreInstructionsWidget.ui index 08232cce..89db2a37 100644 --- a/GUI/RestoreInstructionsWidget.ui +++ b/GUI/RestoreInstructionsWidget.ui @@ -45,6 +45,11 @@ Address + + + Original OpCode + + Original Instruction diff --git a/PINCE.py b/PINCE.py index 3adc1b3d..a2a49da6 100755 --- a/PINCE.py +++ b/PINCE.py @@ -57,6 +57,7 @@ from GUI.TraceInstructionsWindow import Ui_MainWindow as TraceInstructionsWindow from GUI.FunctionsInfoWidget import Ui_Form as FunctionsInfoWidget from GUI.HexEditDialog import Ui_Dialog as HexEditDialog +from GUI.EditInstructionDialog import Ui_Dialog as EditInstructionDialog from GUI.LibpinceReferenceWidget import Ui_Form as LibpinceReferenceWidget from GUI.LogFileWidget import Ui_Form as LogFileWidget from GUI.SearchOpcodeWidget import Ui_Form as SearchOpcodeWidget @@ -146,6 +147,7 @@ def get_hotkeys(): # represents the index of columns in instructions restore table INSTR_ADDR_COL = 0 INSTR_AOB_COL = 1 +INSTR_NAME_COL = 2 # represents the index of columns in breakpoint table BREAK_NUM_COL = 0 @@ -2646,6 +2648,13 @@ def set_address(self): GDB_Engine.set_convenience_variable("pc", current_address) self.refresh_disassemble_view() + def edit_instruction(self): + selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() + current_address = SysUtils.extract_address(current_address_text) + opcode = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() + EditInstructionDialogForm(current_address, opcode, self).exec_() + def nop_instruction(self): selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -3454,6 +3463,7 @@ def copy_all_columns(row): if not GDB_Engine.check_address_in_breakpoints(current_address_int): GuiUtils.delete_menu_entries(menu, [add_condition]) menu.addSeparator() + edit_instruction = menu.addAction("Edit instruction") nop_instruction = menu.addAction("Replace instruction with NOPs") if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() == '90': GuiUtils.delete_menu_entries(menu, [nop_instruction]) @@ -3484,6 +3494,7 @@ def copy_all_columns(row): change_comment: lambda: self.change_bookmark_comment(current_address_int), toggle_breakpoint: self.toggle_breakpoint, add_condition: lambda: self.add_breakpoint_condition(current_address_int), + edit_instruction: self.edit_instruction, nop_instruction: self.nop_instruction, track_breakpoint: self.exec_track_breakpoint_dialog, trace_instructions: self.exec_trace_instructions_dialog, @@ -3857,6 +3868,8 @@ def refresh(self): for row, (address, aob) in enumerate(modified_instructions.items()): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) + instr_name = SysUtils.get_opcode_name(address, aob, GDB_Engine.get_inferior_arch()) + self.tableWidget_Instructions.setItem(row, INSTR_NAME_COL, QTableWidgetItem(instr_name)) GuiUtils.resize_to_contents(self.tableWidget_Instructions) def refresh_all(self): @@ -4535,6 +4548,67 @@ def closeEvent(self, QCloseEvent): instances.remove(self) +class EditInstructionDialogForm(QDialog, EditInstructionDialog): + def __init__(self, address, opcode, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + self.orig_opcode = opcode + self.orig_instr = SysUtils.get_opcode_name(int(address, 0), opcode, GDB_Engine.get_inferior_arch()) + self.is_valid = False + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) + self.lineEdit_Address.setText(address) + self.lineEdit_OpCodes.setText(opcode) + self.lineEdit_Instruction.setText(self.orig_instr) + self.lineEdit_OpCodes.textEdited.connect(self.lineEdit_OpCodes_text_edited) + + def set_not_valid(self, instruction, is_original_opcode): + if is_original_opcode: + self.lineEdit_OpCodes.setStyleSheet("") + else: + self.lineEdit_OpCodes.setStyleSheet("QLineEdit {background-color: red;}") + self.lineEdit_Instruction.setText(instruction) + self.is_valid = False + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) + + def lineEdit_OpCodes_text_edited(self): + aob_string = self.lineEdit_OpCodes.text() + if not SysUtils.parse_string(aob_string, type_defs.VALUE_INDEX.INDEX_AOB): + self.set_not_valid("???", False) + return + + if len(aob_string) != len(self.orig_opcode): + self.set_not_valid("???", False) + return + + if aob_string == self.orig_opcode: + self.set_not_valid(self.orig_instr, True) + return + + self.lineEdit_OpCodes.setStyleSheet("") + self.is_valid = True + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True) + self.refresh_view() + + def refresh_view(self): + self.lineEdit_Instruction.clear() + address = int(self.lineEdit_Address.text(), 0) + opcode = self.lineEdit_OpCodes.text() + instr_str = SysUtils.get_opcode_name(address, opcode, GDB_Engine.get_inferior_arch()) + self.lineEdit_Instruction.setText(instr_str) + + def accept(self): + if not self.is_valid: + return + + # No need to check for validity since address is not editable and opcode is checked in text_edited + address = int(self.lineEdit_Address.text(), 0) + opcode = self.lineEdit_OpCodes.text() + GDB_Engine.modify_instruction(address, opcode) + self.parent().refresh_hex_view() + self.parent().refresh_disassemble_view() + super(EditInstructionDialogForm, self).accept() + + class HexEditDialogForm(QDialog, HexEditDialog): def __init__(self, address, parent=None): super().__init__(parent=parent) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 387fed61..e7cd4587 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -25,7 +25,7 @@ except ImportError: print("WARNING: GDB couldn't locate the package psutil, psutil based user-defined functions won't work\n" + "If you are getting this message without invoking GDB, it means that installation has failed, well, sort of") -import os, shutil, sys, binascii, pickle, json, traceback, re, pwd, pathlib +import os, shutil, sys, binascii, pickle, json, traceback, re, pwd, pathlib, distorm3 from . import type_defs, common_regexes from collections import OrderedDict from importlib.machinery import SourceFileLoader @@ -662,6 +662,30 @@ def modulo_address(int_address, arch_type): raise Exception("arch_type must be a member of type_defs.INFERIOR_ARCH") +#:tag:Utilities +def get_opcode_name(address, opcode_aob, arch_type): + """Returns the instruction name from the opcode + + Args: + address (int): The address where the opcode starts from + opcode_aob (str): String that contains an opcode written as an array of bytes + arch_type (int): Architecture type (x86, x64). Can be a member of type_defs.INFERIOR_ARCH + + Returns: + str: Assembly instruction name that decodes to the supplied OpCode + """ + if arch_type == type_defs.INFERIOR_ARCH.ARCH_64: + disas_option = distorm3.Decode64Bits + elif arch_type == type_defs.INFERIOR_ARCH.ARCH_32: + disas_option = distorm3.Decode32Bits + try: + bytecode = bytes.fromhex(opcode_aob.replace(" ", "")) + except ValueError: + return "???" + disas_data = distorm3.Decode(address, bytecode, disas_option) + return disas_data[0][2] + + #:tag:ValueType def aob_to_str(list_of_bytes, encoding="ascii"): """Converts given array of hex strings to str From 04c53dc39c5a3b8e48e39a780dfd8796bb578b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 9 Oct 2022 02:52:22 +0300 Subject: [PATCH 080/487] Prevent original instruction being lost if edited a second time --- libpince/GDB_Engine.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 20164b68..1d1ec1e9 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -1328,7 +1328,8 @@ def nop_instruction(start_address, length_of_instr): """ old_aob = " ".join(hex_dump(start_address, length_of_instr)) global modified_instructions_dict - modified_instructions_dict[start_address] = old_aob + if start_address not in modified_instructions_dict: + modified_instructions_dict[start_address] = old_aob nop_aob = '90 ' * length_of_instr write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, nop_aob) @@ -1349,7 +1350,8 @@ def modify_instruction(start_address, array_of_bytes): old_aob = " ".join(hex_dump(start_address, length)) global modified_instructions_dict - modified_instructions_dict[start_address] = old_aob + if start_address not in modified_instructions_dict: + modified_instructions_dict[start_address] = old_aob write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, array_of_bytes) From 3b44975b2bf94d8a4e521f14beef4752de91d63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 20 Oct 2022 03:29:05 +0300 Subject: [PATCH 081/487] Update install_pince.sh --- install_pince.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index 5771e709..d5f030b1 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -64,10 +64,10 @@ OS_NAME="Debian" PKG_MGR="apt-get" INSTALL_COMMAND="install" -PKG_NAMES_ALL="python3-pip gdb" -PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-pyqt5 libtool libreadline-dev intltool" -PKG_NAMES_SUSE="$PKG_NAMES_ALL python3-qt5" -PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-qt5 libtool readline-devel python3-devel intltool" +PKG_NAMES_ALL="python3-pip gdb libtool intltool" +PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-pyqt5 libreadline-dev" +PKG_NAMES_SUSE="$PKG_NAMES_ALL python3-qt5 gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 make" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-qt5 readline-devel python3-devel" PKG_NAMES_ARCH="python-pip python-pyqt5 readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES="$PKG_NAMES_DEBIAN" PKG_NAMES_PIP="psutil pexpect distorm3 pygdbmi keyboard" From 633b66f18eb1bfa84a4979a05b1de4590108fbe8 Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Fri, 8 Mar 2019 16:17:18 +0100 Subject: [PATCH 082/487] Don't write Python bytecode This might cause conflicts when installing PINCE via a package manager, as running the program as root just allows it to drop its bytecode files where it wants and the installation directory would therefore contain files that aren't in the original package, causing warnings or even errors in the process. Disabling writing bytecode to files might also keep users from having undeletable files in their home directory. --- PINCE.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.sh b/PINCE.sh index 6c4dcaf6..c0476b25 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -20,8 +20,8 @@ along with this program. If not, see . OS=$(lsb_release -si) # Get rid of gksudo when Debian 8 support drops or polkit gets implemented if [ $OS = "Debian" ] && [ -x "$(command -v gksudo)" ]; then - gksudo python3 PINCE.py + gksudo env PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py else # Preserve env vars to keep settings like theme preferences - sudo -E python3 PINCE.py + sudo -E PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py fi From ac91e30d8ff70e5bb2ced886459bfa25382b4e26 Mon Sep 17 00:00:00 2001 From: Viktor Horsmanheimo Date: Thu, 20 Oct 2022 17:51:41 +0300 Subject: [PATCH 083/487] Fix shellcheck issues on install scripts Also removed unnecessary grepping for how many cores are available. `make -j` automatically uses the maximum amount if none are specified. --- install_gdb.sh | 21 ++++++++++++--------- install_pince.sh | 9 ++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/install_gdb.sh b/install_gdb.sh index 50ca2db3..8ee358c7 100644 --- a/install_gdb.sh +++ b/install_gdb.sh @@ -22,7 +22,7 @@ along with this program. If not, see . GDB_VERSION="gdb-10.2" mkdir -p gdb_pince -cd gdb_pince +cd gdb_pince || exit # clean the directory if another installation happened rm -rf $GDB_VERSION @@ -31,29 +31,32 @@ if [ ! -e ${GDB_VERSION}.tar.gz ] ; then wget "http://ftp.gnu.org/gnu/gdb/${GDB_VERSION}.tar.gz" fi tar -zxvf ${GDB_VERSION}.tar.gz -cd $GDB_VERSION +cd $GDB_VERSION || exit echo "-------------------------------------------------------------------------" echo "DISCLAIMER" echo "-------------------------------------------------------------------------" echo "If you're not on debian or a similar distro with the 'apt' package manager the follow will not work if you don't have gcc and g++ installed" echo "Please install them manually for this to work, this issue will be addressed at a later date" -command -v gcc g++ # extremely lazy fix for other distros, if gcc&g++ is available it will work, if not it won't -if [ $? -gt 0 ]; then + + # extremely lazy fix for other distros, if gcc&g++ is available it will work, if not it won't +if ! command -v gcc g++; then # Dependencies required for compiling GDB sudo apt-get install python3-dev - sudo apt-get install gcc g++ - if [ $? -gt 0 ]; then + + if ! sudo apt-get install gcc g++; then sudo apt-get install software-properties-common sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update - sudo apt-get install gcc g++ - if [ $? -gt 0 ]; then + + if ! sudo apt-get install gcc g++; then echo "Failed to install gcc or g++, aborting..." exit 1 fi fi fi -CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j $(grep -m 1 "cpu cores" /proc/cpuinfo | cut -d: -f 2 | xargs) MAKEINFO=true && sudo make -C gdb install + +CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j MAKEINFO=true && sudo make -C gdb install + if [ ! -e bin/gdb ] ; then echo "Failed to install GDB, restart the installation process" exit 1 diff --git a/install_pince.sh b/install_pince.sh index d5f030b1..e5c3c777 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -27,14 +27,14 @@ CURRENT_USER="$(who mom likes | awk '{print $1}')" compile_scanmem() { sh autogen.sh ./configure --prefix="$(pwd)" - make -j $(grep -m 1 "cpu cores" /proc/cpuinfo | cut -d: -f 2 | xargs) libscanmem.la + make -j libscanmem.la chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file } install_scanmem() { echo "Downloading scanmem" git submodule update --init --recursive - + if [ ! -d "libpince/libscanmem" ]; then mkdir libpince/libscanmem chown -R "${CURRENT_USER}":"${CURRENT_USER}" libpince/libscanmem @@ -42,7 +42,7 @@ install_scanmem() { ( echo "Entering scanmem" cd scanmem || exit - if [ -d "./.libs" ]; then + if [ -d "./.libs" ]; then echo "Recompile scanmem? [y/n]" read -r answer if echo "$answer" | grep -iq "^[Yy]"; then @@ -77,6 +77,7 @@ LSB_RELEASE="$(command -v lsb_release)" if [ -n "$LSB_RELEASE" ] ; then OS_NAME="$(${LSB_RELEASE} -d -s)" else + # shellcheck disable=SC1091 . /etc/os-release OS_NAME="$NAME" fi @@ -98,7 +99,9 @@ case "$OS_NAME" in ;; esac +# shellcheck disable=SC2086 sudo ${PKG_MGR} ${INSTALL_COMMAND} ${PKG_NAMES} +# shellcheck disable=SC2086 sudo ${PIP_COMMAND} install ${PKG_NAMES_PIP} install_scanmem From 67326bb995cbeb09bc69c7ed17260a48678c1459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 24 Nov 2022 09:06:45 +0300 Subject: [PATCH 084/487] Remove unused internal functions --- libpince/GDB_Engine.py | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 764fb68d..362ad34e 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -353,41 +353,16 @@ def execute_func_temporary_interruption(func, *args, **kwargs): """ old_status = inferior_status if old_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - ___internal_interrupt_inferior(type_defs.STOP_REASON.PAUSE) + interrupt_inferior(type_defs.STOP_REASON.PAUSE) result = func(*args, **kwargs) if old_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: try: - ___internal_continue_inferior() + continue_inferior() except type_defs.InferiorRunningException: pass return result -#:tag:Debug -def ___internal_continue_inferior(): - """ - Continue the inferior - DOES NOT TOGGLE temporary_execution_condition - you should always use the real one - if you don't toggle the temporary_execution_condition it will never be able to break - """ - - send_command("c") - - -#:tag:Debug -def ___internal_interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): - """Interrupt the inferior - see notes on ___internal_continue_inferior - Args: - interrupt_reason (int): Just changes the global variable stop_reason. Can be a member of type_defs.STOP_REASON - """ - global stop_reason - send_command("c", control=True) - wait_for_stop() - stop_reason = interrupt_reason - - #:tag:Debug def can_attach(pid): """Check if we can attach to the target From e267060c294171c6b4b1e2f9de99ce7d59e1bc2c Mon Sep 17 00:00:00 2001 From: "William L. DeRieux IV" Date: Tue, 10 Jan 2023 07:48:23 -0500 Subject: [PATCH 085/487] Fixed Namespaces, HexView, Disassembly view, and keypress events (#1) * + Fixed some Qt namespace usages (eg. named enums) + Fixed display of messagebox dialogs (needed to use the StandardButton enum) + Fixed some tracebacks in memory view when no process has been attached + Fixed PointHandCursor for CPU Registers and Flags (needed to the CursorShape enum) + Fixed First scan, Next Scan, etc, don't do anything if no process has been attached + Cleaned-up data() functions in Ascii/HexModels -- simplified the logic and it now avoids an Out of Range exception. + Don't show a context menu, when right-clicking, on the cheat list, nor show a dialog to confirm clearing it, if the list is empty. + Disable Next Scan/Undo Scan until a scan has been started. + Fix Hex checkbox to properly enable the hexadecimal validator (was a type comparison issue) + Moved the Hex/Dec regular expressions to a constant form-level variable (declaring it only once) The regex doesn't change, so declaring a new expresion every time the checkstate changed doesn't make any sense. + Fix opening of gdb console (needed to use the enum name CompletionMode) + Fix argument Out of Range exception in SysUtils.ignore_exceptions (it passes a second argument, a boolean value) * + added TODO.md (just a record of some stuff that needs to be done) * update TODO, added date * Update TODO.md Fixed formatting of the todo * Another round of updates -- dealing with the Hex View (in the Memory view dialog) + Fixed display issue in MemoryView Hex Table + Fixed issue with width of hex digits (eg. 12 34 45, instead 1 3 4) + Fixed some more enum namespaces + Updated TODO * + mark some stuff in TODO as fixed * + updated hex/ascii view + Fixed medium-sized gap between hex and ascii view + Fixed the ascii view text (only show printable chars, non-printable chars will show as a period) * + Completed TODO entries -- for now (scrolling now works and keypress events are working) + Fixed keyboard shortcuts so that they function + Fixed scrolling in Dissassebly and Hex Views via + Vertial Scrollbar + Page/Up Down + Fixed Hex/Ascii represention when memory region is invalid + Updated TODO to reflect what has been fixed * restore the function SysUtils.py::ignore_exceptions::wrapper to its original state. * (updated a variable name) -- restore the function SysUtils.py::ignore_exceptions::wrapper to its original state. * + fixed setting of WindowFlags, Attributes, and Column Sorting -- must use the enum name to refer to a member, eg. Qt.ENUM_NAME.MEMBER instead of Qt.MEMBER * + fixed use of QTextCursor.MoveOperation members (Start, End, etc) * + update aob_to_str -- replace non-string values with a period (just like for ??) * + updated HexView::resize_to_contents -- cast size to an int before calling setting min/max Width * + fixed QMovie CacheMode (CacheAll) * + fixed SysUtils::aob_to_str to handle the situtation where a list of bytes could be a string or a list also disabled the replacement of non-printable characters with a period '.' since, ATM, it will interfere with the hex edit dialog. + fixed consistency in SysUtils::str_to_aob -- the encoding parameter was not being used. --- .gitignore | 1 + GUI/CustomAbstractTableModels/AsciiModel.py | 20 +- GUI/CustomAbstractTableModels/HexModel.py | 20 +- GUI/CustomLabels/FlagRegisterLabel.py | 4 +- GUI/CustomLabels/RegisterLabel.py | 6 +- GUI/CustomTableViews/HexView.py | 11 +- GUI/CustomValidators/HexValidator.py | 6 +- GUI/MemoryViewerWindow.py | 7 + PINCE.py | 337 +++++++++++++++----- TODO.md | 21 ++ libpince/GDB_Engine.py | 8 +- libpince/SysUtils.py | 39 ++- libpince/type_defs.py | 5 +- 13 files changed, 365 insertions(+), 120 deletions(-) create mode 100644 TODO.md diff --git a/.gitignore b/.gitignore index d924e09a..28543fcd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ libpince/libscanmem/* *.py[cod] *$py.class gdb_pince/* +*.gnbs.conf diff --git a/GUI/CustomAbstractTableModels/AsciiModel.py b/GUI/CustomAbstractTableModels/AsciiModel.py index bcd42c42..36964772 100644 --- a/GUI/CustomAbstractTableModels/AsciiModel.py +++ b/GUI/CustomAbstractTableModels/AsciiModel.py @@ -26,15 +26,11 @@ def __init__(self, row_count, column_count, parent=None): super().__init__(row_count, column_count, parent) def data(self, QModelIndex, int_role=None): - if not QModelIndex.isValid(): - return QVariant() - if int_role == Qt.ItemDataRole.BackgroundRole: - address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() - if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: - return QVariant(QColor(Qt.red)) - elif int_role != Qt.DisplayRole: - return QVariant() - if self.data_array is None: - return QVariant() - return QVariant( - SysUtils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()])) + if (not self.data_array is None and len(self.data_array) > 0 and QModelIndex.isValid()): + if int_role == Qt.ItemDataRole.BackgroundRole: + address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() + if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: + return QVariant(QColor.red) + elif int_role == Qt.ItemDataRole.DisplayRole: + return QVariant(SysUtils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()])) + return QVariant() diff --git a/GUI/CustomAbstractTableModels/HexModel.py b/GUI/CustomAbstractTableModels/HexModel.py index 5cb0ef18..21477f0c 100644 --- a/GUI/CustomAbstractTableModels/HexModel.py +++ b/GUI/CustomAbstractTableModels/HexModel.py @@ -36,17 +36,15 @@ def columnCount(self, QModelIndex_parent=None, *args, **kwargs): return self.column_count def data(self, QModelIndex, int_role=None): - if not QModelIndex.isValid(): - return QVariant() - if int_role == Qt.ItemDataRole.BackgroundRole: - address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() - if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: - return QVariant(QColor(Qt.red)) - elif int_role != Qt.DisplayRole: - return QVariant() - if self.data_array is None: - return QVariant() - return QVariant(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]) + if (not self.data_array is None and len(self.data_array) > 0 and QModelIndex.isValid()): + if int_role == Qt.ItemDataRole.BackgroundRole: + address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() + if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: + return QVariant(QColor.red) + elif int_role == Qt.ItemDataRole.DisplayRole: + return QVariant(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]) + + return QVariant() def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): int_address = SysUtils.modulo_address(int_address, GDB_Engine.inferior_arch) diff --git a/GUI/CustomLabels/FlagRegisterLabel.py b/GUI/CustomLabels/FlagRegisterLabel.py index 58c91090..9a292f99 100644 --- a/GUI/CustomLabels/FlagRegisterLabel.py +++ b/GUI/CustomLabels/FlagRegisterLabel.py @@ -35,9 +35,11 @@ def set_value(self, value): self.setText(new) def enterEvent(self, QEvent): - self.setCursor(QCursor(Qt.PointingHandCursor)) + self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): + if GDB_Engine.currentpid == -1: + return registers = GDB_Engine.read_registers() current_flag = self.objectName().lower() label_text = "Enter the new value of flag " + self.objectName() diff --git a/GUI/CustomLabels/RegisterLabel.py b/GUI/CustomLabels/RegisterLabel.py index 93a5fc40..915fd8e8 100644 --- a/GUI/CustomLabels/RegisterLabel.py +++ b/GUI/CustomLabels/RegisterLabel.py @@ -36,9 +36,11 @@ def set_value(self, value): self.setText(new) def enterEvent(self, QEvent): - self.setCursor(QCursor(Qt.PointingHandCursor)) + self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): + if GDB_Engine.currentpid == -1: + return registers = GDB_Engine.read_registers() current_register = self.objectName().lower() register_dialog = InputDialogForm( @@ -48,6 +50,8 @@ def mouseDoubleClickEvent(self, QMouseEvent): self.set_value(GDB_Engine.read_registers()[current_register]) def contextMenuEvent(self, QContextMenuEvent): + if GDB_Engine.currentpid == -1: + return menu = QMenu() show_in_hex_view = menu.addAction("Show in HexView") show_in_disassembler = menu.addAction("Show in Disassembler") diff --git a/GUI/CustomTableViews/HexView.py b/GUI/CustomTableViews/HexView.py index 213a0445..f1bce271 100644 --- a/GUI/CustomTableViews/HexView.py +++ b/GUI/CustomTableViews/HexView.py @@ -16,7 +16,6 @@ """ from PyQt6.QtWidgets import QTableView, QAbstractItemView from PyQt6.QtCore import Qt - from libpince import SysUtils, GDB_Engine @@ -38,9 +37,15 @@ def wheelEvent(self, QWheelEvent): QWheelEvent.ignore() def resize_to_contents(self): + _self_name=self.__class__.__name__ size = self.columnWidth(0) * self.model().columnCount() - self.setMinimumWidth(size) - self.setMaximumWidth(size) + if (_self_name == "QHexView"): + self.setMinimumWidth(int(size*1.875)) + self.setMaximumWidth(int(size*1.875)) + self.resizeColumnsToContents() + else: + self.setMinimumWidth(int(size)) + self.setMaximumWidth(int(size)) def get_selected_address(self): ci = self.currentIndex() diff --git a/GUI/CustomValidators/HexValidator.py b/GUI/CustomValidators/HexValidator.py index ee06a33a..a56a7118 100644 --- a/GUI/CustomValidators/HexValidator.py +++ b/GUI/CustomValidators/HexValidator.py @@ -10,7 +10,7 @@ def validate(self, p_str, p_int): try: int_repr = int(p_str, 0) except ValueError: - return QValidator.Intermediate, p_str, p_int + return QValidator.State.Intermediate, p_str, p_int if int_repr > self.max_limit: - return QValidator.Invalid, p_str, p_int - return QValidator.Acceptable, p_str, p_int + return QValidator.State.Invalid, p_str, p_int + return QValidator.State.Acceptable, p_str, p_int diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index ca6caae4..4855d97c 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -11,6 +11,13 @@ class Ui_MainWindow_MemoryView(object): def setupUi(self, MainWindow_MemoryView): + """ + Setup flag(s) to be used by hexview and dissabemly scrolling, so + that while scrolling, new scroll requests are disabled. + """ + self.bHexViewScrolling = False + self.bDisassemblyScrolling = False + MainWindow_MemoryView.setObjectName("MainWindow_MemoryView") MainWindow_MemoryView.resize(800, 600) self.centralwidget = QtWidgets.QWidget(MainWindow_MemoryView) diff --git a/PINCE.py b/PINCE.py index 2de2eaaf..59f8c092 100755 --- a/PINCE.py +++ b/PINCE.py @@ -18,6 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +from typing import Final + from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ QKeyEvent, QRegularExpressionValidator, QShortcut, QColorConstants from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, \ @@ -285,7 +287,7 @@ def except_hook(exception_type, value, tb): elif exception_type == type_defs.InferiorRunningException: error_dialog = InputDialogForm(item_list=[( "Process is running" + "\nPress " + Hotkeys.break_hotkey.get_active_key() + " to stop process" + - "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.Ok]) + "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.StandardButton.Ok]) error_dialog.exec() traceback.print_exception(exception_type, value, tb) @@ -355,7 +357,16 @@ def run(self): # could pass to scanmem which then would set the current matches # the mainwindow class MainForm(QMainWindow, MainWindow): + def __init__(self): + """ + Declare regular expressions for hexadecimal and decimal input + to be used in checkBox_Hex_stateChanged (or anywhere else that + they are needed). + """ + self.qRegExp_hex: Final[QRegularExpression] = QRegularExpression("(0x)?[A-Fa-f0-9]*$") + self.qRegExp_dec: Final[QRegularExpression] = QRegularExpression("-?[0-9]*") + super().__init__() self.setupUi(self) self.hotkey_to_shortcut = {} @@ -403,7 +414,7 @@ def __init__(self): text = "Unable to initialize GDB\n" \ "You might want to reinstall GDB or use the system GDB\n" \ "To change the current GDB path, check Settings->Debug" - InputDialogForm(item_list=[(text, None)], buttons=[QDialogButtonBox.Ok]).exec() + InputDialogForm(item_list=[(text, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() else: self.apply_after_init() # this should be changed, only works if you use the current directory, fails if you for example install it to some place like bin @@ -480,6 +491,9 @@ def __init__(self): self.pushButton_Console.setIcon(QIcon(QPixmap(icons_directory + "/application_xp_terminal.png"))) self.pushButton_Wiki.setIcon(QIcon(QPixmap(icons_directory + "/book_open.png"))) self.pushButton_About.setIcon(QIcon(QPixmap(icons_directory + "/information.png"))) + self.QWidget_Toolbox.setEnabled(True) + self.pushButton_NextScan.setEnabled(False) + self.pushButton_UndoScan.setEnabled(False) self.auto_attach() def set_default_settings(self): @@ -624,10 +638,12 @@ def toggle_attach_hotkey_pressed(self): dialog_text = "GDB is attached back to the process" if show_messagebox_on_toggle_attach: dialog = InputDialogForm(item_list=[( - dialog_text + "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.Ok]) + dialog_text + "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.StandardButton.Ok]) dialog.exec() def treeWidget_AddressTable_context_menu_event(self, event): + if self.treeWidget_AddressTable.topLevelItemCount() == 0: + return current_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) menu = QMenu() edit_menu = menu.addMenu("Edit") @@ -968,18 +984,20 @@ def pushButton_Console_clicked(self): console_widget.showMaximized() def checkBox_Hex_stateChanged(self, state): - if state == Qt.CheckState.Checked: + if Qt.CheckState(state) == Qt.CheckState.Checked: # allows only things that are hex, can also start with 0x - self.lineEdit_Scan.setValidator(QRegExpValidator(QRegExp("(0x)?[A-Fa-f0-9]*$"), parent=self.lineEdit_Scan)) - self.lineEdit_Scan2.setValidator( - QRegExpValidator(QRegExp("(0x)?[A-Fa-f0-9]*$"), parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.setValidator(QRegularExpressionValidator(self.qRegExp_hex, parent=self.lineEdit_Scan)) + self.lineEdit_Scan2.setValidator(QRegularExpressionValidator(self.qRegExp_hex, parent=self.lineEdit_Scan2)) else: # sets it back to integers only - self.lineEdit_Scan.setValidator(QRegExpValidator(QRegExp("-?[0-9]*"), parent=self.lineEdit_Scan)) - self.lineEdit_Scan2.setValidator(QRegExpValidator(QRegExp("-?[0-9]*"), parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.setValidator(QRegularExpressionValidator(self.qRegExp_dec, parent=self.lineEdit_Scan)) + self.lineEdit_Scan2.setValidator(QRegularExpressionValidator(self.qRegExp_dec, parent=self.lineEdit_Scan2)) # TODO add a damn keybind for this... def pushButton_NewFirstScan_clicked(self): + self.comboBox_ScanType_init() + if GDB_Engine.currentpid == -1: + return if self.scan_mode == type_defs.SCAN_MODE.ONGOING: self.scan_mode = type_defs.SCAN_MODE.NEW self.pushButton_NewFirstScan.setText("First Scan") @@ -999,7 +1017,7 @@ def pushButton_NewFirstScan_clicked(self): self.backend.send_command("reset") self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan - self.comboBox_ScanType_init() + def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, @@ -1086,6 +1104,8 @@ def validate_search(self, search_for, search_for2): return search_for def pushButton_NextScan_clicked(self): + if GDB_Engine.currentpid == -1: + return global ProgressRun search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) @@ -1236,11 +1256,13 @@ def on_new_process(self): # enable scan GUI self.lineEdit_Scan.setPlaceholderText("Scan for") - # self.QWidget_Toolbox.setEnabled(True) - # self.pushButton_NextScan.setEnabled(False) - # self.pushButton_UndoScan.setEnabled(False) + self.QWidget_Toolbox.setEnabled(True) + self.pushButton_NextScan.setEnabled(False) + self.pushButton_UndoScan.setEnabled(False) def delete_address_table_contents(self): + if self.treeWidget_AddressTable.topLevelItemCount() == 0: + return confirm_dialog = InputDialogForm(item_list=[("This will clear the contents of address table\nProceed?",)]) if confirm_dialog.exec(): self.treeWidget_AddressTable.clear() @@ -1888,8 +1910,8 @@ class LoadingDialogForm(QDialog, LoadingDialog): def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) - self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint) - self.setAttribute(Qt.WA_TranslucentBackground) + self.setWindowFlags(self.windowFlags() | Qt.WindowType.FramelessWindowHint) + self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) if parent: GuiUtils.center_to_parent(self) self.keyPressEvent = QEvent.ignore @@ -1905,7 +1927,7 @@ def __init__(self, parent=None): self.movie = QMovie(media_directory + "/LoadingDialog/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) self.movie.setScaledSize(QSize(25, 25)) - self.movie.setCacheMode(QMovie.CacheAll) + self.movie.setCacheMode(QMovie.CacheMode.CacheAll) self.movie.setSpeed(100) self.movie.start() @@ -2265,7 +2287,7 @@ def __init__(self, parent=None): self.completion_model = QStringListModel() self.completer = QCompleter() self.completer.setModel(self.completion_model) - self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) + self.completer.setCompletionMode(QCompleter.CompletionMode.UnfilteredPopupCompletion) self.completer.setMaxVisibleItems(8) self.lineEdit.setCompleter(self.completer) self.quit_commands = ("q", "quit", "-gdb-exit") @@ -2360,7 +2382,7 @@ def reset_console_text(self): def scroll_to_bottom(self): cursor = self.textBrowser.textCursor() - cursor.movePosition(QTextCursor.End) + cursor.movePosition(QTextCursor.MoveOperation.End) self.textBrowser.setTextCursor(cursor) self.textBrowser.ensureCursorVisible() @@ -2396,7 +2418,7 @@ def lineEdit_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), self.scroll_forwards_history) ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() except KeyError: self.lineEdit.keyPressEvent_original(event) @@ -2554,13 +2576,9 @@ def initialize_disassemble_view(self): self.tableWidget_Disassemble.wheelEvent = QEvent.ignore self.verticalScrollBar_Disassemble.wheelEvent = QEvent.ignore - GuiUtils.center_scroll_bar(self.verticalScrollBar_Disassemble) - self.verticalScrollBar_Disassemble.mouseReleaseEvent = self.verticalScrollBar_Disassemble_mouse_release_event + self.verticalScrollBar_Disassemble.sliderChange = self.disassemble_scrollbar_sliderchanged - self.disassemble_scroll_bar_timer = QTimer() - self.disassemble_scroll_bar_timer.setInterval(100) - self.disassemble_scroll_bar_timer.timeout.connect(self.check_disassemble_scrollbar) - self.disassemble_scroll_bar_timer.start() + GuiUtils.center_scroll_bar(self.verticalScrollBar_Disassemble) # Format: [address1, address2, ...] self.tableWidget_Disassemble.travel_history = [] @@ -2592,8 +2610,11 @@ def initialize_hex_view(self): self.tableView_HexView_Ascii.keyPressEvent = self.widget_HexView_key_press_event self.verticalScrollBar_HexView.wheelEvent = QEvent.ignore + + self.verticalScrollBar_HexView.sliderChange = self.hex_view_scrollbar_sliderchanged + self.tableWidget_HexView_Address.wheelEvent = QEvent.ignore - self.scrollArea_Hex.keyPressEvent = QEvent.ignore + self.scrollArea_Hex.keyPressEvent = self.widget_HexView_key_press_event self.tableWidget_HexView_Address.setAutoScroll(False) self.tableWidget_HexView_Address.setStyleSheet("QTableWidget {background-color: transparent;}") self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) @@ -2614,32 +2635,38 @@ def initialize_hex_view(self): self.tableView_HexView_Hex.verticalHeader().defaultSectionSize()) GuiUtils.center_scroll_bar(self.verticalScrollBar_HexView) - self.hex_view_scroll_bar_timer = QTimer() - self.hex_view_scroll_bar_timer.setInterval(100) - self.hex_view_scroll_bar_timer.timeout.connect(self.check_hex_view_scrollbar) - self.hex_view_scroll_bar_timer.start() - self.verticalScrollBar_HexView.mouseReleaseEvent = self.verticalScrollBar_HexView_mouse_release_event + def show_trace_window(self): + if GDB_Engine.currentpid == -1: + return trace_instructions_window = TraceInstructionsWindowForm(prompt_dialog=False) trace_instructions_window.showMaximized() def step_instruction(self): + if GDB_Engine.currentpid == -1: + return if self.updating_memoryview: return GDB_Engine.step_instruction() def step_over_instruction(self): + if GDB_Engine.currentpid == -1: + return if self.updating_memoryview: return GDB_Engine.step_over_instruction() def execute_till_return(self): + if GDB_Engine.currentpid == -1: + return if self.updating_memoryview: return GDB_Engine.execute_till_return() def set_address(self): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -2647,6 +2674,8 @@ def set_address(self): self.refresh_disassemble_view() def nop_instruction(self): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -2657,6 +2686,8 @@ def nop_instruction(self): @GDB_Engine.execute_with_temporary_interruption def toggle_breakpoint(self): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -2669,6 +2700,8 @@ def toggle_breakpoint(self): self.refresh_disassemble_view() def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.BOTH): + if GDB_Engine.currentpid == -1: + return if GDB_Engine.check_address_in_breakpoints(address): GDB_Engine.delete_breakpoint(hex(address)) else: @@ -2687,6 +2720,8 @@ def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.B self.refresh_hex_view() def label_HexView_Information_context_menu_event(self, event): + if GDB_Engine.currentpid == -1: + return def copy_to_clipboard(): app.clipboard().setText(self.label_HexView_Information.text()) @@ -2704,6 +2739,8 @@ def copy_to_clipboard(): pass def widget_HexView_context_menu_event(self, event): + if GDB_Engine.currentpid == -1: + return selected_address = self.tableView_HexView_Hex.get_selected_address() menu = QMenu() edit = menu.addAction("Edit") @@ -2746,11 +2783,15 @@ def widget_HexView_context_menu_event(self, event): pass def exec_hex_view_edit_dialog(self): + if GDB_Engine.currentpid == -1: + return selected_address = self.tableView_HexView_Hex.get_selected_address() HexEditDialogForm(hex(selected_address)).exec() self.refresh_hex_view() def exec_hex_view_go_to_dialog(self): + if GDB_Engine.currentpid == -1: + return current_address = hex(self.tableView_HexView_Hex.get_selected_address()) go_to_dialog = InputDialogForm(item_list=[("Enter the expression", current_address)]) if go_to_dialog.exec(): @@ -2762,6 +2803,8 @@ def exec_hex_view_go_to_dialog(self): self.hex_dump_address(int(dest_address, 16)) def exec_hex_view_add_address_dialog(self): + if GDB_Engine.currentpid == -1: + return selected_address = self.tableView_HexView_Hex.get_selected_address() manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), index=type_defs.VALUE_INDEX.INDEX_AOB) @@ -2769,61 +2812,83 @@ def exec_hex_view_add_address_dialog(self): desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() self.parent().add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate) - def verticalScrollBar_HexView_mouse_release_event(self, event): - GuiUtils.center_scroll_bar(self.verticalScrollBar_HexView) - - def verticalScrollBar_Disassemble_mouse_release_event(self, event): - GuiUtils.center_scroll_bar(self.verticalScrollBar_Disassemble) - - def check_hex_view_scrollbar(self): - if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: - return + def hex_view_scroll_up(self): + self.verticalScrollBar_HexView.setValue(1) + def hex_view_scroll_down(self): + self.verticalScrollBar_HexView.setValue(-1) + + def hex_view_scrollbar_sliderchanged(self, event): + if self.bHexViewScrolling: + return; + self.bHexViewScrolling=True + #if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: + # return maximum = self.verticalScrollBar_HexView.maximum() minimum = self.verticalScrollBar_HexView.minimum() midst = (maximum + minimum) / 2 current_value = self.verticalScrollBar_HexView.value() - if midst - 10 < current_value < midst + 10: - return + #if midst - 10 < current_value < midst + 10: + # self.bHexViewScrolling = False + # return current_address = self.hex_model.current_address if current_value < midst: next_address = current_address - 0x40 else: next_address = current_address + 0x40 self.hex_dump_address(next_address) - - def check_disassemble_scrollbar(self): - if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: - return + GuiUtils.center_scroll_bar(self.verticalScrollBar_HexView) + self.bHexViewScrolling = False + + def disassemble_scroll_up(self): + self.verticalScrollBar_Disassemble.setValue(1) + def disassemble_scroll_down(self): + self.verticalScrollBar_Disassemble.setValue(-1) + + def disassemble_scrollbar_sliderchanged(self, even): + if self.bDisassemblyScrolling: + return; + self.bDisassemblyScrolling = True + #if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: + # return maximum = self.verticalScrollBar_Disassemble.maximum() minimum = self.verticalScrollBar_Disassemble.minimum() midst = (maximum + minimum) / 2 current_value = self.verticalScrollBar_Disassemble.value() - if midst - 10 < current_value < midst + 10: - return + #if midst - 10 < current_value < midst + 10: + # self.bDisassemblyScrolling = False + # return if current_value < midst: self.tableWidget_Disassemble_scroll("previous", instructions_per_scroll) else: self.tableWidget_Disassemble_scroll("next", instructions_per_scroll) + GuiUtils.center_scroll_bar(self.verticalScrollBar_Disassemble) + self.bDisassemblyScrolling = False def on_hex_view_current_changed(self, QModelIndex_current): - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SingleSelection) + if GDB_Engine.currentpid == -1: + return + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.hex_view_last_selected_address_int = self.tableView_HexView_Hex.get_selected_address() self.tableView_HexView_Ascii.selectionModel().setCurrentIndex(QModelIndex_current, - QItemSelectionModel.ClearAndSelect) + QItemSelectionModel.SelectionFlag.ClearAndSelect) self.tableWidget_HexView_Address.selectRow(QModelIndex_current.row()) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.NoSelection) + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) def on_ascii_view_current_changed(self, QModelIndex_current): - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SingleSelection) + if GDB_Engine.currentpid == -1: + return + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.tableView_HexView_Hex.selectionModel().setCurrentIndex(QModelIndex_current, - QItemSelectionModel.ClearAndSelect) + QItemSelectionModel.SelectionFlag.ClearAndSelect) self.tableWidget_HexView_Address.selectRow(QModelIndex_current.row()) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.NoSelection) + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) # TODO: Consider merging HexView_Address, HexView_Hex and HexView_Ascii into one UI class # TODO: Move this function to that class if that happens # TODO: Also consider moving shared fields of HexView and HexModel to that class(such as HexModel.current_address) def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT): + if GDB_Engine.currentpid == -1: + return int_address = SysUtils.modulo_address(int_address, GDB_Engine.inferior_arch) if not (self.hex_view_current_region.start <= int_address < self.hex_view_current_region.end): information = SysUtils.get_region_info(GDB_Engine.currentpid, int_address) @@ -2861,18 +2926,20 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL row_index = int(index / HEX_VIEW_COL_COUNT) model_index = QModelIndex(self.hex_model.index(row_index, index % HEX_VIEW_COL_COUNT)) self.tableView_HexView_Hex.selectionModel().setCurrentIndex(model_index, - QItemSelectionModel.ClearAndSelect) + QItemSelectionModel.SelectionFlag.ClearAndSelect) self.tableView_HexView_Ascii.selectionModel().setCurrentIndex(model_index, - QItemSelectionModel.ClearAndSelect) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SingleSelection) + QItemSelectionModel.SelectionFlag.ClearAndSelect) + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_HexView_Address.selectRow(row_index) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.NoSelection) + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) break else: self.tableView_HexView_Hex.clearSelection() self.tableView_HexView_Ascii.clearSelection() def refresh_hex_view(self): + if GDB_Engine.currentpid == -1: + return if self.tableWidget_HexView_Address.rowCount() == 0: entry_point = GDB_Engine.find_entry_point() if not entry_point: @@ -2887,6 +2954,8 @@ def refresh_hex_view(self): # offset can also be an address as hex str # returns True if the given expression is disassembled correctly, False if not def disassemble_expression(self, expression, offset="+200", append_to_travel_history=False): + if GDB_Engine.currentpid == -1: + return disas_data = GDB_Engine.disassemble(expression, offset) if not disas_data: QMessageBox.information(app.focusWidget(), "Error", "Cannot access memory at expression " + expression) @@ -3011,10 +3080,14 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his return True def refresh_disassemble_view(self): + if GDB_Engine.currentpid == -1: + return self.disassemble_expression(self.disassemble_currently_displayed_address) # Set colour of a row if a specific address is encountered(e.g $pc, a bookmarked address etc.) def handle_colours(self, row_colour): + if GDB_Engine.currentpid == -1: + return for row in row_colour: current_row = row_colour[row] if PC_COLOUR in current_row: @@ -3041,6 +3114,8 @@ def handle_colours(self, row_colour): # color parameter should be Qt.colour def set_row_colour(self, row, colour): + if GDB_Engine.currentpid == -1: + return for col in range(self.tableWidget_Disassemble.columnCount()): self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, QColor(colour)) @@ -3085,6 +3160,8 @@ def on_process_running(self): self.setWindowTitle("Memory Viewer - Running") def add_breakpoint_condition(self, int_address): + if GDB_Engine.currentpid == -1: + return condition_text = "Enter the expression for condition, for instance:\n\n" + \ "$eax==0x523\n" + \ "$rax>0 && ($rbp<0 || $rsp==0)\n" + \ @@ -3103,6 +3180,8 @@ def add_breakpoint_condition(self, int_address): hex(int_address) + "\nCheck terminal for details") def update_registers(self): + if GDB_Engine.currentpid == -1: + return registers = GDB_Engine.read_registers() if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64: self.stackedWidget.setCurrentWidget(self.registers_64) @@ -3151,6 +3230,8 @@ def update_registers(self): self.FS.set_value(registers["fs"]) def update_stacktrace(self): + if GDB_Engine.currentpid == -1: + return stack_trace_info = GDB_Engine.get_stacktrace_info() self.tableWidget_StackTrace.setRowCount(0) self.tableWidget_StackTrace.setRowCount(len(stack_trace_info)) @@ -3159,6 +3240,8 @@ def update_stacktrace(self): self.tableWidget_StackTrace.setItem(row, STACKTRACE_FRAME_ADDRESS_COL, QTableWidgetItem(item[1])) def set_stack_widget(self, stack_widget): + if GDB_Engine.currentpid == -1: + return self.stackedWidget_StackScreens.setCurrentWidget(stack_widget) if stack_widget == self.Stack: self.update_stack() @@ -3166,6 +3249,8 @@ def set_stack_widget(self, stack_widget): self.update_stacktrace() def tableWidget_StackTrace_context_menu_event(self, event): + if GDB_Engine.currentpid == -1: + return def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_StackTrace.item(row, column).text()) @@ -3195,6 +3280,8 @@ def copy_to_clipboard(row, column): pass def update_stack(self): + if GDB_Engine.currentpid == -1: + return stack_info = GDB_Engine.get_stack_info() self.tableWidget_Stack.setRowCount(0) self.tableWidget_Stack.setRowCount(len(stack_info)) @@ -3206,6 +3293,8 @@ def update_stack(self): self.tableWidget_Stack.resizeColumnToContents(STACK_VALUE_COL) def tableWidget_Stack_key_press_event(self, event): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3217,12 +3306,15 @@ def tableWidget_Stack_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), lambda: self.hex_dump_address(int(current_address, 16))) ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_Stack.keyPressEvent_original(event) def tableWidget_Stack_context_menu_event(self, event): + if GDB_Engine.currentpid == -1: + return + def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_Stack.item(row, column).text()) @@ -3261,6 +3353,8 @@ def copy_to_clipboard(row, column): pass def tableWidget_Stack_double_click(self, index): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) if index.column() == STACK_POINTER_ADDRESS_COL: current_address_text = self.tableWidget_Stack.item(selected_row, STACK_POINTER_ADDRESS_COL).text() @@ -3276,6 +3370,8 @@ def tableWidget_Stack_double_click(self, index): self.disassemble_expression(current_address, append_to_travel_history=True) def tableWidget_StackTrace_double_click(self, index): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_StackTrace) if index.column() == STACKTRACE_RETURN_ADDRESS_COL: current_address_text = self.tableWidget_StackTrace.item(selected_row, STACKTRACE_RETURN_ADDRESS_COL).text() @@ -3287,16 +3383,20 @@ def tableWidget_StackTrace_double_click(self, index): self.hex_dump_address(int(current_address, 16)) def tableWidget_StackTrace_key_press_event(self, event): + if GDB_Engine.currentpid == -1: + return actions = type_defs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stacktrace) ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_StackTrace.keyPressEvent_original(event) def widget_Disassemble_wheel_event(self, event): + if GDB_Engine.currentpid == -1: + return steps = event.angleDelta() if steps.y() > 0: self.tableWidget_Disassemble_scroll("previous", instructions_per_scroll) @@ -3304,6 +3404,8 @@ def widget_Disassemble_wheel_event(self, event): self.tableWidget_Disassemble_scroll("next", instructions_per_scroll) def disassemble_check_viewport(self, where, instruction_count): + if GDB_Engine.currentpid == -1: + return current_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_row_height = self.tableWidget_Disassemble.rowViewportPosition(current_row) row_height = self.tableWidget_Disassemble.verticalHeader().defaultSectionSize() @@ -3324,11 +3426,15 @@ def disassemble_check_viewport(self, where, instruction_count): self.tableWidget_Disassemble_scroll(where, instruction_count) def tableWidget_Disassemble_scroll(self, where, instruction_count): + if GDB_Engine.currentpid == -1: + return current_address = self.disassemble_currently_displayed_address new_address = GDB_Engine.find_address_of_closest_instruction(current_address, where, instruction_count) self.disassemble_expression(new_address) def widget_HexView_wheel_event(self, event): + if GDB_Engine.currentpid == -1: + return steps = event.angleDelta() current_address = self.hex_model.current_address if steps.y() > 0: @@ -3338,6 +3444,8 @@ def widget_HexView_wheel_event(self, event): self.hex_dump_address(next_address) def widget_HexView_key_press_event(self, event): + if GDB_Engine.currentpid == -1: + return selected_address = self.tableView_HexView_Hex.get_selected_address() actions = type_defs.KeyboardModifiersTupleDict([ @@ -3345,15 +3453,19 @@ def widget_HexView_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), lambda: self.disassemble_expression(hex(selected_address), append_to_travel_history=True)), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_A), self.exec_hex_view_add_address_dialog), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_hex_view) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_hex_view), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.hex_view_scroll_up), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.hex_view_scroll_down), ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() except KeyError: pass self.tableView_HexView_Hex.keyPressEvent_original(event) def tableWidget_Disassemble_key_press_event(self, event): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3369,15 +3481,19 @@ def tableWidget_Disassemble_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_T), self.exec_trace_instructions_dialog), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_disassemble_view), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), lambda: self.disassemble_check_viewport("next", 1)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), lambda: self.disassemble_check_viewport("previous", 1)) + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), lambda: self.disassemble_check_viewport("previous", 1)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.disassemble_scroll_up), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.disassemble_scroll_down) ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_Disassemble.keyPressEvent_original(event) def tableWidget_Disassemble_item_double_clicked(self, index): + if GDB_Engine.currentpid == -1: + return if index.column() == DISAS_COMMENT_COL: selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -3388,6 +3504,8 @@ def tableWidget_Disassemble_item_double_clicked(self, index): self.bookmark_address(current_address) def tableWidget_Disassemble_item_selection_changed(self): + if GDB_Engine.currentpid == -1: + return try: selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) selected_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -3398,18 +3516,25 @@ def tableWidget_Disassemble_item_selection_changed(self): # Search the item in given row for location changing instructions # Go to the address pointed by that instruction if it contains any def follow_instruction(self, selected_row): + if GDB_Engine.currentpid == -1: + return address = SysUtils.instruction_follow_address( self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text()) if address: self.disassemble_expression(address, append_to_travel_history=True) def disassemble_go_back(self): + if GDB_Engine.currentpid == -1: + return if self.tableWidget_Disassemble.travel_history: last_location = self.tableWidget_Disassemble.travel_history[-1] self.disassemble_expression(last_location) self.tableWidget_Disassemble.travel_history.pop() def tableWidget_Disassemble_context_menu_event(self, event): + if GDB_Engine.currentpid == -1: + return + def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_Disassemble.item(row, column).text()) @@ -3503,6 +3628,8 @@ def copy_all_columns(row): self.disassemble_expression(SysUtils.extract_address(action.text()), append_to_travel_history=True) def dissect_current_region(self): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3512,6 +3639,8 @@ def dissect_current_region(self): self.refresh_disassemble_view() def exec_examine_referrers_widget(self, current_address_text): + if GDB_Engine.currentpid == -1: + return if not GuiUtils.contains_reference_mark(current_address_text): return current_address = SysUtils.extract_address(current_address_text) @@ -3520,6 +3649,8 @@ def exec_examine_referrers_widget(self, current_address_text): examine_referrers_widget.show() def exec_trace_instructions_dialog(self): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3527,6 +3658,8 @@ def exec_trace_instructions_dialog(self): trace_instructions_window.showMaximized() def exec_track_breakpoint_dialog(self): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3535,6 +3668,8 @@ def exec_track_breakpoint_dialog(self): track_breakpoint_widget.show() def exec_disassemble_go_to_dialog(self): + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3545,6 +3680,8 @@ def exec_disassemble_go_to_dialog(self): self.disassemble_expression(traveled_exp, append_to_travel_history=True) def bookmark_address(self, int_address): + if GDB_Engine.currentpid == -1: + return if int_address in self.tableWidget_Disassemble.bookmarks: QMessageBox.information(app.focusWidget(), "Error", "This address has already been bookmarked") return @@ -3557,6 +3694,8 @@ def bookmark_address(self, int_address): self.refresh_disassemble_view() def change_bookmark_comment(self, int_address): + if GDB_Engine.currentpid == -1: + return current_comment = self.tableWidget_Disassemble.bookmarks[int_address] comment_dialog = InputDialogForm(item_list=[("Enter the comment for bookmarked address", current_comment)]) if comment_dialog.exec(): @@ -3567,49 +3706,71 @@ def change_bookmark_comment(self, int_address): self.refresh_disassemble_view() def delete_bookmark(self, int_address): + if GDB_Engine.currentpid == -1: + return if int_address in self.tableWidget_Disassemble.bookmarks: del self.tableWidget_Disassemble.bookmarks[int_address] self.refresh_disassemble_view() def actionBookmarks_triggered(self): + if GDB_Engine.currentpid == -1: + return bookmark_widget = BookmarkWidgetForm(self) bookmark_widget.show() bookmark_widget.activateWindow() def actionStackTrace_Info_triggered(self): + if GDB_Engine.currentpid == -1: + return self.stacktrace_info_widget = StackTraceInfoWidgetForm() self.stacktrace_info_widget.show() def actionBreakpoints_triggered(self): + if GDB_Engine.currentpid == -1: + return breakpoint_widget = BreakpointInfoWidgetForm(self) breakpoint_widget.show() breakpoint_widget.activateWindow() def actionFunctions_triggered(self): + if GDB_Engine.currentpid == -1: + return functions_info_widget = FunctionsInfoWidgetForm(self) functions_info_widget.show() def actionGDB_Log_File_triggered(self): + if GDB_Engine.currentpid == -1: + return log_file_widget = LogFileWidgetForm() log_file_widget.showMaximized() def actionMemory_Regions_triggered(self): + if GDB_Engine.currentpid == -1: + return memory_regions_widget = MemoryRegionsWidgetForm(self) memory_regions_widget.show() def actionRestore_Instructions_triggered(self): + if GDB_Engine.currentpid == -1: + return restore_instructions_widget = RestoreInstructionsWidgetForm(self) restore_instructions_widget.show() def actionReferenced_Strings_triggered(self): + if GDB_Engine.currentpid == -1: + return ref_str_widget = ReferencedStringsWidgetForm(self) ref_str_widget.show() def actionReferenced_Calls_triggered(self): + if GDB_Engine.currentpid == -1: + return ref_call_widget = ReferencedCallsWidgetForm(self) ref_call_widget.show() def actionInject_so_file_triggered(self): + if GDB_Engine.currentpid == -1: + return file_path = QFileDialog.getOpenFileName(self, "Select the .so file", "", "Shared object library (*.so)")[0] if file_path: if GDB_Engine.inject_with_dlopen_call(file_path): @@ -3618,6 +3779,8 @@ def actionInject_so_file_triggered(self): QMessageBox.information(self, "Error", "Failed to inject the .so file") def actionCall_Function_triggered(self): + if GDB_Engine.currentpid == -1: + return label_text = "Enter the expression for the function that'll be called from the inferior" \ "\nYou can view functions list from View->Functions" \ "\n\nFor instance:" \ @@ -3636,21 +3799,29 @@ def actionCall_Function_triggered(self): QMessageBox.information(self, "Failed", "Failed to call the expression " + call_dialog.get_values()) def actionSearch_Opcode_triggered(self): + if GDB_Engine.currentpid == -1: + return start_address = int(self.disassemble_currently_displayed_address, 16) end_address = start_address + 0x30000 search_opcode_widget = SearchOpcodeWidgetForm(hex(start_address), hex(end_address), self) search_opcode_widget.show() def actionDissect_Code_triggered(self): + if GDB_Engine.currentpid == -1: + return self.dissect_code_dialog = DissectCodeDialogForm() self.dissect_code_dialog.exec() self.refresh_disassemble_view() def actionlibpince_triggered(self): + if GDB_Engine.currentpid == -1: + return libpince_widget = LibpinceReferenceWidgetForm(is_window=True) libpince_widget.showMaximized() def pushButton_ShowFloatRegisters_clicked(self): + if GDB_Engine.currentpid == -1: + return self.float_registers_widget = FloatRegisterWidgetForm() self.float_registers_widget.show() GuiUtils.center_to_window(self.float_registers_widget, self.widget_Registers) @@ -3869,7 +4040,7 @@ def tableWidget_Instructions_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_Instructions.keyPressEvent_original(event) @@ -3932,7 +4103,7 @@ def tableWidget_BreakpointInfo_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) ]) try: - actions[event.modifiers(), event.key()]() + actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_BreakpointInfo.keyPressEvent_original(event) @@ -4261,7 +4432,7 @@ class TraceInstructionsWaitWidgetForm(QWidget, TraceInstructionsWaitWidget): def __init__(self, address, breakpoint, parent=None): super().__init__(parent=parent) self.setupUi(self) - self.setWindowFlags(self.windowFlags() | Qt.Window | Qt.FramelessWindowHint) + self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) GuiUtils.center(self) self.address = address self.breakpoint = breakpoint @@ -4269,8 +4440,8 @@ def __init__(self, address, breakpoint, parent=None): self.movie = QMovie(media_directory + "/TraceInstructionsWaitWidget/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) self.movie.setScaledSize(QSize(215, 100)) - self.setAttribute(Qt.WA_TranslucentBackground) - self.movie.setCacheMode(QMovie.CacheAll) + self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) + self.movie.setCacheMode(QMovie.CacheMode.CacheAll) self.movie.setSpeed(100) self.movie.start() self.pushButton_Cancel.clicked.connect(self.close) @@ -4528,7 +4699,7 @@ def pushButton_Help_clicked(self): "\n@plt means this function is a subroutine for the original one" \ "\nThere can be more than one of the same function" \ "\nIt means that the function is overloaded" - InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.Ok]).exec() + InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() def closeEvent(self, QCloseEvent): global instances @@ -4780,7 +4951,7 @@ def fill_resource_table(self): self.tableWidget_ResourceTable.setItem(row, LIBPINCE_REFERENCE_ITEM_COL, table_widget_item) self.tableWidget_ResourceTable.setItem(row, LIBPINCE_REFERENCE_VALUE_COL, table_widget_item_value) self.tableWidget_ResourceTable.setSortingEnabled(True) - self.tableWidget_ResourceTable.sortByColumn(LIBPINCE_REFERENCE_ITEM_COL, Qt.AscendingOrder) + self.tableWidget_ResourceTable.sortByColumn(LIBPINCE_REFERENCE_ITEM_COL, Qt.SortOrder.AscendingOrder) GuiUtils.resize_to_contents(self.tableWidget_ResourceTable) def pushButton_TextDown_clicked(self): @@ -4788,7 +4959,7 @@ def pushButton_TextDown_clicked(self): return cursor = self.textBrowser_TypeDefs.textCursor() cursor.clearSelection() - cursor.movePosition(QTextCursor.Start) + cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_TypeDefs.setTextCursor(cursor) if self.current_found == self.found_count: self.current_found = 1 @@ -4804,7 +4975,7 @@ def pushButton_TextUp_clicked(self): return cursor = self.textBrowser_TypeDefs.textCursor() cursor.clearSelection() - cursor.movePosition(QTextCursor.Start) + cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_TypeDefs.setTextCursor(cursor) if self.current_found == 1: self.current_found = self.found_count @@ -4820,7 +4991,7 @@ def highlight_text(self): self.textBrowser_TypeDefs.setTextBackgroundColor(QColor("white")) cursor = self.textBrowser_TypeDefs.textCursor() cursor.clearSelection() - cursor.movePosition(QTextCursor.Start) + cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_TypeDefs.setTextCursor(cursor) highlight_format = QTextCharFormat() @@ -4839,7 +5010,7 @@ def highlight_text(self): return cursor = self.textBrowser_TypeDefs.textCursor() cursor.clearSelection() - cursor.movePosition(QTextCursor.Start) + cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_TypeDefs.setTextCursor(cursor) self.textBrowser_TypeDefs.find(pattern) self.current_found = 1 @@ -4910,7 +5081,7 @@ def refresh_contents(self): # Scrolling to bottom cursor = self.textBrowser_LogContent.textCursor() - cursor.movePosition(QTextCursor.End) + cursor.movePosition(QTextCursor.MoveOperation.End) self.textBrowser_LogContent.setTextCursor(cursor) self.textBrowser_LogContent.ensureCursorVisible() log_file.close() @@ -4976,7 +5147,7 @@ def pushButton_Help_clicked(self): "\n'[re]cx' searches for both 'rcx' and 'ecx'" \ "\nUse the char '\\' to escape special chars such as '['" \ "\n'\[rsp\]' searches for opcodes that contain '[rsp]'" - InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.Ok]).exec() + InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() def tableWidget_Opcodes_item_double_clicked(self, index): row = index.row() @@ -5242,7 +5413,7 @@ def __init__(self, parent=None): dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec() self.refresh_table() - self.tableWidget_References.sortByColumn(REF_STR_ADDR_COL, Qt.AscendingOrder) + self.tableWidget_References.sortByColumn(REF_STR_ADDR_COL, Qt.SortOrder.AscendingOrder) self.tableWidget_References.selectionModel().currentChanged.connect(self.tableWidget_References_current_changed) self.listWidget_Referrers.itemDoubleClicked.connect(self.listWidget_Referrers_item_double_clicked) self.tableWidget_References.itemDoubleClicked.connect(self.tableWidget_References_item_double_clicked) @@ -5276,10 +5447,10 @@ def refresh_table(self): for row, item in enumerate(item_list): self.tableWidget_References.setItem(row, REF_STR_ADDR_COL, QTableWidgetItem(self.pad_hex(item[0]))) table_widget_item = QTableWidgetItem() - table_widget_item.setData(Qt.EditRole, item[1]) + table_widget_item.setData(Qt.ItemDataRole.EditRole, item[1]) self.tableWidget_References.setItem(row, REF_STR_COUNT_COL, table_widget_item) table_widget_item = QTableWidgetItem() - table_widget_item.setData(Qt.EditRole, item[2]) + table_widget_item.setData(Qt.ItemDataRole.EditRole, item[2]) self.tableWidget_References.setItem(row, REF_STR_VAL_COL, table_widget_item) self.tableWidget_References.setSortingEnabled(True) @@ -5377,7 +5548,7 @@ def __init__(self, parent=None): dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec() self.refresh_table() - self.tableWidget_References.sortByColumn(REF_CALL_ADDR_COL, Qt.AscendingOrder) + self.tableWidget_References.sortByColumn(REF_CALL_ADDR_COL, Qt.SortOrder.AscendingOrder) self.tableWidget_References.selectionModel().currentChanged.connect(self.tableWidget_References_current_changed) self.listWidget_Referrers.itemDoubleClicked.connect(self.listWidget_Referrers_item_double_clicked) self.tableWidget_References.itemDoubleClicked.connect(self.tableWidget_References_item_double_clicked) @@ -5409,7 +5580,7 @@ def refresh_table(self): for row, item in enumerate(item_list): self.tableWidget_References.setItem(row, REF_CALL_ADDR_COL, QTableWidgetItem(self.pad_hex(item[0]))) table_widget_item = QTableWidgetItem() - table_widget_item.setData(Qt.EditRole, item[1]) + table_widget_item.setData(Qt.ItemDataRole.EditRole, item[1]) self.tableWidget_References.setItem(row, REF_CALL_COUNT_COL, table_widget_item) self.tableWidget_References.setSortingEnabled(True) @@ -5571,7 +5742,7 @@ def listWidget_Referrers_current_changed(self, QModelIndex_current): for item in disas_data: self.textBrowser_DisasInfo.append(item[0] + item[2]) cursor = self.textBrowser_DisasInfo.textCursor() - cursor.movePosition(QTextCursor.Start) + cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_DisasInfo.setTextCursor(cursor) self.textBrowser_DisasInfo.ensureCursorVisible() diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..d76f3cbf --- /dev/null +++ b/TODO.md @@ -0,0 +1,21 @@ + +--- +**2022/11/24 -- Fix scrolling via the vertical scrollbar in memoryview** + +[fixed] + Currently using the vertical scrollbar to scroll the disassembled instructions in the memoryview, and in hex view, results in endless movement of the scrollbar but no actual scrolling takes place. + +--- + +--- +**2022/11/24 -- Hex and Ascii Models in Memory View Don't show the proper values** + +[fixed] + Currently the Hex and Ascii Viewer are showing black squares, or , it should + show the hex value (in the hex view) and the Ascii value (or a . for non-ascii). + +[fixed] + Additionally, the hex digits are not showing two digits per entry (eg 12 34, instead of 1 3) + +[fixed] + Ascii text-view has for non-printable characters, this needs to be changed to . + +[fixed] + Pressing PgUp/Dn, or arrow keys does not scroll the hex view (but the mouse wheel does) + +--- diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 764fb68d..3c504f93 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -377,7 +377,7 @@ def ___internal_continue_inferior(): #:tag:Debug def ___internal_interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): - """Interrupt the inferior + """Interrupt the inferior see notes on ___internal_continue_inferior Args: interrupt_reason (int): Just changes the global variable stop_reason. Can be a member of type_defs.STOP_REASON @@ -429,6 +429,8 @@ def interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): Args: interrupt_reason (int): Just changes the global variable stop_reason. Can be a member of type_defs.STOP_REASON """ + if currentpid == -1: + return global stop_reason send_command("c", control=True) wait_for_stop() @@ -438,6 +440,8 @@ def interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): #:tag:Debug def continue_inferior(): """Continue the inferior""" + if currentpid == -1: + return send_command("c") @@ -696,6 +700,8 @@ def toggle_attach(): int: The new state of the process as a member of type_defs.TOGGLE_ATTACH None: If detaching or attaching fails """ + if currentpid == -1: + return if is_attached(): if common_regexes.gdb_error.search(send_command("phase-out")): return diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 387fed61..80e7f76d 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -674,9 +674,40 @@ def aob_to_str(list_of_bytes, encoding="ascii"): str: str equivalent of array """ - # 3f is ascii hex representation of char "?" - return bytes.fromhex("".join(list_of_bytes).replace("??", "3f")).decode(encoding, "surrogateescape") + ### make an actual list of bytes + hexString = "" + byteList = list_of_bytes + if (isinstance(list_of_bytes, list)): + byteList = list_of_bytes + else: + byteList = [] + byteList.append(list_of_bytes) + + newByte=0 + for sByte in byteList: + if (sByte == "??"): + hexString += f'{63:02x}' # replace ?? with a single ? + else: + if (isinstance(sByte, int)): + byte=sByte + else: + byte=int(sByte,16) + """NOTE: replacing non-printable chars with a period will + have an adverse effect on the ability to edit hex/ASCII data + since the editor dialog will replace the hex bytes with 2e rather + than replacing only the edited bytes. + + So for now, don't replace them -- but be aware that this clutters + the ascii text in the memory view and does not look 'neat' + """ + #if ( (byte < 32) or (byte > 126) ): + # hexString += f'{46:02x}' # replace non-printable chars with a period (.) + #else: + hexString += f'{byte:02x}' + + hexBytes=bytes.fromhex(hexString) + return hexBytes.decode(encoding, "surrogateescape") #:tag:ValueType def str_to_aob(string, encoding="ascii"): @@ -689,7 +720,7 @@ def str_to_aob(string, encoding="ascii"): Returns: str: AoB equivalent of the given string """ - s = str(binascii.hexlify(string.encode(encoding, "surrogateescape")), "ascii") + s = str(binascii.hexlify(string.encode(encoding, "surrogateescape")), encoding) return " ".join(s[i:i + 2] for i in range(0, len(s), 2)) @@ -1068,6 +1099,8 @@ def wrapper(*args, **kwargs): try: func(*args, **kwargs) except: + #print(f' Args: {args}' ) + #print(f' Kwargs: {kwargs}' ) traceback.print_exc() return wrapper diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 84b7bc5f..42f5ca6e 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -510,14 +510,15 @@ class KeyboardModifiersTupleDict(collections.abc.Mapping): def __init__(self, OrderedDict_like_list): new_dict = {} for keycomb, value in OrderedDict_like_list: - new_dict[keycomb.toCombined()] = value + new_dict[keycomb] = value self._storage = new_dict def __getitem__(self, keycomb): - return self._storage[keycomb.toCombined()] + return self._storage[keycomb] def __iter__(self): return iter(self._storage) def __len__(self): return len(self._storage) + From 0b61b65acce77af0ffde034ad6582ee342868757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 10 Jan 2023 17:08:37 +0300 Subject: [PATCH 086/487] Fix HexModel --- GUI/CustomAbstractTableModels/HexModel.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/GUI/CustomAbstractTableModels/HexModel.py b/GUI/CustomAbstractTableModels/HexModel.py index 21477f0c..a68ea628 100644 --- a/GUI/CustomAbstractTableModels/HexModel.py +++ b/GUI/CustomAbstractTableModels/HexModel.py @@ -15,7 +15,7 @@ along with this program. If not, see . """ from PyQt6.QtCore import QAbstractTableModel, QVariant, Qt -from PyQt6.QtGui import QColor +from PyQt6.QtGui import QColorConstants from libpince import SysUtils, GDB_Engine @@ -36,11 +36,11 @@ def columnCount(self, QModelIndex_parent=None, *args, **kwargs): return self.column_count def data(self, QModelIndex, int_role=None): - if (not self.data_array is None and len(self.data_array) > 0 and QModelIndex.isValid()): + if self.data_array and QModelIndex.isValid(): if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: - return QVariant(QColor.red) + return QVariant(QColorConstants.Red) elif int_role == Qt.ItemDataRole.DisplayRole: return QVariant(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]) @@ -55,9 +55,9 @@ def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): self.data_array = data_array if breakpoint_info is None: breakpoint_info = GDB_Engine.get_breakpoint_info() - for breakpoint in breakpoint_info: - breakpoint_address = int(breakpoint.address, 16) - for i in range(breakpoint.size): + for bp in breakpoint_info: + breakpoint_address = int(bp.address, 16) + for i in range(bp.size): self.breakpoint_list.add(SysUtils.modulo_address(breakpoint_address + i, GDB_Engine.inferior_arch)) self.current_address = int_address self.layoutChanged.emit() From 6c6c77463337f15177c30d16b01d0825209093f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 10 Jan 2023 17:06:49 +0200 Subject: [PATCH 087/487] Update new .py files to PyQT6 --- GUI/EditInstructionDialog.py | 12 +++++------- GUI/RestoreInstructionsWidget.py | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/GUI/EditInstructionDialog.py b/GUI/EditInstructionDialog.py index 3bdbe8e8..fce254b2 100644 --- a/GUI/EditInstructionDialog.py +++ b/GUI/EditInstructionDialog.py @@ -1,14 +1,12 @@ -# -*- coding: utf-8 -*- - # Form implementation generated from reading ui file 'EditInstructionDialog.ui' # -# Created by: PyQt5 UI code generator 5.15.7 +# Created by: PyQt6 UI code generator 6.4.0 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): @@ -23,8 +21,8 @@ def setupUi(self, Dialog): self.lineEdit_OpCodes.setObjectName("lineEdit_OpCodes") self.gridLayout.addWidget(self.lineEdit_OpCodes, 1, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() diff --git a/GUI/RestoreInstructionsWidget.py b/GUI/RestoreInstructionsWidget.py index c191c706..91d0e393 100644 --- a/GUI/RestoreInstructionsWidget.py +++ b/GUI/RestoreInstructionsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'RestoreInstructionsWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. From d790d31fe9a625168818e903bc0b6d100b3eb40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 10 Jan 2023 18:22:27 +0300 Subject: [PATCH 088/487] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 64510669..bd9166aa 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,7 @@ In some cases, ```sudo sh PINCE.sh``` works too, as reported in https://github.c ### For developers: ``` -sudo apt-get install qttools5-dev-tools (qt6 form designer) -sudo apt-get install pyqt6-dev-tools (pyuic5) +sudo apt-get install qt6-base-dev (designer and pyuic6) sudo pip3 install line_profiler (for performance testing) ``` How to use line_profiler: Add ```@profile``` tag to the desired function and run PINCE with ```sudo kernprof -l -v PINCE.py``` From 15461260c021fdcf740c3f672f2e4f781f73ae5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 10 Jan 2023 18:37:22 +0300 Subject: [PATCH 089/487] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bd9166aa..3cd66900 100644 --- a/README.md +++ b/README.md @@ -65,9 +65,9 @@ git clone --recursive https://github.com/korcankaraokcu/PINCE cd PINCE sudo sh install_pince.sh ``` -For Archlinux, you can also use the [AUR package](https://aur.archlinux.org/packages/pince-git/) as an alternative. +~~For Archlinux, you can also use the [AUR package](https://aur.archlinux.org/packages/pince-git/) as an alternative~~ Currently outdated, use the installation script -If you like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them if you want. +If you like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them if you want ***Notes:*** - GDB enhancements (peda, pwndbg, etc) that use a global gdbinit file might cause PINCE to misfunction at times. Please disable them or use them locally before starting PINCE @@ -80,7 +80,7 @@ In some cases, ```sudo sh PINCE.sh``` works too, as reported in https://github.c ### For developers: ``` -sudo apt-get install qt6-base-dev (designer and pyuic6) +sudo apt-get install qt6-tools-dev (designer and pyuic6) sudo pip3 install line_profiler (for performance testing) ``` How to use line_profiler: Add ```@profile``` tag to the desired function and run PINCE with ```sudo kernprof -l -v PINCE.py``` From a31d889b96cbf3794f1380990d78b8a7199c907c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 10 Jan 2023 18:18:38 +0200 Subject: [PATCH 090/487] Fix Edit Instruction dialog after PyQT6 transition --- PINCE.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index 051cec43..f394eb8a 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2680,7 +2680,7 @@ def edit_instruction(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) opcode = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() - EditInstructionDialogForm(current_address, opcode, self).exec_() + EditInstructionDialogForm(current_address, opcode, self).exec() def nop_instruction(self): if GDB_Engine.currentpid == -1: @@ -4726,7 +4726,7 @@ def __init__(self, address, opcode, parent=None): self.orig_opcode = opcode self.orig_instr = SysUtils.get_opcode_name(int(address, 0), opcode, GDB_Engine.get_inferior_arch()) self.is_valid = False - self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) self.lineEdit_Address.setText(address) self.lineEdit_OpCodes.setText(opcode) self.lineEdit_Instruction.setText(self.orig_instr) @@ -4739,7 +4739,7 @@ def set_not_valid(self, instruction, is_original_opcode): self.lineEdit_OpCodes.setStyleSheet("QLineEdit {background-color: red;}") self.lineEdit_Instruction.setText(instruction) self.is_valid = False - self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) def lineEdit_OpCodes_text_edited(self): aob_string = self.lineEdit_OpCodes.text() @@ -4757,7 +4757,7 @@ def lineEdit_OpCodes_text_edited(self): self.lineEdit_OpCodes.setStyleSheet("") self.is_valid = True - self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True) self.refresh_view() def refresh_view(self): From 6e582882aae9ef894b4c8c23966f8adc78d9f7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 14 Jan 2023 00:57:04 +0200 Subject: [PATCH 091/487] Disable hex edit from saving bytes to Restore Instructions widget --- PINCE.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/PINCE.py b/PINCE.py index f394eb8a..7b019cdc 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4856,12 +4856,7 @@ def accept(self): QMessageBox.information(self, "Error", expression + " isn't a valid expression") return value = self.lineEdit_HexView.text() - - try: - address = int(address, 0) - except ValueError: - return - GDB_Engine.modify_instruction(address, value) + GDB_Engine.write_memory(address, type_defs.VALUE_INDEX.INDEX_AOB, value) super(HexEditDialogForm, self).accept() From 7e8d8370220d00ec6f04996221c257e9a7cbc60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 14 Jan 2023 03:04:31 +0300 Subject: [PATCH 092/487] Add double click event to tableWidget_Instructions --- PINCE.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PINCE.py b/PINCE.py index 7b019cdc..3eeb8191 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4002,6 +4002,7 @@ def __init__(self, parent=None): self.tableWidget_Instructions.keyPressEvent_original = self.tableWidget_Instructions.keyPressEvent self.tableWidget_Instructions.keyPressEvent = self.tableWidget_Instructions_key_press_event self.tableWidget_Instructions.contextMenuEvent = self.tableWidget_Instructions_context_menu_event + self.tableWidget_Instructions.itemDoubleClicked.connect(self.tableWidget_Instructions_double_clicked) self.refresh() def tableWidget_Instructions_context_menu_event(self, event): @@ -4058,6 +4059,11 @@ def tableWidget_Instructions_key_press_event(self, event): pass self.tableWidget_Instructions.keyPressEvent_original(event) + def tableWidget_Instructions_double_clicked(self, index): + current_address_text = self.tableWidget_Instructions.item(index.row(), INSTR_ADDR_COL).text() + current_address = SysUtils.extract_address(current_address_text) + self.parent().disassemble_expression(current_address, append_to_travel_history=True) + def closeEvent(self, QCloseEvent): global instances instances.remove(self) From af42dbe49186c76120bf520271b3978a032f1b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 14 Jan 2023 03:42:05 +0300 Subject: [PATCH 093/487] Auto PEP-8 --- PINCE.py | 112 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 70 insertions(+), 42 deletions(-) diff --git a/PINCE.py b/PINCE.py index 3eeb8191..87eb543d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -289,7 +289,8 @@ def except_hook(exception_type, value, tb): elif exception_type == type_defs.InferiorRunningException: error_dialog = InputDialogForm(item_list=[( "Process is running" + "\nPress " + Hotkeys.break_hotkey.get_active_key() + " to stop process" + - "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.StandardButton.Ok]) + "\n\nGo to Settings->General to disable this dialog",)], + buttons=[QDialogButtonBox.StandardButton.Ok]) error_dialog.exec() traceback.print_exception(exception_type, value, tb) @@ -462,8 +463,10 @@ def __init__(self): self.comboBox_ValueType_init() self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) - self.lineEdit_Scan.setValidator(QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan)) - self.lineEdit_Scan2.setValidator(QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.setValidator( + QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan)) + self.lineEdit_Scan2.setValidator( + QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan2)) self.comboBox_ScanType.currentIndexChanged.connect(self.comboBox_ScanType_current_index_changed) self.comboBox_ScanType_current_index_changed() self.pushButton_Settings.clicked.connect(self.pushButton_Settings_clicked) @@ -640,7 +643,8 @@ def toggle_attach_hotkey_pressed(self): dialog_text = "GDB is attached back to the process" if show_messagebox_on_toggle_attach: dialog = InputDialogForm(item_list=[( - dialog_text + "\n\nGo to Settings->General to disable this dialog",)], buttons=[QDialogButtonBox.StandardButton.Ok]) + dialog_text + "\n\nGo to Settings->General to disable this dialog",)], + buttons=[QDialogButtonBox.StandardButton.Ok]) dialog.exec() def treeWidget_AddressTable_context_menu_event(self, event): @@ -895,13 +899,20 @@ def treeWidget_AddressTable_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_selected_records), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_X), self.cut_selected_records_recursively), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_C), self.copy_selected_records_recursively), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), lambda: self.paste_records(insert_after=False)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), lambda: self.paste_records(insert_after=True)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_I), lambda: self.paste_records(insert_inside=True)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_value), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_desc), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_address), - (QKeyCombination(Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_type) + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), + lambda: self.paste_records(insert_after=False)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), + lambda: self.paste_records(insert_after=True)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_I), + lambda: self.paste_records(insert_inside=True)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Return), + self.treeWidget_AddressTable_edit_value), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), + self.treeWidget_AddressTable_edit_desc), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), + self.treeWidget_AddressTable_edit_address), + ( + QKeyCombination(Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_type) ]) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() @@ -1020,7 +1031,6 @@ def pushButton_NewFirstScan_clicked(self): self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan - def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, type_defs.SCAN_TYPE.UNCHANGED, type_defs.SCAN_TYPE.UNKNOWN] @@ -1155,7 +1165,8 @@ def _scan_to_length(self, type_index): def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) - self.add_entry_to_addresstable("No Description", current_item.text(), current_item.data(Qt.ItemDataRole.UserRole)[0], length) + self.add_entry_to_addresstable("No Description", current_item.text(), + current_item.data(Qt.ItemDataRole.UserRole)[0], length) def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) @@ -1163,7 +1174,8 @@ def comboBox_ValueType_current_index_changed(self): "int": QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan), # integers "float": QRegularExpressionValidator(QRegularExpression("-?[0-9]+[.,]?[0-9]*")), # floats, should work fine with the small amount of testing I did - "bytearray": QRegularExpressionValidator(QRegularExpression("^(([A-Fa-f0-9?]{2} +)+)$"), parent=self.lineEdit_Scan), + "bytearray": QRegularExpressionValidator(QRegularExpression("^(([A-Fa-f0-9?]{2} +)+)$"), + parent=self.lineEdit_Scan), # array of bytes "string": None } @@ -1980,7 +1992,8 @@ def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typ except IndexError: label.setAlignment(Qt.AlignmentFlag.AlignCenter) label.setText(item[0]) - label.setTextInteractionFlags(Qt.TextInteractionFlag.LinksAccessibleByMouse | Qt.TextInteractionFlag.TextSelectableByMouse) + label.setTextInteractionFlags( + Qt.TextInteractionFlag.LinksAccessibleByMouse | Qt.TextInteractionFlag.TextSelectableByMouse) self.verticalLayout.addWidget(label) try: item_data = item[1] @@ -2420,7 +2433,7 @@ def lineEdit_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), self.scroll_forwards_history) ]) try: - actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: self.lineEdit.keyPressEvent_original(event) @@ -2638,7 +2651,6 @@ def initialize_hex_view(self): GuiUtils.center_scroll_bar(self.verticalScrollBar_HexView) - def show_trace_window(self): if GDB_Engine.currentpid == -1: return @@ -2731,6 +2743,7 @@ def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.B def label_HexView_Information_context_menu_event(self, event): if GDB_Engine.currentpid == -1: return + def copy_to_clipboard(): app.clipboard().setText(self.label_HexView_Information.text()) @@ -2823,20 +2836,21 @@ def exec_hex_view_add_address_dialog(self): def hex_view_scroll_up(self): self.verticalScrollBar_HexView.setValue(1) + def hex_view_scroll_down(self): self.verticalScrollBar_HexView.setValue(-1) def hex_view_scrollbar_sliderchanged(self, event): if self.bHexViewScrolling: - return; - self.bHexViewScrolling=True - #if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: + return + self.bHexViewScrolling = True + # if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: # return maximum = self.verticalScrollBar_HexView.maximum() minimum = self.verticalScrollBar_HexView.minimum() midst = (maximum + minimum) / 2 current_value = self.verticalScrollBar_HexView.value() - #if midst - 10 < current_value < midst + 10: + # if midst - 10 < current_value < midst + 10: # self.bHexViewScrolling = False # return current_address = self.hex_model.current_address @@ -2850,20 +2864,21 @@ def hex_view_scrollbar_sliderchanged(self, event): def disassemble_scroll_up(self): self.verticalScrollBar_Disassemble.setValue(1) + def disassemble_scroll_down(self): self.verticalScrollBar_Disassemble.setValue(-1) def disassemble_scrollbar_sliderchanged(self, even): if self.bDisassemblyScrolling: - return; + return self.bDisassemblyScrolling = True - #if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: + # if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: # return maximum = self.verticalScrollBar_Disassemble.maximum() minimum = self.verticalScrollBar_Disassemble.minimum() midst = (maximum + minimum) / 2 current_value = self.verticalScrollBar_Disassemble.value() - #if midst - 10 < current_value < midst + 10: + # if midst - 10 < current_value < midst + 10: # self.bDisassemblyScrolling = False # return if current_value < midst: @@ -3180,7 +3195,8 @@ def add_breakpoint_condition(self, int_address): condition_line_edit_text = breakpoint.condition else: condition_line_edit_text = "" - condition_dialog = InputDialogForm(item_list=[(condition_text, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) + condition_dialog = InputDialogForm( + item_list=[(condition_text, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) if condition_dialog.exec(): condition = condition_dialog.get_values() if not GDB_Engine.modify_breakpoint(hex(int_address), type_defs.BREAKPOINT_MODIFY.CONDITION, @@ -3260,6 +3276,7 @@ def set_stack_widget(self, stack_widget): def tableWidget_StackTrace_context_menu_event(self, event): if GDB_Engine.currentpid == -1: return + def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_StackTrace.item(row, column).text()) @@ -3312,10 +3329,11 @@ def tableWidget_Stack_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), lambda: self.disassemble_expression(current_address, append_to_travel_history=True)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), lambda: self.hex_dump_address(int(current_address, 16))) + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), + lambda: self.hex_dump_address(int(current_address, 16))) ]) try: - actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_Stack.keyPressEvent_original(event) @@ -3398,7 +3416,7 @@ def tableWidget_StackTrace_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stacktrace) ]) try: - actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_StackTrace.keyPressEvent_original(event) @@ -3467,7 +3485,7 @@ def widget_HexView_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.hex_view_scroll_down), ]) try: - actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: pass self.tableView_HexView_Hex.keyPressEvent_original(event) @@ -3481,21 +3499,27 @@ def tableWidget_Disassemble_key_press_event(self, event): current_address_int = int(current_address, 16) actions = type_defs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), lambda: self.follow_instruction(selected_row)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_E), lambda: self.exec_examine_referrers_widget(current_address_text)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), + lambda: self.follow_instruction(selected_row)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_E), + lambda: self.exec_examine_referrers_widget(current_address_text)), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_disassemble_go_to_dialog), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), lambda: self.hex_dump_address(current_address_int)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), lambda: self.bookmark_address(current_address_int)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), + lambda: self.hex_dump_address(current_address_int)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), + lambda: self.bookmark_address(current_address_int)), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.dissect_current_region), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_T), self.exec_trace_instructions_dialog), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_disassemble_view), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), lambda: self.disassemble_check_viewport("next", 1)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), lambda: self.disassemble_check_viewport("previous", 1)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), + lambda: self.disassemble_check_viewport("next", 1)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), + lambda: self.disassemble_check_viewport("previous", 1)), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.disassemble_scroll_up), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.disassemble_scroll_down) ]) try: - actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_Disassemble.keyPressEvent_original(event) @@ -4054,7 +4078,7 @@ def tableWidget_Instructions_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) ]) try: - actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_Instructions.keyPressEvent_original(event) @@ -4118,11 +4142,12 @@ def tableWidget_BreakpointInfo_key_press_event(self, event): current_address = None actions = type_defs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), lambda: self.delete_breakpoint(current_address)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), + lambda: self.delete_breakpoint(current_address)), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) ]) try: - actions[QKeyCombination(event.modifiers(),Qt.Key(event.key()))]() + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: pass self.tableWidget_BreakpointInfo.keyPressEvent_original(event) @@ -4391,7 +4416,8 @@ def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() self.parent().parent().add_entry_to_addresstable("Accessed by " + self.address, address, - self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole), 10, True) + self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole), + 10, True) def pushButton_Stop_clicked(self): if self.stopped: @@ -4718,7 +4744,8 @@ def pushButton_Help_clicked(self): "\n@plt means this function is a subroutine for the original one" \ "\nThere can be more than one of the same function" \ "\nIt means that the function is overloaded" - InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() + InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], + buttons=[QDialogButtonBox.StandardButton.Ok]).exec() def closeEvent(self, QCloseEvent): global instances @@ -5227,7 +5254,8 @@ def pushButton_Help_clicked(self): "\n'[re]cx' searches for both 'rcx' and 'ecx'" \ "\nUse the char '\\' to escape special chars such as '['" \ "\n'\[rsp\]' searches for opcodes that contain '[rsp]'" - InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() + InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], + buttons=[QDialogButtonBox.StandardButton.Ok]).exec() def tableWidget_Opcodes_item_double_clicked(self, index): row = index.row() From b916e525023ad077504199a256c66d63e6fcdc5b Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 15 Jan 2023 11:53:31 +0100 Subject: [PATCH 094/487] add exit on error function --- install_pince.sh | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index cbe6a0d2..e4c28018 100644 --- a/install_pince.sh +++ b/install_pince.sh @@ -23,17 +23,25 @@ along with this program. If not, see . CURRENT_USER="$(who mom likes | awk '{print $1}')" +exit_on_error() { + if [ "$?" -ne 0 ]; then + echo "Error occured while installing PINCE, check the output above for more information" + echo "Installation failed." + exit 1 + fi +} + # assumes you're in scanmem directory compile_scanmem() { - sh autogen.sh - ./configure --prefix="$(pwd)" - make -j libscanmem.la + sh autogen.sh || exit_on_error + ./configure --prefix="$(pwd)" || exit_on_error + make -j libscanmem.la || exit_on_error chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file } install_scanmem() { echo "Downloading scanmem" - git submodule update --init --recursive + git submodule update --init --recursive || exit_on_error if [ ! -d "libpince/libscanmem" ]; then mkdir libpince/libscanmem @@ -41,7 +49,7 @@ install_scanmem() { fi ( echo "Entering scanmem" - cd scanmem || exit + cd scanmem || exit_on_error if [ -d "./.libs" ]; then echo "Recompile scanmem? [y/n]" read -r answer @@ -58,6 +66,7 @@ install_scanmem() { ) # required for relative import, since it will throw an import error if it's just `import misc` sed -i 's/import misc/from \. import misc/g' libpince/libscanmem/scanmem.py + return 0 } OS_NAME="Debian" From f8c137f5488ceb8c89e17583df906861940af250 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 15 Jan 2023 11:55:06 +0100 Subject: [PATCH 095/487] add SteamOS unofficially to install script --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index e4c28018..f878c0e7 100644 --- a/install_pince.sh +++ b/install_pince.sh @@ -97,7 +97,7 @@ case "$OS_NAME" in PKG_MGR="zypper" PKG_NAMES="$PKG_NAMES_SUSE" ;; -*Arch*) +*Arch* | *SteamOS*) PKG_MGR="pacman" PKG_NAMES="$PKG_NAMES_ARCH" INSTALL_COMMAND="-S" From f9c4347ca3a23509733323d8ee29bbe3e156f6eb Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 15 Jan 2023 12:32:46 +0100 Subject: [PATCH 096/487] change function to return 1 on error exit out after each step if error --- install_pince.sh | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index f878c0e7..51fcede7 100644 --- a/install_pince.sh +++ b/install_pince.sh @@ -25,6 +25,7 @@ CURRENT_USER="$(who mom likes | awk '{print $1}')" exit_on_error() { if [ "$?" -ne 0 ]; then + echo echo "Error occured while installing PINCE, check the output above for more information" echo "Installation failed." exit 1 @@ -33,15 +34,16 @@ exit_on_error() { # assumes you're in scanmem directory compile_scanmem() { - sh autogen.sh || exit_on_error - ./configure --prefix="$(pwd)" || exit_on_error - make -j libscanmem.la || exit_on_error + sh autogen.sh || return 1 + ./configure --prefix="$(pwd)" || return 1 + make -j libscanmem.la || return 1 chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file + return 0 } install_scanmem() { echo "Downloading scanmem" - git submodule update --init --recursive || exit_on_error + git submodule update --init --recursive || return 1 if [ ! -d "libpince/libscanmem" ]; then mkdir libpince/libscanmem @@ -49,15 +51,15 @@ install_scanmem() { fi ( echo "Entering scanmem" - cd scanmem || exit_on_error + cd scanmem || return 1 if [ -d "./.libs" ]; then echo "Recompile scanmem? [y/n]" read -r answer if echo "$answer" | grep -iq "^[Yy]"; then - compile_scanmem + compile_scanmem || return 1 fi else - compile_scanmem + compile_scanmem || return 1 fi cp --preserve .libs/libscanmem.so ../libpince/libscanmem/ cp --preserve gui/scanmem.py ../libpince/libscanmem @@ -110,11 +112,12 @@ case "$OS_NAME" in esac # shellcheck disable=SC2086 -sudo ${PKG_MGR} ${INSTALL_COMMAND} ${PKG_NAMES} +sudo ${PKG_MGR} ${INSTALL_COMMAND} ${PKG_NAMES} || exit_on_error # shellcheck disable=SC2086 -sudo ${PIP_COMMAND} install ${PKG_NAMES_PIP} +sudo ${PIP_COMMAND} install ${PKG_NAMES_PIP} || exit_on_error -install_scanmem +install_scanmem || exit_on_error +echo echo "PINCE has been installed successfully!" echo "Now, just run 'sh PINCE.sh' from terminal" From c4d1656d52ea020a57f24290158105d59bf86cdf Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 15 Jan 2023 13:18:20 +0100 Subject: [PATCH 097/487] rm steamOS again from feedback --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index 51fcede7..a0ceb90f 100644 --- a/install_pince.sh +++ b/install_pince.sh @@ -99,7 +99,7 @@ case "$OS_NAME" in PKG_MGR="zypper" PKG_NAMES="$PKG_NAMES_SUSE" ;; -*Arch* | *SteamOS*) +*Arch*) PKG_MGR="pacman" PKG_NAMES="$PKG_NAMES_ARCH" INSTALL_COMMAND="-S" From 62d77f3c4b19ff56bdc02538beb59aeaa9f4564f Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 15 Jan 2023 18:59:27 +0100 Subject: [PATCH 098/487] Fix return in artificial context not passed on --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index a0ceb90f..ce677311 100644 --- a/install_pince.sh +++ b/install_pince.sh @@ -65,7 +65,7 @@ install_scanmem() { cp --preserve gui/scanmem.py ../libpince/libscanmem cp --preserve gui/misc.py ../libpince/libscanmem echo "Exiting scanmem" - ) + ) || return 1 # required for relative import, since it will throw an import error if it's just `import misc` sed -i 's/import misc/from \. import misc/g' libpince/libscanmem/scanmem.py return 0 From 9eada95eae4ee41f63bbf8c8d1f71f71709ccac3 Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Mon, 16 Jan 2023 20:22:28 +0700 Subject: [PATCH 099/487] fix scan_mode initial --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 87eb543d..98d05860 100755 --- a/PINCE.py +++ b/PINCE.py @@ -457,7 +457,7 @@ def __init__(self): self.pushButton_Save.clicked.connect(self.pushButton_Save_clicked) self.pushButton_NewFirstScan.clicked.connect(self.pushButton_NewFirstScan_clicked) self.pushButton_NextScan.clicked.connect(self.pushButton_NextScan_clicked) - self.scan_mode = type_defs.SCAN_MODE.ONGOING + self.scan_mode = type_defs.SCAN_MODE.NEW self.pushButton_NewFirstScan_clicked() self.comboBox_ScanScope_init() self.comboBox_ValueType_init() From e7a3e57da8cada303dd13a500d9a73e2782f178e Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Tue, 17 Jan 2023 06:58:25 +0700 Subject: [PATCH 100/487] FIX: scan type is set wrong and flipped because of previous commit thanks for the help: https://github.com/brkzlr Scan type is wrong and flipped because `ScanType_Init` because the ScanType_Init function is called right before the scan_mode values are swapped after pressing on First Scan/New Scan --- PINCE.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 98d05860..24c39da8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1008,8 +1008,8 @@ def checkBox_Hex_stateChanged(self, state): # TODO add a damn keybind for this... def pushButton_NewFirstScan_clicked(self): - self.comboBox_ScanType_init() if GDB_Engine.currentpid == -1: + self.comboBox_ScanType_init() return if self.scan_mode == type_defs.SCAN_MODE.ONGOING: self.scan_mode = type_defs.SCAN_MODE.NEW @@ -1031,6 +1031,8 @@ def pushButton_NewFirstScan_clicked(self): self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan + self.comboBox_ScanType_init() + def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, type_defs.SCAN_TYPE.UNCHANGED, type_defs.SCAN_TYPE.UNKNOWN] From 713da9a6858bd376dd80739ce287261c6fb3d57f Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Sat, 21 Jan 2023 21:07:19 +0700 Subject: [PATCH 101/487] refactor comboBox_ScanType_init --- PINCE.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 24c39da8..36777096 100755 --- a/PINCE.py +++ b/PINCE.py @@ -458,7 +458,7 @@ def __init__(self): self.pushButton_NewFirstScan.clicked.connect(self.pushButton_NewFirstScan_clicked) self.pushButton_NextScan.clicked.connect(self.pushButton_NextScan_clicked) self.scan_mode = type_defs.SCAN_MODE.NEW - self.pushButton_NewFirstScan_clicked() + self.comboBox_ScanType_init(self.scan_mode) self.comboBox_ScanScope_init() self.comboBox_ValueType_init() self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) @@ -1009,7 +1009,7 @@ def checkBox_Hex_stateChanged(self, state): # TODO add a damn keybind for this... def pushButton_NewFirstScan_clicked(self): if GDB_Engine.currentpid == -1: - self.comboBox_ScanType_init() + self.comboBox_ScanType_init(self.scan_mode) return if self.scan_mode == type_defs.SCAN_MODE.ONGOING: self.scan_mode = type_defs.SCAN_MODE.NEW @@ -1031,7 +1031,7 @@ def pushButton_NewFirstScan_clicked(self): self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan - self.comboBox_ScanType_init() + self.comboBox_ScanType_init(self.scan_mode) def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, @@ -1047,10 +1047,10 @@ def comboBox_ScanType_current_index_changed(self): self.label_Between.setVisible(False) self.lineEdit_Scan2.setVisible(False) - def comboBox_ScanType_init(self): + def comboBox_ScanType_init(self, _scan_mode: type_defs.SCAN_MODE): current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() - if self.scan_mode == type_defs.SCAN_MODE.NEW: + if _scan_mode == type_defs.SCAN_MODE.NEW: items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.LESS, type_defs.SCAN_TYPE.MORE, type_defs.SCAN_TYPE.BETWEEN, type_defs.SCAN_TYPE.UNKNOWN] else: From ee9db8d2a5b81392b6f3576a272d5a98f10b7aa1 Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Sat, 21 Jan 2023 21:55:05 +0700 Subject: [PATCH 102/487] add no_selected_proc_warning --- PINCE.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 36777096..acb4d9e8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -587,6 +587,18 @@ def apply_settings(self): if GDB_Engine.gdb_initialized: self.apply_after_init() + def no_selected_proc_warning(self): + msg_box = QMessageBox() + msg_box.setIcon(QMessageBox.Icon.Warning) + msg_box.setWindowTitle("No process selected") + msg_box.setText("process need to be selected to do this operation, select one?") + msg_box.setStandardButtons(QMessageBox.StandardButton.No | QMessageBox.StandardButton.Yes) + ret_val = msg_box.exec() + # if user want to select process + if ret_val == QMessageBox.StandardButton.Yes: + self.processwindow = ProcessForm(self) + self.processwindow.show() + # Check if any process should be attached to automatically # Patterns at former positions have higher priority if regex is off def auto_attach(self): @@ -1009,8 +1021,9 @@ def checkBox_Hex_stateChanged(self, state): # TODO add a damn keybind for this... def pushButton_NewFirstScan_clicked(self): if GDB_Engine.currentpid == -1: - self.comboBox_ScanType_init(self.scan_mode) + self.no_selected_proc_warning() return + if self.scan_mode == type_defs.SCAN_MODE.ONGOING: self.scan_mode = type_defs.SCAN_MODE.NEW self.pushButton_NewFirstScan.setText("First Scan") From 0aa3e6c02ef45dd450f7a7192be207dc3a7ce5df Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Sat, 21 Jan 2023 22:06:10 +0700 Subject: [PATCH 103/487] change `no_selected_proc_warning` warning text --- PINCE.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index acb4d9e8..04300918 100755 --- a/PINCE.py +++ b/PINCE.py @@ -591,11 +591,11 @@ def no_selected_proc_warning(self): msg_box = QMessageBox() msg_box.setIcon(QMessageBox.Icon.Warning) msg_box.setWindowTitle("No process selected") - msg_box.setText("process need to be selected to do this operation, select one?") - msg_box.setStandardButtons(QMessageBox.StandardButton.No | QMessageBox.StandardButton.Yes) + msg_box.setText("No process is selected! Do you want to select one now?") + msg_box.setStandardButtons(QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Ok) ret_val = msg_box.exec() # if user want to select process - if ret_val == QMessageBox.StandardButton.Yes: + if ret_val == QMessageBox.StandardButton.Ok: self.processwindow = ProcessForm(self) self.processwindow.show() From 9fd46b2878bc7f454a551c52862051f902106fde Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Sat, 21 Jan 2023 22:29:10 +0700 Subject: [PATCH 104/487] change `comboBox_ScanType_init` params back --- PINCE.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index 04300918..3b67b954 100755 --- a/PINCE.py +++ b/PINCE.py @@ -458,7 +458,7 @@ def __init__(self): self.pushButton_NewFirstScan.clicked.connect(self.pushButton_NewFirstScan_clicked) self.pushButton_NextScan.clicked.connect(self.pushButton_NextScan_clicked) self.scan_mode = type_defs.SCAN_MODE.NEW - self.comboBox_ScanType_init(self.scan_mode) + self.comboBox_ScanType_init() self.comboBox_ScanScope_init() self.comboBox_ValueType_init() self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) @@ -1044,7 +1044,7 @@ def pushButton_NewFirstScan_clicked(self): self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan - self.comboBox_ScanType_init(self.scan_mode) + self.comboBox_ScanType_init() def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, @@ -1060,10 +1060,10 @@ def comboBox_ScanType_current_index_changed(self): self.label_Between.setVisible(False) self.lineEdit_Scan2.setVisible(False) - def comboBox_ScanType_init(self, _scan_mode: type_defs.SCAN_MODE): + def comboBox_ScanType_init(self): current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() - if _scan_mode == type_defs.SCAN_MODE.NEW: + if self.scan_mode == type_defs.SCAN_MODE.NEW: items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.LESS, type_defs.SCAN_TYPE.MORE, type_defs.SCAN_TYPE.BETWEEN, type_defs.SCAN_TYPE.UNKNOWN] else: From 230078c77f6d035ecb21db8d93899d0c360a8681 Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Mon, 23 Jan 2023 21:50:57 +0700 Subject: [PATCH 105/487] Revert "refactor comboBox_ScanType_init" This reverts commit 577568f75c5c597a3d32e67deae76781d45307ef. --- PINCE.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/PINCE.py b/PINCE.py index 3b67b954..24c39da8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -458,7 +458,7 @@ def __init__(self): self.pushButton_NewFirstScan.clicked.connect(self.pushButton_NewFirstScan_clicked) self.pushButton_NextScan.clicked.connect(self.pushButton_NextScan_clicked) self.scan_mode = type_defs.SCAN_MODE.NEW - self.comboBox_ScanType_init() + self.pushButton_NewFirstScan_clicked() self.comboBox_ScanScope_init() self.comboBox_ValueType_init() self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) @@ -587,18 +587,6 @@ def apply_settings(self): if GDB_Engine.gdb_initialized: self.apply_after_init() - def no_selected_proc_warning(self): - msg_box = QMessageBox() - msg_box.setIcon(QMessageBox.Icon.Warning) - msg_box.setWindowTitle("No process selected") - msg_box.setText("No process is selected! Do you want to select one now?") - msg_box.setStandardButtons(QMessageBox.StandardButton.Cancel | QMessageBox.StandardButton.Ok) - ret_val = msg_box.exec() - # if user want to select process - if ret_val == QMessageBox.StandardButton.Ok: - self.processwindow = ProcessForm(self) - self.processwindow.show() - # Check if any process should be attached to automatically # Patterns at former positions have higher priority if regex is off def auto_attach(self): @@ -1021,9 +1009,8 @@ def checkBox_Hex_stateChanged(self, state): # TODO add a damn keybind for this... def pushButton_NewFirstScan_clicked(self): if GDB_Engine.currentpid == -1: - self.no_selected_proc_warning() + self.comboBox_ScanType_init() return - if self.scan_mode == type_defs.SCAN_MODE.ONGOING: self.scan_mode = type_defs.SCAN_MODE.NEW self.pushButton_NewFirstScan.setText("First Scan") From 02d2ef28a9d97af067cc3a1441737cc326e1d0f9 Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Mon, 23 Jan 2023 21:57:17 +0700 Subject: [PATCH 106/487] disable QWidget_Toolbox before process is selected --- PINCE.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 24c39da8..fe3570c9 100755 --- a/PINCE.py +++ b/PINCE.py @@ -496,7 +496,7 @@ def __init__(self): self.pushButton_Console.setIcon(QIcon(QPixmap(icons_directory + "/application_xp_terminal.png"))) self.pushButton_Wiki.setIcon(QIcon(QPixmap(icons_directory + "/book_open.png"))) self.pushButton_About.setIcon(QIcon(QPixmap(icons_directory + "/information.png"))) - self.QWidget_Toolbox.setEnabled(True) + self.QWidget_Toolbox.setEnabled(False) self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) self.auto_attach() @@ -1603,6 +1603,8 @@ def pushButton_Open_clicked(self): if self.parent().attach_to_pid(pid): self.close() self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) + # a process has been selected re-enable main gui + self.QWidget_Toolbox.setEnabled(True) def pushButton_CreateProcess_clicked(self): file_path = QFileDialog.getOpenFileName(self, "Select the target binary")[0] From 78eafe35a4a44b6e30c7594117231e7d1c9babc0 Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Mon, 23 Jan 2023 22:27:35 +0700 Subject: [PATCH 107/487] disable mem view, add address and qwidget_toolbox via ui file --- GUI/MainWindow.py | 10 ++++++---- GUI/MainWindow.ui | 10 ++++++++-- PINCE.py | 5 +++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index cd48774a..b8ac86d5 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -1,6 +1,6 @@ -# Form implementation generated from reading ui file 'MainWindow.ui' +# Form implementation generated from reading ui file './MainWindow.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -30,6 +30,7 @@ def setupUi(self, MainWindow): self.horizontalLayout_8.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinAndMaxSize) self.horizontalLayout_8.setObjectName("horizontalLayout_8") self.pushButton_MemoryView = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_MemoryView.setEnabled(False) self.pushButton_MemoryView.setObjectName("pushButton_MemoryView") self.horizontalLayout_8.addWidget(self.pushButton_MemoryView) spacerItem = QtWidgets.QSpacerItem(120, 20, QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Minimum) @@ -51,6 +52,7 @@ def setupUi(self, MainWindow): spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem2) self.pushButton_AddAddressManually = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_AddAddressManually.setEnabled(False) self.pushButton_AddAddressManually.setObjectName("pushButton_AddAddressManually") self.horizontalLayout_8.addWidget(self.pushButton_AddAddressManually) self.gridLayout.addLayout(self.horizontalLayout_8, 2, 0, 1, 1) @@ -151,7 +153,7 @@ def setupUi(self, MainWindow): self.verticalLayout_6.addWidget(self.tableWidget_valuesearchtable) self.horizontalLayout_9.addLayout(self.verticalLayout_6) self.QWidget_Toolbox = QtWidgets.QWidget(self.centralwidget) - self.QWidget_Toolbox.setEnabled(True) + self.QWidget_Toolbox.setEnabled(False) self.QWidget_Toolbox.setObjectName("QWidget_Toolbox") self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.QWidget_Toolbox) self.verticalLayout_5.setObjectName("verticalLayout_5") @@ -282,7 +284,7 @@ def setupUi(self, MainWindow): self.gridLayout.addLayout(self.horizontalLayout_9, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 30)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index a14d5166..fcc87708 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -72,6 +72,9 @@ + + false + Memory View @@ -151,6 +154,9 @@ + + false + Add Address Manually @@ -357,7 +363,7 @@ - true + false @@ -671,7 +677,7 @@ 0 0 678 - 30 + 22 diff --git a/PINCE.py b/PINCE.py index fe3570c9..08e20236 100755 --- a/PINCE.py +++ b/PINCE.py @@ -496,7 +496,7 @@ def __init__(self): self.pushButton_Console.setIcon(QIcon(QPixmap(icons_directory + "/application_xp_terminal.png"))) self.pushButton_Wiki.setIcon(QIcon(QPixmap(icons_directory + "/book_open.png"))) self.pushButton_About.setIcon(QIcon(QPixmap(icons_directory + "/information.png"))) - self.QWidget_Toolbox.setEnabled(False) + #self.QWidget_Toolbox.setEnabled(False) self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) self.auto_attach() @@ -1275,6 +1275,8 @@ def on_new_process(self): self.QWidget_Toolbox.setEnabled(True) self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) + self.pushButton_AddAddressManually.setEnabled(True) + self.pushButton_MemoryView.setEnabled(True) def delete_address_table_contents(self): if self.treeWidget_AddressTable.topLevelItemCount() == 0: @@ -1604,7 +1606,6 @@ def pushButton_Open_clicked(self): self.close() self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) # a process has been selected re-enable main gui - self.QWidget_Toolbox.setEnabled(True) def pushButton_CreateProcess_clicked(self): file_path = QFileDialog.getOpenFileName(self, "Select the target binary")[0] From 054ffba27a5273c3294a952c27dc1580ccd0a1b5 Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Mon, 23 Jan 2023 22:44:02 +0700 Subject: [PATCH 108/487] revert menubar height accidently changed them when using qt designer --- GUI/MainWindow.py | 4 ++-- GUI/MainWindow.ui | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index b8ac86d5..e4f577e1 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -1,4 +1,4 @@ -# Form implementation generated from reading ui file './MainWindow.ui' +# Form implementation generated from reading ui file 'MainWindow.ui' # # Created by: PyQt6 UI code generator 6.4.0 # @@ -284,7 +284,7 @@ def setupUi(self, MainWindow): self.gridLayout.addLayout(self.horizontalLayout_9, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 22)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 30)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index fcc87708..e3723d5e 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -677,7 +677,7 @@ 0 0 678 - 22 + 30 From a63e7f7e1128916fb4bc281b86e1426256dd082c Mon Sep 17 00:00:00 2001 From: KuhakuPixel Date: Mon, 23 Jan 2023 22:59:11 +0700 Subject: [PATCH 109/487] remove useless comments --- PINCE.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 08e20236..9b337405 100755 --- a/PINCE.py +++ b/PINCE.py @@ -496,7 +496,6 @@ def __init__(self): self.pushButton_Console.setIcon(QIcon(QPixmap(icons_directory + "/application_xp_terminal.png"))) self.pushButton_Wiki.setIcon(QIcon(QPixmap(icons_directory + "/book_open.png"))) self.pushButton_About.setIcon(QIcon(QPixmap(icons_directory + "/information.png"))) - #self.QWidget_Toolbox.setEnabled(False) self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) self.auto_attach() @@ -1605,7 +1604,6 @@ def pushButton_Open_clicked(self): if self.parent().attach_to_pid(pid): self.close() self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) - # a process has been selected re-enable main gui def pushButton_CreateProcess_clicked(self): file_path = QFileDialog.getOpenFileName(self, "Select the target binary")[0] From 4265ec3f1787d6641914d401029fc7eeca5eb302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 29 Jan 2023 02:21:53 +0200 Subject: [PATCH 110/487] Add debug configuration for Visual Studio Code/Vimspector --- .gitignore | 1 + .vimspector.json | 33 +++++++++++++++++++++++++++++++++ .vscode/launch.json | 19 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 .vimspector.json create mode 100644 .vscode/launch.json diff --git a/.gitignore b/.gitignore index 28543fcd..17cce2a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ __pycache__/ .idea/* .vscode/* +!.vscode/launch.json libscanmem.so* libpince/libscanmem/* *.directory diff --git a/.vimspector.json b/.vimspector.json new file mode 100644 index 00000000..fb33cb7e --- /dev/null +++ b/.vimspector.json @@ -0,0 +1,33 @@ +{ + "configurations": { + "Debug PINCE": { + "adapter": "debugpy", + "default": true, + "variables": { + "Python": { + "shell": "/bin/sh -c 'if [ -z \"${dollar}VIRTUAL_ENV\" ]; then echo $$(which python3); else echo \"${dollar}VIRTUAL_ENV/bin/python\"; fi'" + } + }, + "filetypes": [ "python" ], + "configuration": { + "name": "Debug PINCE", + "type": "python", + "request": "launch", + "cwd": "${workspaceFolder}", + "python": "$Python", + "stopOnEntry": false, + "justMyCode": false, + "sudo": true, + "console": "integratedTerminal", + "program": "PINCE.py" + }, + "breakpoints": { + "exception": { + "uncaught": "Y", + "raised": "N", + "userUnhandled": "N" + } + } + } + } +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..c3cf96dc --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Debug PINCE", + "type": "python", + "request": "launch", + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "justMyCode": false, + "sudo": true, + "console": "integratedTerminal", + "program": "PINCE.py" + } + ] +} From 6e1338ca408343b9618f3f9aa831fb6d2b6a3cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 29 Jan 2023 14:15:50 +0200 Subject: [PATCH 111/487] Fix missing icons when lauching through debugger --- .vimspector.json | 2 +- .vscode/launch.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vimspector.json b/.vimspector.json index fb33cb7e..db0c78dc 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -19,7 +19,7 @@ "justMyCode": false, "sudo": true, "console": "integratedTerminal", - "program": "PINCE.py" + "program": "${workspaceFolder}/PINCE.py" }, "breakpoints": { "exception": { diff --git a/.vscode/launch.json b/.vscode/launch.json index c3cf96dc..2149684f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,7 @@ "justMyCode": false, "sudo": true, "console": "integratedTerminal", - "program": "PINCE.py" + "program": "${workspaceFolder}/PINCE.py" } ] } From 0683b39e12791d52cebd5f376537483dfa91e141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 29 Jan 2023 16:58:56 +0300 Subject: [PATCH 112/487] Fixed modularity of script_directory --- libpince/SysUtils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 22348868..d06a0286 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -210,7 +210,7 @@ def get_media_directory(): Returns: str: A string pointing to the media directory """ - return sys.path[0] + "/media" + return get_current_script_directory() + "/media" #:tag:Utilities @@ -220,7 +220,7 @@ def get_logo_directory(): Returns: str: A string pointing to the logo directory """ - return sys.path[0] + "/media/logo" + return get_current_script_directory() + "/media/logo" #:tag:Utilities From c0d06c50eac6ba19808ab59400ebb6cc19756897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 31 Jan 2023 14:35:38 +0300 Subject: [PATCH 113/487] quit state_observe_thread peacefully --- libpince/GDB_Engine.py | 51 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 28a9777e..f3b41503 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -300,31 +300,34 @@ def check_inferior_status(cache=None): global child global gdb_output stored_output = "" - while True: - child.expect_exact("\r\n") # A new line for TTY devices - child.before = child.before.strip() - if not child.before: - continue - stored_output += "\n" + child.before - if child.before == "(gdb)": - check_inferior_status(stored_output) - stored_output = "" - continue - command_file = re.escape(SysUtils.get_gdb_command_file(currentpid)) - if common_regexes.gdb_command_source(command_file).search(child.before): - child.expect_exact("(gdb)") + try: + while True: + child.expect_exact("\r\n") # A new line for TTY devices child.before = child.before.strip() - check_inferior_status() - gdb_output = child.before - stored_output = "" - with gdb_waiting_for_prompt_condition: - gdb_waiting_for_prompt_condition.notify_all() - if gdb_output_mode.command_output: - print(child.before) - else: - if gdb_output_mode.async_output: - print(child.before) - gdb_async_output.broadcast_message(child.before) + if not child.before: + continue + stored_output += "\n" + child.before + if child.before == "(gdb)": + check_inferior_status(stored_output) + stored_output = "" + continue + command_file = re.escape(SysUtils.get_gdb_command_file(currentpid)) + if common_regexes.gdb_command_source(command_file).search(child.before): + child.expect_exact("(gdb)") + child.before = child.before.strip() + check_inferior_status() + gdb_output = child.before + stored_output = "" + with gdb_waiting_for_prompt_condition: + gdb_waiting_for_prompt_condition.notify_all() + if gdb_output_mode.command_output: + print(child.before) + else: + if gdb_output_mode.async_output: + print(child.before) + gdb_async_output.broadcast_message(child.before) + except OSError: + pass def execute_with_temporary_interruption(func): From 547881991ac817bd08707b08617cdaa96ee943ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 31 Jan 2023 15:02:20 +0300 Subject: [PATCH 114/487] add exit message --- libpince/GDB_Engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index f3b41503..6382ec97 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -327,7 +327,7 @@ def check_inferior_status(cache=None): print(child.before) gdb_async_output.broadcast_message(child.before) except OSError: - pass + print("Exiting state_observe_thread") def execute_with_temporary_interruption(func): From 4a3e467a9ba550e56dd3e114c9d4bb17002e7998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 1 Feb 2023 16:18:42 +0300 Subject: [PATCH 115/487] Fix GTK version mismatch issues --- PINCE.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/PINCE.py b/PINCE.py index 9b337405..b2138b67 100755 --- a/PINCE.py +++ b/PINCE.py @@ -18,6 +18,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +import gi + +# This fixes GTK version mismatch issues and crashes on gnome +# See #153 and #159 for more information +# This line can be deleted when GTK 4.0 properly runs on all supported systems +gi.require_version('Gtk', '3.0') + from typing import Final from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ From 98f0cf85602d4f92ca4f31dd00b37db56e8d338a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 2 Feb 2023 22:56:55 +0300 Subject: [PATCH 116/487] Remove toggle_attach dialog --- GUI/SettingsDialog.py | 7 +------ GUI/SettingsDialog.ui | 10 ---------- PINCE.py | 22 +++++----------------- 3 files changed, 6 insertions(+), 33 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 46065b61..63503f24 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SettingsDialog.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -110,10 +110,6 @@ def setupUi(self, Dialog): self.checkBox_MessageBoxOnException.setChecked(True) self.checkBox_MessageBoxOnException.setObjectName("checkBox_MessageBoxOnException") self.verticalLayout_5.addWidget(self.checkBox_MessageBoxOnException) - self.checkBox_MessageBoxOnToggleAttach = QtWidgets.QCheckBox(self.page) - self.checkBox_MessageBoxOnToggleAttach.setChecked(True) - self.checkBox_MessageBoxOnToggleAttach.setObjectName("checkBox_MessageBoxOnToggleAttach") - self.verticalLayout_5.addWidget(self.checkBox_MessageBoxOnToggleAttach) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.label_8 = QtWidgets.QLabel(self.page) @@ -348,7 +344,6 @@ def retranslateUi(self, Dialog): self.lineEdit_FreezeInterval.setText(_translate("Dialog", "100")) self.label_10.setText(_translate("Dialog", "ms")) self.checkBox_MessageBoxOnException.setText(_translate("Dialog", "Show a MessageBox on InferiorRunning and GDBInitialize exceptions")) - self.checkBox_MessageBoxOnToggleAttach.setText(_translate("Dialog", "Show a MessageBox on Toggle Attach")) self.label_8.setText(_translate("Dialog", "GDB output:")) self.checkBox_OutputModeAsync.setText(_translate("Dialog", "Async")) self.checkBox_OutputModeCommand.setText(_translate("Dialog", "Command")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 775b5e69..1fa6f4cf 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -215,16 +215,6 @@ - - - - Show a MessageBox on Toggle Attach - - - true - - - diff --git a/PINCE.py b/PINCE.py index b2138b67..777624d6 100755 --- a/PINCE.py +++ b/PINCE.py @@ -92,7 +92,6 @@ table_update_interval = int FreezeInterval = int show_messagebox_on_exception = bool -show_messagebox_on_toggle_attach = bool gdb_output_mode = tuple auto_attach_list = str auto_attach_regex = bool @@ -513,7 +512,6 @@ def set_default_settings(self): self.settings.setValue("address_table_update_interval", 500) self.settings.setValue("freeze_interval", 100) self.settings.setValue("show_messagebox_on_exception", True) - self.settings.setValue("show_messagebox_on_toggle_attach", True) self.settings.setValue("gdb_output_mode", type_defs.gdb_output_mode(True, True, True)) self.settings.setValue("auto_attach_list", "") self.settings.setValue("logo_path", "ozgurozbek/pince_small_transparent.png") @@ -558,7 +556,6 @@ def apply_settings(self): global update_table global table_update_interval global show_messagebox_on_exception - global show_messagebox_on_toggle_attach global gdb_output_mode global auto_attach_list global logo_path @@ -573,7 +570,6 @@ def apply_settings(self): table_update_interval = self.settings.value("General/address_table_update_interval", type=int) FreezeInterval = self.settings.value("General/freeze_interval", type=int) show_messagebox_on_exception = self.settings.value("General/show_messagebox_on_exception", type=bool) - show_messagebox_on_toggle_attach = self.settings.value("General/show_messagebox_on_toggle_attach", type=bool) gdb_output_mode = self.settings.value("General/gdb_output_mode", type=tuple) auto_attach_list = self.settings.value("General/auto_attach_list", type=str) logo_path = self.settings.value("General/logo_path", type=str) @@ -625,6 +621,8 @@ def auto_attach(self): # Keyboard package has an issue with exceptions, any trigger function that throws an exception stops the event loop # Writing a custom event loop instead of ignoring exceptions could work as well but honestly, this looks cleaner + # Keyboard package does not play well with Qt, do not use anything Qt related with hotkeys + # Using any Qt functionality with the hotkeys will freeze the process or just crash it @SysUtils.ignore_exceptions def pause_hotkey_pressed(self): GDB_Engine.interrupt_inferior(type_defs.STOP_REASON.PAUSE) @@ -639,19 +637,13 @@ def continue_hotkey_pressed(self): @SysUtils.ignore_exceptions def toggle_attach_hotkey_pressed(self): + if GDB_Engine.inferior_status==type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + GDB_Engine.interrupt_inferior(type_defs.STOP_REASON.PAUSE) result = GDB_Engine.toggle_attach() if not result: - dialog_text = "Unable to toggle attach" + print("Unable to toggle attach") elif result == type_defs.TOGGLE_ATTACH.DETACHED: self.on_status_detached() - dialog_text = "GDB is detached from the process" - else: - dialog_text = "GDB is attached back to the process" - if show_messagebox_on_toggle_attach: - dialog = InputDialogForm(item_list=[( - dialog_text + "\n\nGo to Settings->General to disable this dialog",)], - buttons=[QDialogButtonBox.StandardButton.Ok]) - dialog.exec() def treeWidget_AddressTable_context_menu_event(self, event): if self.treeWidget_AddressTable.topLevelItemCount() == 0: @@ -2139,8 +2131,6 @@ def accept(self): self.settings.setValue("General/address_table_update_interval", current_table_update_interval) self.settings.setValue("General/freeze_interval", freezeinterval) self.settings.setValue("General/show_messagebox_on_exception", self.checkBox_MessageBoxOnException.isChecked()) - self.settings.setValue("General/show_messagebox_on_toggle_attach", - self.checkBox_MessageBoxOnToggleAttach.isChecked()) current_gdb_output_mode = type_defs.gdb_output_mode(self.checkBox_OutputModeAsync.isChecked(), self.checkBox_OutputModeCommand.isChecked(), self.checkBox_OutputModeCommandInfo.isChecked()) @@ -2184,8 +2174,6 @@ def config_gui(self): str(self.settings.value("General/freeze_interval", type=int))) self.checkBox_MessageBoxOnException.setChecked( self.settings.value("General/show_messagebox_on_exception", type=bool)) - self.checkBox_MessageBoxOnToggleAttach.setChecked( - self.settings.value("General/show_messagebox_on_toggle_attach", type=bool)) self.checkBox_OutputModeAsync.setChecked(self.settings.value("General/gdb_output_mode").async_output) self.checkBox_OutputModeCommand.setChecked(self.settings.value("General/gdb_output_mode").command_output) self.checkBox_OutputModeCommandInfo.setChecked(self.settings.value("General/gdb_output_mode").command_info) From a59de9835d49c3d47d3a009a513c0ccbd92974fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 4 Feb 2023 00:18:18 +0300 Subject: [PATCH 117/487] Shorten function names --- PINCE.py | 6 +++--- README.md | 2 +- libpince/GDB_Engine.py | 2 +- libpince/Notes.txt | 2 +- libpince/SysUtils.py | 8 ++++---- run_tests.py | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/PINCE.py b/PINCE.py index 777624d6..78ef4453 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1562,7 +1562,7 @@ def __init__(self, parent=None): # refreshes process list def generate_new_list(self): text = self.lineEdit_SearchProcess.text() - processlist = SysUtils.search_in_processes_by_name(text) + processlist = SysUtils.search_processes(text) self.refresh_process_table(self.tableWidget_ProcessTable, processlist) def keyPressEvent(self, e): @@ -3445,7 +3445,7 @@ def disassemble_check_viewport(self, where, instruction_count): last_visible_row += 1 current_address = SysUtils.extract_address( self.tableWidget_Disassemble.item(current_row, DISAS_ADDR_COL).text()) - new_address = GDB_Engine.find_address_of_closest_instruction(current_address, "previous", last_visible_row) + new_address = GDB_Engine.find_closest_instruction_address(current_address, "previous", last_visible_row) self.disassemble_expression(new_address) elif (where == "previous" and current_row == 0) or (where == "next" and current_row_height > height): self.tableWidget_Disassemble_scroll(where, instruction_count) @@ -3454,7 +3454,7 @@ def tableWidget_Disassemble_scroll(self, where, instruction_count): if GDB_Engine.currentpid == -1: return current_address = self.disassemble_currently_displayed_address - new_address = GDB_Engine.find_address_of_closest_instruction(current_address, where, instruction_count) + new_address = GDB_Engine.find_closest_instruction_address(current_address, where, instruction_count) self.disassemble_expression(new_address) def widget_HexView_wheel_event(self, event): diff --git a/README.md b/README.md index 3cd66900..3e71deb6 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Pre-release screenshots: * Custom scripts instead of using gdb's x command for reading memory **[Done]** * Custom scripts instead of using gdb's set command for modifying memory **[Done]** - **libpince - A reusable python library** - * PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget is automatically generated by looking at the docstrings of the source files. PINCE has a unique parsing technique that allows parsing variables. Check the function get_comments_of_variables in SysUtils for the details. This feature might be replaced with Sphinx in the future + * PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget is automatically generated by looking at the docstrings of the source files. PINCE has a unique parsing technique that allows parsing variables. Check the function get_variable_comments in SysUtils for the details. This feature might be replaced with Sphinx in the future - **Extendable with .so files at runtime** * See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) - **Automatic Trainer Generation:** **[Planned]** diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 6382ec97..becfe28e 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -1013,7 +1013,7 @@ def get_current_thread_information(): #:tag:Assembly -def find_address_of_closest_instruction(address, instruction_location="next", instruction_count=1): +def find_closest_instruction_address(address, instruction_location="next", instruction_count=1): """Finds address of the closest instruction next to the given address, assuming that the given address is valid Args: diff --git a/libpince/Notes.txt b/libpince/Notes.txt index 5b447b7d..89e10255 100644 --- a/libpince/Notes.txt +++ b/libpince/Notes.txt @@ -1,5 +1,5 @@ 2/5/2018 - All docstrings that has "\" character in them should start with "r" to make themselves interpreted as raw strings. Otherwise SysUtils.get_docstrings() won't be able to escape "\" by itself. Check these functions for examples: -SysUtils.get_comments_of_variables() +SysUtils.get_variable_comments() GDB_Engine.create_process() GDB_Engine.attach() GDB_Engine.init_gdb() diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index d06a0286..8bc3bc2f 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -60,7 +60,7 @@ def get_process_information(pid): #:tag:Processes -def search_in_processes_by_name(process_name): +def search_processes(process_name): """Searches currently running processes and returns a list of psutil.Process objects corresponding to processes that has the str process_name in them @@ -815,7 +815,7 @@ def execute_shell_command_as_user(command): def get_docstrings(modules, search_for=""): """Gathers docstrings from a list of modules For now, this function only supports variables and functions - See get_comments_of_variables function to learn documenting variables in PINCE style + See get_variable_comments function to learn documenting variables in PINCE style Args: modules (list): A list of modules @@ -826,7 +826,7 @@ def get_docstrings(modules, search_for=""): Format-->{variable1:docstring1, variable2:docstring2, ...} """ element_dict = {} - variable_comment_dict = get_comments_of_variables(modules) + variable_comment_dict = get_variable_comments(modules) for item in modules: for key, value in item.__dict__.items(): name_with_module = get_module_name(item) + "." + key @@ -841,7 +841,7 @@ def get_docstrings(modules, search_for=""): #:tag:Utilities -def get_comments_of_variables(modules, search_for=""): +def get_variable_comments(modules, search_for=""): r"""Gathers comments from a list of modules Python normally doesn't allow modifying __doc__ variable of the variables This function is designed to bring a solution to this problem diff --git a/run_tests.py b/run_tests.py index b5928680..2214e2ad 100644 --- a/run_tests.py +++ b/run_tests.py @@ -34,7 +34,7 @@ args = parser.parse_args() if args.a: - process_list = SysUtils.search_in_processes_by_name(args.a) + process_list = SysUtils.search_processes(args.a) if not process_list: parser.error("There's no process with the name " + args.a) if len(process_list) > 1: From c85e7b3ab5e0211f9c7d0d7a83f91978c861110a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 4 Feb 2023 00:59:16 +0300 Subject: [PATCH 118/487] Move toggle_attach logic --- PINCE.py | 2 -- libpince/GDB_Engine.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 78ef4453..66e1908f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -637,8 +637,6 @@ def continue_hotkey_pressed(self): @SysUtils.ignore_exceptions def toggle_attach_hotkey_pressed(self): - if GDB_Engine.inferior_status==type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - GDB_Engine.interrupt_inferior(type_defs.STOP_REASON.PAUSE) result = GDB_Engine.toggle_attach() if not result: print("Unable to toggle attach") diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index becfe28e..d5306bfa 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -680,6 +680,8 @@ def toggle_attach(): """ if currentpid == -1: return + if inferior_status==type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + interrupt_inferior(type_defs.STOP_REASON.PAUSE) if is_attached(): if common_regexes.gdb_error.search(send_command("phase-out")): return From 9cc019be3ec81819cb4357e182a1ba346573ff53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 4 Feb 2023 17:31:55 +0200 Subject: [PATCH 119/487] Change PINCE installer script to query users' package managers for unsupported distros --- install_gdb.sh | 0 install_pince.sh | 97 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 75 insertions(+), 22 deletions(-) mode change 100644 => 100755 install_gdb.sh mode change 100644 => 100755 install_pince.sh diff --git a/install_gdb.sh b/install_gdb.sh old mode 100644 new mode 100755 diff --git a/install_pince.sh b/install_pince.sh old mode 100644 new mode 100755 index ce677311..b8dba44e --- a/install_pince.sh +++ b/install_pince.sh @@ -71,22 +71,79 @@ install_scanmem() { return 0 } -OS_NAME="Debian" -PKG_MGR="apt-get" -INSTALL_COMMAND="install" - +ask_pkg_mgr() { + shopt -s nocasematch + echo + echo "Your distro is not officially supported! Trying to install anyway." + echo "Please choose your package manager." + echo "1) APT" + echo "2) Pacman" + echo "3) DNF" + echo "4) Zypper" + echo "5) None of the above" + read -r -p "Choose: " OPTION + + case $OPTION in + 1|*APT*) + OS_NAME="Debian" + ;; + 2|*PACMAN*) + OS_NAME="Arch" + ;; + 3|*DNF*) + OS_NAME="Fedora" + ;; + 4|*ZYPPER*) + OS_NAME="SUSE" + ;; + *) + return 1 + ;; + esac + + return 0 +} PKG_NAMES_ALL="python3-pip gdb libtool intltool" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays -PKG_NAMES="$PKG_NAMES_DEBIAN" PKG_NAMES_PIP="pyqt6 psutil pexpect distorm3 pygdbmi keyboard" PIP_COMMAND="pip3" +INSTALL_COMMAND="install" + +set_install_vars() { + case $1 in + *SUSE*) + PKG_MGR="zypper" + PKG_NAMES="$PKG_NAMES_SUSE" + ;; + *Arch*) + PKG_MGR="pacman" + PKG_NAMES="$PKG_NAMES_ARCH" + INSTALL_COMMAND="-S --needed" + PIP_COMMAND="pip" + ;; + *Fedora*) + PKG_MGR="dnf -y" + PKG_NAMES="$PKG_NAMES_FEDORA" + ;; + *Debian*|*Ubuntu*) + PKG_MGR="apt -y" + PKG_NAMES="$PKG_NAMES_DEBIAN" + ;; + *) + return 1 + ;; + esac + + return 0 +} + LSB_RELEASE="$(command -v lsb_release)" -if [ -n "$LSB_RELEASE" ] ; then +if [ -n "$LSB_RELEASE" ]; then OS_NAME="$(${LSB_RELEASE} -d -s)" else # shellcheck disable=SC1091 @@ -94,22 +151,18 @@ else OS_NAME="$NAME" fi -case "$OS_NAME" in -*SUSE*) - PKG_MGR="zypper" - PKG_NAMES="$PKG_NAMES_SUSE" - ;; -*Arch*) - PKG_MGR="pacman" - PKG_NAMES="$PKG_NAMES_ARCH" - INSTALL_COMMAND="-S" - PIP_COMMAND="pip" - ;; -*Fedora*) - PKG_MGR="dnf -y" - PKG_NAMES="$PKG_NAMES_FEDORA" - ;; -esac +set_install_vars $OS_NAME + +if [ "$?" -ne 0 ]; then + ask_pkg_mgr + if [ "$?" -ne 0 ]; then + echo + echo "Sorry, your distro is not supported!" + exit 1 + fi + + set_install_vars $OS_NAME +fi # shellcheck disable=SC2086 sudo ${PKG_MGR} ${INSTALL_COMMAND} ${PKG_NAMES} || exit_on_error From 5a2d0f310c080f344200e15c6b850b9c158693cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 4 Feb 2023 23:20:34 +0200 Subject: [PATCH 120/487] Change user input uppercasing with a POSIX compliant way --- install_pince.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index b8dba44e..9d27f37a 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -72,7 +72,6 @@ install_scanmem() { } ask_pkg_mgr() { - shopt -s nocasematch echo echo "Your distro is not officially supported! Trying to install anyway." echo "Please choose your package manager." @@ -81,7 +80,9 @@ ask_pkg_mgr() { echo "3) DNF" echo "4) Zypper" echo "5) None of the above" + read -r -p "Choose: " OPTION + OPTION=$(echo $OPTION | tr '[:lower:]' '[:upper:]') case $OPTION in 1|*APT*) From 0a5f6683433278fded422a7ef3fd4c5c675d62c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 6 Feb 2023 00:32:33 +0300 Subject: [PATCH 121/487] Implement TrackSelectorDialog --- GUI/TrackSelectorDialog.py | 39 ++++++++++++++++++++++++++++++++ GUI/TrackSelectorDialog.ui | 46 ++++++++++++++++++++++++++++++++++++++ PINCE.py | 22 ++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 GUI/TrackSelectorDialog.py create mode 100644 GUI/TrackSelectorDialog.ui diff --git a/GUI/TrackSelectorDialog.py b/GUI/TrackSelectorDialog.py new file mode 100644 index 00000000..56e13bc7 --- /dev/null +++ b/GUI/TrackSelectorDialog.py @@ -0,0 +1,39 @@ +# Form implementation generated from reading ui file 'TrackSelectorDialog.ui' +# +# Created by: PyQt6 UI code generator 6.4.0 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(165, 99) + Dialog.setWindowTitle("") + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(Dialog) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.pushButton_Pointer = QtWidgets.QPushButton(Dialog) + self.pushButton_Pointer.setObjectName("pushButton_Pointer") + self.verticalLayout.addWidget(self.pushButton_Pointer) + self.pushButton_Pointed = QtWidgets.QPushButton(Dialog) + self.pushButton_Pointed.setObjectName("pushButton_Pointed") + self.verticalLayout.addWidget(self.pushButton_Pointed) + self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + self.label.setText(_translate("Dialog", "Select an address to track")) + self.pushButton_Pointer.setText(_translate("Dialog", "Pointer")) + self.pushButton_Pointed.setText(_translate("Dialog", "Pointed Address")) diff --git a/GUI/TrackSelectorDialog.ui b/GUI/TrackSelectorDialog.ui new file mode 100644 index 00000000..a0067453 --- /dev/null +++ b/GUI/TrackSelectorDialog.ui @@ -0,0 +1,46 @@ + + + Dialog + + + + 0 + 0 + 165 + 99 + + + + + + + + + + + + Select an address to track + + + + + + + Pointer + + + + + + + Pointed Address + + + + + + + + + + diff --git a/PINCE.py b/PINCE.py index 66e1908f..a43e40ca 100755 --- a/PINCE.py +++ b/PINCE.py @@ -45,6 +45,7 @@ from GUI.SelectProcess import Ui_MainWindow as ProcessWindow from GUI.AddAddressManuallyDialog import Ui_Dialog as ManualAddressDialog from GUI.EditTypeDialog import Ui_Dialog as EditTypeDialog +from GUI.TrackSelectorDialog import Ui_Dialog as TrackSelectorDialog from GUI.LoadingDialog import Ui_Dialog as LoadingDialog from GUI.InputDialog import Ui_Dialog as InputDialog from GUI.TextEditDialog import Ui_Dialog as TextEditDialog @@ -738,6 +739,14 @@ def exec_track_watchpoint_widget(self, watchpoint_type): if not selected_row: return address = selected_row.text(ADDR_COL).strip("P->") # @todo Maybe rework address grabbing logic in the future + address_data = selected_row.data(ADDR_COL, Qt.ItemDataRole.UserRole) + if isinstance(address_data, type_defs.PointerType): + selection_dialog = TrackSelectorDialogForm() + selection_dialog.exec() + if not selection_dialog.selection: + return + if selection_dialog.selection == "pointer": + address = address_data.get_base_address() value_type = selected_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) if type_defs.VALUE_INDEX.is_string(value_type.value_index): value_text = selected_row.text(VALUE_COL) @@ -1920,6 +1929,19 @@ def get_values(self): return address_type, length, zero_terminate +class TrackSelectorDialogForm(QDialog, TrackSelectorDialog): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + self.selection = None + self.pushButton_Pointer.clicked.connect(lambda: self.change_selection("pointer")) + self.pushButton_Pointed.clicked.connect(lambda: self.change_selection("pointed")) + + def change_selection(self, selection): + self.selection = selection + self.close() + + class LoadingDialogForm(QDialog, LoadingDialog): def __init__(self, parent=None): super().__init__(parent=parent) From 9f265b801684ef2a55919516417dff88753ef1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 6 Feb 2023 01:25:33 +0300 Subject: [PATCH 122/487] Remove unused stuff --- GUI/MainWindow.py | 38 +--------------------- GUI/MainWindow.ui | 80 +---------------------------------------------- 2 files changed, 2 insertions(+), 116 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index e4f577e1..dc5df13c 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -249,34 +249,10 @@ def setupUi(self, MainWindow): self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.verticalLayout.setObjectName("verticalLayout") - self.radioButton_RoundedDefault = QtWidgets.QRadioButton(self.widget_2) - self.radioButton_RoundedDefault.setEnabled(False) - self.radioButton_RoundedDefault.setObjectName("radioButton_RoundedDefault") - self.verticalLayout.addWidget(self.radioButton_RoundedDefault) - self.radioButton_RoundedExtreme = QtWidgets.QRadioButton(self.widget_2) - self.radioButton_RoundedExtreme.setEnabled(False) - self.radioButton_RoundedExtreme.setObjectName("radioButton_RoundedExtreme") - self.verticalLayout.addWidget(self.radioButton_RoundedExtreme) - self.radioButton_Truncated = QtWidgets.QRadioButton(self.widget_2) - self.radioButton_Truncated.setEnabled(False) - self.radioButton_Truncated.setObjectName("radioButton_Truncated") - self.verticalLayout.addWidget(self.radioButton_Truncated) - self.checkBox_Unicode = QtWidgets.QCheckBox(self.widget_2) - self.checkBox_Unicode.setEnabled(False) - self.checkBox_Unicode.setObjectName("checkBox_Unicode") - self.verticalLayout.addWidget(self.checkBox_Unicode) - self.checkBox_CaseSensitive = QtWidgets.QCheckBox(self.widget_2) - self.checkBox_CaseSensitive.setEnabled(False) - self.checkBox_CaseSensitive.setObjectName("checkBox_CaseSensitive") - self.verticalLayout.addWidget(self.checkBox_CaseSensitive) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_3.addItem(spacerItem5) - self.checkBox_Unrandomizer = QtWidgets.QCheckBox(self.widget_2) - self.checkBox_Unrandomizer.setEnabled(False) - self.checkBox_Unrandomizer.setObjectName("checkBox_Unrandomizer") - self.verticalLayout_3.addWidget(self.checkBox_Unrandomizer) self.verticalLayout.addLayout(self.verticalLayout_3) self.horizontalLayout_4.addWidget(self.widget_2) self.verticalLayout_5.addLayout(self.horizontalLayout_4) @@ -284,7 +260,7 @@ def setupUi(self, MainWindow): self.gridLayout.addLayout(self.horizontalLayout_9, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 30)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) @@ -330,15 +306,3 @@ def retranslateUi(self, MainWindow): self.label.setText(_translate("MainWindow", "Scan Type:")) self.label_2.setText(_translate("MainWindow", "Value Type:")) self.label_ScanScope.setText(_translate("MainWindow", "Scan Scope:")) - self.radioButton_RoundedDefault.setToolTip(_translate("MainWindow", "Not currently supported")) - self.radioButton_RoundedDefault.setText(_translate("MainWindow", "Ro&unded (Default)")) - self.radioButton_RoundedExtreme.setToolTip(_translate("MainWindow", "Not currently supported")) - self.radioButton_RoundedExtreme.setText(_translate("MainWindow", "Rou&nded (Extreme)")) - self.radioButton_Truncated.setToolTip(_translate("MainWindow", "Not currently supported")) - self.radioButton_Truncated.setText(_translate("MainWindow", "Truncated")) - self.checkBox_Unicode.setToolTip(_translate("MainWindow", "Not currently supported")) - self.checkBox_Unicode.setText(_translate("MainWindow", "Unicode")) - self.checkBox_CaseSensitive.setToolTip(_translate("MainWindow", "Not currently supported")) - self.checkBox_CaseSensitive.setText(_translate("MainWindow", "Case Sensitive")) - self.checkBox_Unrandomizer.setToolTip(_translate("MainWindow", "Not currently supported")) - self.checkBox_Unrandomizer.setText(_translate("MainWindow", "Unrandomizer")) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index e3723d5e..4fd1e376 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -564,71 +564,6 @@ 0 - - - - false - - - Not currently supported - - - Ro&unded (Default) - - - - - - - false - - - Not currently supported - - - Rou&nded (Extreme) - - - - - - - false - - - Not currently supported - - - Truncated - - - - - - - false - - - Not currently supported - - - Unicode - - - - - - - false - - - Not currently supported - - - Case Sensitive - - - @@ -644,19 +579,6 @@ - - - - false - - - Not currently supported - - - Unrandomizer - - - @@ -677,7 +599,7 @@ 0 0 678 - 30 + 22 From 641612a351ff101025d621c49a4a849a3dc68ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 17 Feb 2023 14:32:57 +0300 Subject: [PATCH 123/487] Move screenshots to github image hosting --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3e71deb6..fe08e0e6 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,17 @@ PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB) *Disclaimer: **YOU** are responsible for your actions. PINCE does **NOT** take any responsibility for the damage caused by the users* Pre-release screenshots: -![](media/screenshots/pince.png) -![](media/screenshots/pince1.png) -![](media/screenshots/pince2.png) -![](media/screenshots/pince3.png) -![](media/screenshots/pince4.png) -![](media/screenshots/pince5.png) -![](media/screenshots/pince6.png) -![](media/screenshots/pince7.png) -![](media/screenshots/pince8.png) -![](media/screenshots/pince9.png) +![pince0](https://user-images.githubusercontent.com/5638719/219640001-b99f96a2-bffb-4b61-99a1-b187713897e2.png) +![pince1](https://user-images.githubusercontent.com/5638719/219640254-40152be1-8e97-4d26-a313-62a56b9fe1a5.png) +![pince2](https://user-images.githubusercontent.com/5638719/219640331-ddfc35f8-4bdd-488c-b7e2-a60e0f5c9f5c.png) +![pince3](https://user-images.githubusercontent.com/5638719/219640353-bb733c19-9ce7-4baf-81ce-4306c658fbe6.png) +![pince4](https://user-images.githubusercontent.com/5638719/219640370-a73c1796-8d2b-4d31-a63c-aa0b41f9f608.png) +![pince5](https://user-images.githubusercontent.com/5638719/219640384-62a384c8-cc32-45ef-b975-e310674302c2.png) +![pince6](https://user-images.githubusercontent.com/5638719/219640402-e03768b3-4e88-4c75-9d73-29dfbb69b3c0.png) +![pince7](https://user-images.githubusercontent.com/5638719/219640469-8b496c67-b074-4c9a-9890-9e52227cf75d.png) +![pince8](https://user-images.githubusercontent.com/5638719/219640488-61a8df17-405b-45ae-9b29-f9d214eb8571.png) +![pince9](https://user-images.githubusercontent.com/5638719/219640522-85cac1a9-e425-4b4f-abeb-a61104caa618.png) + # Features - **Memory searching:** PINCE uses [libscanmem](https://github.com/scanmem/scanmem) to search the memory efficiently **[Done]** - **Variable Inspection&Modification** **[Done/Basic]** From f6e0b25fd3ba24bc604331b1d40f8aa4d04518ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 17 Feb 2023 14:57:06 +0300 Subject: [PATCH 124/487] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe08e0e6..867c2342 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - Implement extra MemoryViewerWindow tabs(independent from other steps) - ~~Consider removing the command file layer of IPC system for GDB_Engine.send_command to speed up things~~(independent from other steps)[Update-29/04/2018 : Delaying this until GDB/MI implements a native multiline command feature or improves ```interpreter-exec``` command to cover every single multiline command type(including ```define``` commands)] - Implement thread info widget -- Add ability to change logo and other assets if people contribute more than one asset per usage. Also consider using [PINCE-media](https://github.com/korcankaraokcu/PINCE-media) for development if needed(independent from other steps) +- Add ability to change logo and other assets if people contribute more than one asset per usage - Implement developer mode in settings. Developer mode will include features like dissection of GUI elements on events such as mouse-over(independent from other steps) - Add ability to include non-absolute calls for dissect code feature(i.e call rax). Should be considered after the first version release. Might be useful for multi-breakpoint related features - Implement toggling of arrows for easier navigation for dissected regions(independent from other steps) From 47d1b7634a98ef78f3ad9d94ed5df12784f6db2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 17 Feb 2023 14:59:07 +0300 Subject: [PATCH 125/487] Update Notes.txt --- Notes.txt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Notes.txt b/Notes.txt index 79170a71..14cc66e6 100644 --- a/Notes.txt +++ b/Notes.txt @@ -34,7 +34,7 @@ If you need to pass self as a parameter, please don't use 'super().__init__(pare 28/8/2018 - All QMessageBoxes that's called from outside of their classes(via parent() etc.) must use 'QApplication.focusWidget()' instead of 'self' in their first parameter. Refer to issue #57 for more information -14/11/2018 - All logo requests should be posted in media/logo/your_username. Instead of opening a new issue, PR your logo files to that folder. Your PR must include at least one png file named pince_small, pince_medium or pince_big, according to its size. Optionally, you can also post your design files +14/11/2018 - All logo requests should be posted in media/logo/your_username. Instead of opening a new issue, PR your logo files to that folder. Your PR must include at least one png file named pince_small, pince_medium or pince_big, according to its size So, a minimal PR will look like this: /media/logo/your_username/pince_big.png @@ -45,10 +45,5 @@ A full PR will look like this: /media/logo/your_username/pince_big.png /media/logo/your_username/pince_medium.png /media/logo/your_username/pince_small.png -/media/logo/your_username/pince_big.ai -/media/logo/your_username/pince_medium.ai -/media/logo/your_username/pince_small.ai -It doesn't have to be ai extension, I just picked Adobe Illustrator for the example above - -23/11/2018 - Don't use get_current_item or get_current_row within currentItemChanged or currentChanged signals. Qt doesn't update selected rows on first currentChanged or currentItemChanged calls \ No newline at end of file +23/11/2018 - Don't use get_current_item or get_current_row within currentItemChanged or currentChanged signals. Qt doesn't update selected rows on first currentChanged or currentItemChanged calls From 3505969aad33abc10537f3890e8d06c81d361a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Fri, 17 Feb 2023 14:32:43 +0200 Subject: [PATCH 126/487] Add Python 3 dev headers for APT distros --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index 9d27f37a..ca999242 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -106,7 +106,7 @@ ask_pkg_mgr() { } PKG_NAMES_ALL="python3-pip gdb libtool intltool" -PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev" +PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays From 2081b2e446d2cccf623d4f52fb94ee7a3d0bb6d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 17 Feb 2023 19:14:39 +0300 Subject: [PATCH 127/487] Update screenshots --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 867c2342..e071eecb 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,11 @@ PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB) *Disclaimer: **YOU** are responsible for your actions. PINCE does **NOT** take any responsibility for the damage caused by the users* -Pre-release screenshots: +Pre-release screenshots: + ![pince0](https://user-images.githubusercontent.com/5638719/219640001-b99f96a2-bffb-4b61-99a1-b187713897e2.png) ![pince1](https://user-images.githubusercontent.com/5638719/219640254-40152be1-8e97-4d26-a313-62a56b9fe1a5.png) -![pince2](https://user-images.githubusercontent.com/5638719/219640331-ddfc35f8-4bdd-488c-b7e2-a60e0f5c9f5c.png) +![pince2](https://user-images.githubusercontent.com/5638719/219706426-56c233f5-b047-4a8f-b090-ab439b98ef3a.png) ![pince3](https://user-images.githubusercontent.com/5638719/219640353-bb733c19-9ce7-4baf-81ce-4306c658fbe6.png) ![pince4](https://user-images.githubusercontent.com/5638719/219640370-a73c1796-8d2b-4d31-a63c-aa0b41f9f608.png) ![pince5](https://user-images.githubusercontent.com/5638719/219640384-62a384c8-cc32-45ef-b975-e310674302c2.png) From a09761da87802fd8d3bcbcae6e3b96fe6bfef764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 19 Feb 2023 22:06:07 +0300 Subject: [PATCH 128/487] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e071eecb..41edb544 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ TODO: Include build status with the title when test coverage increases and Travi --> PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB), focused on games. However, it can be used for any reverse-engineering related stuff. PINCE is an abbreviation for "PINCE is not Cheat Engine". PINCE is in development right now, read [Features](#features) part of the project to see what is done and [Roadmap](#current-roadmap) part to see what is currently planned. Also, please read [Wiki Page](https://github.com/korcankaraokcu/PINCE/wiki) of the project to understand how PINCE works. -### [Feel free to join our discord server!](https://discord.gg/KCNDp9m) +### [Feel free to join our discord server!](https://discord.gg/jVt3BzTSpz) *Disclaimer: Do not trust to any source other than [Trusted Sources](#trusted-sources) that claims to have the source code or package for PINCE and remember to report them **immediately*** From 6b454fd09d68051759378a2cbc8340e1b9589d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 23 Feb 2023 06:38:54 +0300 Subject: [PATCH 129/487] Add scan type hotkeys --- PINCE.py | 35 ++++++++++++++++++++++++----------- libpince/type_defs.py | 11 ++++++++++- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/PINCE.py b/PINCE.py index a43e40ca..c4214ee3 100755 --- a/PINCE.py +++ b/PINCE.py @@ -116,6 +116,7 @@ def change_key(self, custom): if self.handle is not None: remove_hotkey(self.handle) self.handle = None + self.custom = custom if custom == '': return self.handle = add_hotkey(custom.lower(), self.func) @@ -126,7 +127,7 @@ def change_func(self, func): remove_hotkey(self.handle) if self.custom != "": self.handle = add_hotkey(self.custom, func) - else: + elif self.default != "": self.handle = add_hotkey(self.default, func) def get_active_key(self): @@ -138,10 +139,17 @@ def get_active_key(self): break_hotkey = Hotkey("break_hotkey", "Break the process", "F2") continue_hotkey = Hotkey("continue_hotkey", "Continue the process", "F3") toggle_attach_hotkey = Hotkey("toggle_attach_hotkey", "Toggle attach/detach", "Shift+F10") + exact_scan_hotkey = Hotkey("exact_scan_hotkey", "Next Scan - Exact", "") + increased_scan_hotkey = Hotkey("increased_scan_hotkey", "Next Scan - Increased", "") + decreased_scan_hotkey = Hotkey("decreased_scan_hotkey", "Next Scan - Decreased", "") + changed_scan_hotkey = Hotkey("changed_scan_hotkey", "Next Scan - Changed", "") + unchanged_scan_hotkey = Hotkey("unchanged_scan_hotkey", "Next Scan - Unchanged", "") @staticmethod def get_hotkeys(): - return Hotkeys.pause_hotkey, Hotkeys.break_hotkey, Hotkeys.continue_hotkey, Hotkeys.toggle_attach_hotkey + return Hotkeys.pause_hotkey, Hotkeys.break_hotkey, Hotkeys.continue_hotkey, Hotkeys.toggle_attach_hotkey, \ + Hotkeys.exact_scan_hotkey, Hotkeys.increased_scan_hotkey, Hotkeys.decreased_scan_hotkey, \ + Hotkeys.changed_scan_hotkey, Hotkeys.unchanged_scan_hotkey code_injection_method = int @@ -384,7 +392,12 @@ def __init__(self): Hotkeys.pause_hotkey: self.pause_hotkey_pressed, Hotkeys.break_hotkey: self.break_hotkey_pressed, Hotkeys.continue_hotkey: self.continue_hotkey_pressed, - Hotkeys.toggle_attach_hotkey: self.toggle_attach_hotkey_pressed + Hotkeys.toggle_attach_hotkey: self.toggle_attach_hotkey_pressed, + Hotkeys.exact_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.EXACT), + Hotkeys.increased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.INCREASED), + Hotkeys.decreased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.DECREASED), + Hotkeys.changed_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.CHANGED), + Hotkeys.unchanged_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.UNCHANGED) } for hotkey, func in hotkey_to_func.items(): hotkey.change_func(func) @@ -644,6 +657,13 @@ def toggle_attach_hotkey_pressed(self): elif result == type_defs.TOGGLE_ATTACH.DETACHED: self.on_status_detached() + @SysUtils.ignore_exceptions + def nextscan_hotkey_pressed(self, index): + if self.scan_mode == type_defs.SCAN_MODE.NEW: + return + self.comboBox_ScanType.setCurrentIndex(index) + self.pushButton_NextScan_clicked() + def treeWidget_AddressTable_context_menu_event(self, event): if self.treeWidget_AddressTable.topLevelItemCount() == 0: return @@ -1055,14 +1075,7 @@ def comboBox_ScanType_current_index_changed(self): def comboBox_ScanType_init(self): current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() - if self.scan_mode == type_defs.SCAN_MODE.NEW: - items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.LESS, type_defs.SCAN_TYPE.MORE, - type_defs.SCAN_TYPE.BETWEEN, type_defs.SCAN_TYPE.UNKNOWN] - else: - items = [type_defs.SCAN_TYPE.EXACT, type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.INCREASED_BY, - type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.DECREASED_BY, type_defs.SCAN_TYPE.LESS, - type_defs.SCAN_TYPE.MORE, type_defs.SCAN_TYPE.BETWEEN, type_defs.SCAN_TYPE.CHANGED, - type_defs.SCAN_TYPE.UNCHANGED] + items = type_defs.SCAN_TYPE.get_list(self.scan_mode) old_index = 0 for index, type_index in enumerate(items): if current_type == type_index: diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 42f5ca6e..d9f1766a 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -291,10 +291,19 @@ class SCAN_TYPE: UNCHANGED = 9 UNKNOWN = 10 + @staticmethod + def get_list(scan_mode): + if scan_mode == SCAN_MODE.NEW: + return [SCAN_TYPE.EXACT, SCAN_TYPE.LESS, SCAN_TYPE.MORE, SCAN_TYPE.BETWEEN, SCAN_TYPE.UNKNOWN] + else: + return [SCAN_TYPE.EXACT, SCAN_TYPE.INCREASED, SCAN_TYPE.INCREASED_BY, SCAN_TYPE.DECREASED, + SCAN_TYPE.DECREASED_BY, SCAN_TYPE.LESS, SCAN_TYPE.MORE, SCAN_TYPE.BETWEEN, + SCAN_TYPE.CHANGED, SCAN_TYPE.UNCHANGED] + # Represents the texts at indexes in combobox scan_type_to_text_dict = collections.OrderedDict([ - (SCAN_TYPE.EXACT, "Exact Scan"), + (SCAN_TYPE.EXACT, "Exact"), (SCAN_TYPE.INCREASED, "Increased"), (SCAN_TYPE.INCREASED_BY, "Increased by"), (SCAN_TYPE.DECREASED, "Decreased"), From 7e95dcd360d56f87b920441ede8163b836245383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 26 Feb 2023 22:44:42 +0300 Subject: [PATCH 130/487] Fix scan hotkey crashes --- PINCE.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index c4214ee3..a4793d0a 100755 --- a/PINCE.py +++ b/PINCE.py @@ -636,7 +636,7 @@ def auto_attach(self): # Keyboard package has an issue with exceptions, any trigger function that throws an exception stops the event loop # Writing a custom event loop instead of ignoring exceptions could work as well but honestly, this looks cleaner # Keyboard package does not play well with Qt, do not use anything Qt related with hotkeys - # Using any Qt functionality with the hotkeys will freeze the process or just crash it + # Instead of using Qt functions, try to use their signals to prevent crashes @SysUtils.ignore_exceptions def pause_hotkey_pressed(self): GDB_Engine.interrupt_inferior(type_defs.STOP_REASON.PAUSE) @@ -662,7 +662,7 @@ def nextscan_hotkey_pressed(self, index): if self.scan_mode == type_defs.SCAN_MODE.NEW: return self.comboBox_ScanType.setCurrentIndex(index) - self.pushButton_NextScan_clicked() + self.pushButton_NextScan.clicked.emit() def treeWidget_AddressTable_context_menu_event(self, event): if self.treeWidget_AddressTable.topLevelItemCount() == 0: From d5da38f0498c78fdce5d60a65f89a1226973c3c4 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Mon, 13 Mar 2023 21:24:03 +0100 Subject: [PATCH 131/487] add pygobject as dependecy fixes "AttributeError: module 'gi' has no attribute 'require_version'" --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index ca999242..70059c99 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -110,7 +110,7 @@ PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays -PKG_NAMES_PIP="pyqt6 psutil pexpect distorm3 pygdbmi keyboard" +PKG_NAMES_PIP="pyqt6 psutil pexpect distorm3 pygdbmi keyboard pygobject" PIP_COMMAND="pip3" INSTALL_COMMAND="install" From c732e61ad4f0c0356a51a217104ac09df896bef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 14 Mar 2023 16:35:17 +0300 Subject: [PATCH 132/487] Add redhat-lsb --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index 70059c99..f318cd7c 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -108,7 +108,7 @@ ask_pkg_mgr() { PKG_NAMES_ALL="python3-pip gdb libtool intltool" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 make" -PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES_PIP="pyqt6 psutil pexpect distorm3 pygdbmi keyboard pygobject" PIP_COMMAND="pip3" From 4a76cd5b3b0dcae72cf3123f020be5366a9bcb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 29 Apr 2023 23:12:34 +0300 Subject: [PATCH 133/487] Change PINCE installation to use Python venv --- .gitignore | 1 + PINCE.sh | 6 ++++++ README.md | 2 +- install_pince.sh | 11 ++++++++--- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 17cce2a7..bec68f53 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ libpince/libscanmem/* *$py.class gdb_pince/* *.gnbs.conf +.venv/* diff --git a/PINCE.sh b/PINCE.sh index c0476b25..601c18b1 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -16,6 +16,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ' +if [ ! -d ".venv/PINCE" ]; then + echo "Please run \"sh install_pince.sh\" first!" + exit 1 +fi + # Change this bullcrap when polkit is implemented OS=$(lsb_release -si) # Get rid of gksudo when Debian 8 support drops or polkit gets implemented @@ -23,5 +28,6 @@ if [ $OS = "Debian" ] && [ -x "$(command -v gksudo)" ]; then gksudo env PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py else # Preserve env vars to keep settings like theme preferences + source .venv/PINCE/bin/activate sudo -E PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py fi diff --git a/README.md b/README.md index 41edb544..1bed48f1 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Pre-release screenshots: ``` git clone --recursive https://github.com/korcankaraokcu/PINCE cd PINCE -sudo sh install_pince.sh +sh install_pince.sh ``` ~~For Archlinux, you can also use the [AUR package](https://aur.archlinux.org/packages/pince-git/) as an alternative~~ Currently outdated, use the installation script diff --git a/install_pince.sh b/install_pince.sh index f318cd7c..66d4b8d8 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -111,7 +111,6 @@ PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk- PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES_PIP="pyqt6 psutil pexpect distorm3 pygdbmi keyboard pygobject" -PIP_COMMAND="pip3" INSTALL_COMMAND="install" @@ -125,7 +124,6 @@ set_install_vars() { PKG_MGR="pacman" PKG_NAMES="$PKG_NAMES_ARCH" INSTALL_COMMAND="-S --needed" - PIP_COMMAND="pip" ;; *Fedora*) PKG_MGR="dnf -y" @@ -167,8 +165,15 @@ fi # shellcheck disable=SC2086 sudo ${PKG_MGR} ${INSTALL_COMMAND} ${PKG_NAMES} || exit_on_error + +# Prepare Python virtual environment +if [ ! -d ".venv/PINCE" ]; then + python3 -m venv .venv/PINCE +fi +source .venv/PINCE/bin/activate + # shellcheck disable=SC2086 -sudo ${PIP_COMMAND} install ${PKG_NAMES_PIP} || exit_on_error +pip3 install ${PKG_NAMES_PIP} || exit_on_error install_scanmem || exit_on_error From 74e56115972eba6efe92d7febb2729c421237cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 29 Apr 2023 23:31:06 +0300 Subject: [PATCH 134/487] Fix Python venv importing for Debian --- PINCE.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.sh b/PINCE.sh index 601c18b1..09a9d914 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -20,6 +20,7 @@ if [ ! -d ".venv/PINCE" ]; then echo "Please run \"sh install_pince.sh\" first!" exit 1 fi +source .venv/PINCE/bin/activate # Change this bullcrap when polkit is implemented OS=$(lsb_release -si) @@ -28,6 +29,5 @@ if [ $OS = "Debian" ] && [ -x "$(command -v gksudo)" ]; then gksudo env PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py else # Preserve env vars to keep settings like theme preferences - source .venv/PINCE/bin/activate sudo -E PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py fi From 5df4cb2628c27e83465736d802711f56dde37e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 30 Apr 2023 01:35:53 +0300 Subject: [PATCH 135/487] Fix GDB losing virtual env variables through pexpect --- libpince/GDB_Engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index d5306bfa..aa8a2cef 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -491,7 +491,7 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): last_gdb_command = "" libpince_dir = SysUtils.get_libpince_directory() - child = pexpect.spawn('sudo LC_NUMERIC=C ' + gdb_path + ' --interpreter=mi', cwd=libpince_dir, + child = pexpect.spawn('sudo LC_NUMERIC=C -E ' + gdb_path + ' --interpreter=mi', cwd=libpince_dir, encoding="utf-8") child.setecho(False) child.delaybeforesend = 0 From 29fedb387c6076a2026963445cddc43e3b887207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Mon, 1 May 2023 00:19:57 +0300 Subject: [PATCH 136/487] Replace source bash built-in with dot --- PINCE.sh | 2 +- install_pince.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.sh b/PINCE.sh index 09a9d914..904ac23c 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -20,7 +20,7 @@ if [ ! -d ".venv/PINCE" ]; then echo "Please run \"sh install_pince.sh\" first!" exit 1 fi -source .venv/PINCE/bin/activate +. .venv/PINCE/bin/activate # Change this bullcrap when polkit is implemented OS=$(lsb_release -si) diff --git a/install_pince.sh b/install_pince.sh index 66d4b8d8..a62bbd90 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -170,7 +170,7 @@ sudo ${PKG_MGR} ${INSTALL_COMMAND} ${PKG_NAMES} || exit_on_error if [ ! -d ".venv/PINCE" ]; then python3 -m venv .venv/PINCE fi -source .venv/PINCE/bin/activate +. .venv/PINCE/bin/activate # shellcheck disable=SC2086 pip3 install ${PKG_NAMES_PIP} || exit_on_error From a5ad5028be86801b846f6453d67b54a4eb18ab34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Mon, 1 May 2023 14:31:29 +0300 Subject: [PATCH 137/487] Debian/Ubuntu venv fixes --- PINCE.sh | 13 ++++--------- install_pince.sh | 2 +- libpince/GDB_Engine.py | 3 ++- libpince/gdbinit_venv | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 libpince/gdbinit_venv diff --git a/PINCE.sh b/PINCE.sh index 904ac23c..36d59e68 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -22,12 +22,7 @@ if [ ! -d ".venv/PINCE" ]; then fi . .venv/PINCE/bin/activate -# Change this bullcrap when polkit is implemented -OS=$(lsb_release -si) -# Get rid of gksudo when Debian 8 support drops or polkit gets implemented -if [ $OS = "Debian" ] && [ -x "$(command -v gksudo)" ]; then - gksudo env PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py -else - # Preserve env vars to keep settings like theme preferences - sudo -E PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py -fi +# Preserve env vars to keep settings like theme preferences. +# Debian/Ubuntu does not preserve PATH through sudo even with -E for security reasons +# so we need to force PATH preservation with venv activated user's PATH. +sudo -E --preserve-env=PATH PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py diff --git a/install_pince.sh b/install_pince.sh index a62bbd90..e6f2183a 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -106,7 +106,7 @@ ask_pkg_mgr() { } PKG_NAMES_ALL="python3-pip gdb libtool intltool" -PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev" +PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config libcairo2-dev libgirepository1.0-dev" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index aa8a2cef..6ba74dcc 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -491,7 +491,7 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): last_gdb_command = "" libpince_dir = SysUtils.get_libpince_directory() - child = pexpect.spawn('sudo LC_NUMERIC=C -E ' + gdb_path + ' --interpreter=mi', cwd=libpince_dir, + child = pexpect.spawn('sudo -E --preserve-env=PATH LC_NUMERIC=C ' + gdb_path + ' --interpreter=mi', cwd=libpince_dir, encoding="utf-8") child.setecho(False) child.delaybeforesend = 0 @@ -502,6 +502,7 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): status_thread.start() gdb_initialized = True set_logging(False) + send_command("source ./gdbinit_venv") send_command("source " + SysUtils.get_user_path(type_defs.USER_PATHS.GDBINIT_PATH)) SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_PATH)) diff --git a/libpince/gdbinit_venv b/libpince/gdbinit_venv new file mode 100644 index 00000000..fb2701f7 --- /dev/null +++ b/libpince/gdbinit_venv @@ -0,0 +1,14 @@ +# Update GDB's Python paths with the `sys.path` values of the local +# Python installation, whether that is brew'ed Python, a virtualenv, +# or another system python. + +# Convert GDB to interpret in Python +python +import os,subprocess,sys + +# Execute a Python using the user's shell and pull out the sys.path (for site-packages) +paths = subprocess.check_output('python -c "import os,sys;print(os.linesep.join(sys.path).strip())"',shell=True).decode("utf-8").split() + +# Extend GDB's Python's search path +sys.path.extend(paths) +end From 88dbb2c2c4aa070fc49b6578e3e62556f0c06706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 2 May 2023 00:07:06 +0300 Subject: [PATCH 138/487] Additional packages for SUSE/Fedora --- install_pince.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index e6f2183a..d47fc33a 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -107,8 +107,8 @@ ask_pkg_mgr() { PKG_NAMES_ALL="python3-pip gdb libtool intltool" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config libcairo2-dev libgirepository1.0-dev" -PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 make" -PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb" +PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES_PIP="pyqt6 psutil pexpect distorm3 pygdbmi keyboard pygobject" From bdebd7ab2ba47bc7ad046b43fac1205365fc583a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Wed, 3 May 2023 00:22:04 +0300 Subject: [PATCH 139/487] Add check for user initiated sudo --- PINCE.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PINCE.sh b/PINCE.sh index 36d59e68..f3f90806 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -16,6 +16,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ' +if [ "$(id -u)" = "0" ]; then + echo "Please do not run this script as root!" + exit 1 +fi + if [ ! -d ".venv/PINCE" ]; then echo "Please run \"sh install_pince.sh\" first!" exit 1 From f6a1e969ae16d6f326f5f458a967743115003648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Wed, 3 May 2023 00:28:54 +0300 Subject: [PATCH 140/487] Add sudo check for install_pince.sh as well --- install_pince.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/install_pince.sh b/install_pince.sh index d47fc33a..63a88b90 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -20,6 +20,10 @@ along with this program. If not, see . # it will create the necessary files in PINCEs directory instead of scanmems, which will result in having to run `sh autogen.sh` # twice, see this link https://github.com/protocolbuffers/protobuf/issues/149#issuecomment-473092810 +if [ "$(id -u)" = "0" ]; then + echo "Please do not run this script as root!" + exit 1 +fi CURRENT_USER="$(who mom likes | awk '{print $1}')" From 353796ceefef2169cfdc9ba80a7fd3bbad97ab6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 5 May 2023 21:58:49 +0300 Subject: [PATCH 141/487] Fix colors --- PINCE.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index a4793d0a..36146f3e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3147,16 +3147,16 @@ def handle_colours(self, row_colour): current_row = row_colour[row] if PC_COLOUR in current_row: if BREAKPOINT_COLOUR in current_row: - colour = Qt.green + colour = QColorConstants.Green elif BOOKMARK_COLOUR in current_row: - colour = Qt.yellow + colour = QColorConstants.Yellow else: colour = PC_COLOUR self.set_row_colour(row, colour) continue if BREAKPOINT_COLOUR in current_row: if BOOKMARK_COLOUR in current_row: - colour = Qt.magenta + colour = QColorConstants.Magenta else: colour = BREAKPOINT_COLOUR self.set_row_colour(row, colour) @@ -3167,12 +3167,11 @@ def handle_colours(self, row_colour): if REF_COLOUR in current_row: self.set_row_colour(row, REF_COLOUR) - # color parameter should be Qt.colour def set_row_colour(self, row, colour): if GDB_Engine.currentpid == -1: return for col in range(self.tableWidget_Disassemble.columnCount()): - self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, QColor(colour)) + self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, colour) def on_process_stop(self): if GDB_Engine.stop_reason == type_defs.STOP_REASON.PAUSE: @@ -4718,7 +4717,7 @@ def apply_data(self, output): address_item = QTableWidgetItem(address) else: address_item = QTableWidgetItem("DEFINED") - address_item.setBackground(Qt.green) + address_item.setBackground(QColorConstants.Green) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_ADDR_COL, address_item) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_SYMBOL_COL, QTableWidgetItem(item[1])) self.tableWidget_SymbolInfo.setSortingEnabled(True) @@ -5126,14 +5125,14 @@ def pushButton_TextUp_clicked(self): def highlight_text(self): self.textBrowser_TypeDefs.selectAll() - self.textBrowser_TypeDefs.setTextBackgroundColor(QColor("white")) + self.textBrowser_TypeDefs.setTextBackgroundColor(QColorConstants.White) cursor = self.textBrowser_TypeDefs.textCursor() cursor.clearSelection() cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_TypeDefs.setTextCursor(cursor) highlight_format = QTextCharFormat() - highlight_format.setBackground(QBrush(QColor("red"))) + highlight_format.setBackground(QColorConstants.LightGray) pattern = self.lineEdit_SearchText.text() found_count = 0 while True: From 013819f86513c4df20e0df9b6b0268f015c97b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 7 May 2023 18:35:12 +0300 Subject: [PATCH 142/487] Fix double click for FunctionsInfoWidget --- PINCE.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PINCE.py b/PINCE.py index 36146f3e..71b4188c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4761,6 +4761,8 @@ def copy_to_clipboard(row, column): def tableWidget_SymbolInfo_item_double_clicked(self, index): address = self.tableWidget_SymbolInfo.item(index.row(), FUNCTIONS_INFO_ADDR_COL).text() + if address == "DEFINED": + return self.parent().disassemble_expression(address, append_to_travel_history=True) def pushButton_Help_clicked(self): From 71ea556a52f0f2057ce0823d90b999481f692d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 8 May 2023 00:33:14 +0300 Subject: [PATCH 143/487] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 1bed48f1..75375112 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,7 @@ If you like to uninstall PINCE, just delete this folder, almost everything is in - Check https://github.com/korcankaraokcu/PINCE/issues/116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` # Running PINCE -Just run ```sh PINCE.sh``` in the PINCE directory -In some cases, ```sudo sh PINCE.sh``` works too, as reported in https://github.com/korcankaraokcu/PINCE/issues/138 +Just run ```sh PINCE.sh``` in the PINCE directory ### For developers: ``` From 5a0cda7bccaf3df7ab9c80c9373f329d6629560e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 May 2023 01:47:05 +0300 Subject: [PATCH 144/487] Fix word wrap --- GUI/MemoryViewerWindow.py | 17 ++++++----------- GUI/MemoryViewerWindow.ui | 16 +++++++++++----- GUI/ReferencedCallsWidget.py | 3 ++- GUI/ReferencedCallsWidget.ui | 7 +++++-- GUI/ReferencedStringsWidget.py | 3 ++- GUI/ReferencedStringsWidget.ui | 7 +++++-- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 4855d97c..e5c026f7 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MemoryViewerWindow.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -11,13 +11,6 @@ class Ui_MainWindow_MemoryView(object): def setupUi(self, MainWindow_MemoryView): - """ - Setup flag(s) to be used by hexview and dissabemly scrolling, so - that while scrolling, new scroll requests are disabled. - """ - self.bHexViewScrolling = False - self.bDisassemblyScrolling = False - MainWindow_MemoryView.setObjectName("MainWindow_MemoryView") MainWindow_MemoryView.resize(800, 600) self.centralwidget = QtWidgets.QWidget(MainWindow_MemoryView) @@ -54,6 +47,7 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_Disassemble.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Disassemble.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Disassemble.setShowGrid(False) + self.tableWidget_Disassemble.setWordWrap(False) self.tableWidget_Disassemble.setObjectName("tableWidget_Disassemble") self.tableWidget_Disassemble.setColumnCount(4) self.tableWidget_Disassemble.setRowCount(0) @@ -86,7 +80,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Registers.setWidgetResizable(True) self.scrollArea_Registers.setObjectName("scrollArea_Registers") self.scrollAreaWidgetContents_Registers = QtWidgets.QWidget() - self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 331, 336)) + self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 336, 342)) self.scrollAreaWidgetContents_Registers.setObjectName("scrollAreaWidgetContents_Registers") self.gridLayout_8 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_Registers) self.gridLayout_8.setContentsMargins(0, 0, 0, 0) @@ -586,7 +580,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Hex.setWidgetResizable(True) self.scrollArea_Hex.setObjectName("scrollArea_Hex") self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() - self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 546, 193)) + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 545, 200)) self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") self.gridLayout_11 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) self.gridLayout_11.setContentsMargins(0, 0, 0, 0) @@ -667,6 +661,7 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_StackTrace.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_StackTrace.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_StackTrace.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_StackTrace.setWordWrap(False) self.tableWidget_StackTrace.setObjectName("tableWidget_StackTrace") self.tableWidget_StackTrace.setColumnCount(2) self.tableWidget_StackTrace.setRowCount(0) @@ -712,7 +707,7 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_5.addWidget(self.splitter_MainMiddle, 0, 0, 1, 1) MainWindow_MemoryView.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow_MemoryView) - self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) self.menubar.setObjectName("menubar") self.menuView = QtWidgets.QMenu(self.menubar) self.menuView.setObjectName("menuView") diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index c3a176fb..32790667 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -99,6 +99,9 @@ false + + false + true @@ -178,8 +181,8 @@ 0 0 - 331 - 336 + 336 + 342 @@ -1262,8 +1265,8 @@ 0 0 - 546 - 193 + 545 + 200 @@ -1442,6 +1445,9 @@ QAbstractItemView::SelectRows + + false + true @@ -1547,7 +1553,7 @@ 0 0 800 - 30 + 22 diff --git a/GUI/ReferencedCallsWidget.py b/GUI/ReferencedCallsWidget.py index 9a5dc757..e71cd008 100644 --- a/GUI/ReferencedCallsWidget.py +++ b/GUI/ReferencedCallsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ReferencedCallsWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -43,6 +43,7 @@ def setupUi(self, Form): self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_References.setWordWrap(False) self.tableWidget_References.setObjectName("tableWidget_References") self.tableWidget_References.setColumnCount(2) self.tableWidget_References.setRowCount(0) diff --git a/GUI/ReferencedCallsWidget.ui b/GUI/ReferencedCallsWidget.ui index dff3de79..d5899ee3 100644 --- a/GUI/ReferencedCallsWidget.ui +++ b/GUI/ReferencedCallsWidget.ui @@ -76,16 +76,19 @@ true + + false + true false - + 16 - + 16 diff --git a/GUI/ReferencedStringsWidget.py b/GUI/ReferencedStringsWidget.py index e451ebfa..e77293c4 100644 --- a/GUI/ReferencedStringsWidget.py +++ b/GUI/ReferencedStringsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ReferencedStringsWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -43,6 +43,7 @@ def setupUi(self, Form): self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_References.setWordWrap(False) self.tableWidget_References.setObjectName("tableWidget_References") self.tableWidget_References.setColumnCount(3) self.tableWidget_References.setRowCount(0) diff --git a/GUI/ReferencedStringsWidget.ui b/GUI/ReferencedStringsWidget.ui index 74554432..4c8e075a 100644 --- a/GUI/ReferencedStringsWidget.ui +++ b/GUI/ReferencedStringsWidget.ui @@ -76,16 +76,19 @@ true + + false + true false - + 16 - + 16 From 69c63221ef24a26b3f75be283c202c18d3947756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 May 2023 17:50:46 +0300 Subject: [PATCH 145/487] Add xcb packages --- install_pince.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index 63a88b90..871b26e9 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -108,9 +108,9 @@ ask_pkg_mgr() { return 0 } - +# About xcb packages -> https://github.com/cdgriffith/FastFlix/wiki/Common-questions-and-problems PKG_NAMES_ALL="python3-pip gdb libtool intltool" -PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config libcairo2-dev libgirepository1.0-dev" +PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays From cfcfbe625118182e54c7dcfd9a7e200272f184fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 May 2023 20:27:09 +0300 Subject: [PATCH 146/487] Bump gdb version to 11.2 --- install_gdb.sh | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/install_gdb.sh b/install_gdb.sh index 8ee358c7..d8b39f0c 100755 --- a/install_gdb.sh +++ b/install_gdb.sh @@ -19,7 +19,7 @@ along with this program. If not, see . # This script installs a specific gdb version locally, the default installation script doesn't need this anymore, you can use it as a fallback if system gdb is being problematic # After installing a local gdb, you must specify its binary location via the Settings->Debug -GDB_VERSION="gdb-10.2" +GDB_VERSION="gdb-11.2" mkdir -p gdb_pince cd gdb_pince || exit @@ -38,22 +38,7 @@ echo "-------------------------------------------------------------------------" echo "If you're not on debian or a similar distro with the 'apt' package manager the follow will not work if you don't have gcc and g++ installed" echo "Please install them manually for this to work, this issue will be addressed at a later date" - # extremely lazy fix for other distros, if gcc&g++ is available it will work, if not it won't -if ! command -v gcc g++; then - # Dependencies required for compiling GDB - sudo apt-get install python3-dev - - if ! sudo apt-get install gcc g++; then - sudo apt-get install software-properties-common - sudo add-apt-repository ppa:ubuntu-toolchain-r/test - sudo apt-get update - - if ! sudo apt-get install gcc g++; then - echo "Failed to install gcc or g++, aborting..." - exit 1 - fi - fi -fi +sudo apt-get install python3-dev libgmp3-dev CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j MAKEINFO=true && sudo make -C gdb install From 7dcbe8392ff1e815445ca01255b320a169de1443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 May 2023 20:58:35 +0300 Subject: [PATCH 147/487] Fix scrolling --- PINCE.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PINCE.py b/PINCE.py index 71b4188c..adce811f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2619,6 +2619,7 @@ def initialize_disassemble_view(self): self.disassemble_currently_displayed_address = "0" self.widget_Disassemble.wheelEvent = self.widget_Disassemble_wheel_event + self.bDisassemblyScrolling = False # rejects new scroll requests while scrolling self.tableWidget_Disassemble.wheelEvent = QEvent.ignore self.verticalScrollBar_Disassemble.wheelEvent = QEvent.ignore @@ -2655,6 +2656,7 @@ def initialize_hex_view(self): self.tableView_HexView_Hex.keyPressEvent = self.widget_HexView_key_press_event self.tableView_HexView_Ascii.keyPressEvent = self.widget_HexView_key_press_event + self.bHexViewScrolling = False # rejects new scroll requests while scrolling self.verticalScrollBar_HexView.wheelEvent = QEvent.ignore self.verticalScrollBar_HexView.sliderChange = self.hex_view_scrollbar_sliderchanged From 529a58d8c62372a50c00f79073b3a999ab391d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 May 2023 22:55:25 +0300 Subject: [PATCH 148/487] Fix AscendingOrder --- PINCE.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index adce811f..10ec53b4 100755 --- a/PINCE.py +++ b/PINCE.py @@ -5605,7 +5605,7 @@ def tableWidget_References_current_changed(self, QModelIndex_current): referrers = str_dict[hex(int(addr, 16))] addrs = [hex(address) for address in referrers] self.listWidget_Referrers.addItems([self.pad_hex(item.all) for item in GDB_Engine.examine_expressions(addrs)]) - self.listWidget_Referrers.sortItems(Qt.AscendingOrder) + self.listWidget_Referrers.sortItems(Qt.SortOrder.AscendingOrder) str_dict.close() def tableWidget_References_item_double_clicked(self, index): @@ -5735,7 +5735,7 @@ def tableWidget_References_current_changed(self, QModelIndex_current): referrers = call_dict[hex(int(SysUtils.extract_address(addr), 16))] addrs = [hex(address) for address in referrers] self.listWidget_Referrers.addItems([self.pad_hex(item.all) for item in GDB_Engine.examine_expressions(addrs)]) - self.listWidget_Referrers.sortItems(Qt.AscendingOrder) + self.listWidget_Referrers.sortItems(Qt.SortOrder.AscendingOrder) call_dict.close() def tableWidget_References_item_double_clicked(self, index): @@ -5808,7 +5808,7 @@ def __init__(self, int_address, parent=None): self.hex_len = 16 if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64 else 8 self.collect_referrer_data() self.refresh_table() - self.listWidget_Referrers.sortItems(Qt.AscendingOrder) + self.listWidget_Referrers.sortItems(Qt.SortOrder.AscendingOrder) self.listWidget_Referrers.selectionModel().currentChanged.connect(self.listWidget_Referrers_current_changed) self.listWidget_Referrers.itemDoubleClicked.connect(self.listWidget_Referrers_item_double_clicked) self.listWidget_Referrers.contextMenuEvent = self.listWidget_Referrers_context_menu_event @@ -5873,7 +5873,7 @@ def refresh_table(self): continue self.listWidget_Referrers.addItem(item) self.listWidget_Referrers.setSortingEnabled(True) - self.listWidget_Referrers.sortItems(Qt.AscendingOrder) + self.listWidget_Referrers.sortItems(Qt.SortOrder.AscendingOrder) def listWidget_Referrers_current_changed(self, QModelIndex_current): if QModelIndex_current.row() < 0: From 6bc822db91f8f4575e3d92fc5543cc274b445f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 May 2023 23:44:39 +0300 Subject: [PATCH 149/487] Fix LoadingDialog freeze issue --- PINCE.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 10ec53b4..c6b56ab5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1995,8 +1995,13 @@ class BackgroundThread(QThread): def __init__(self): super().__init__() + # Unhandled exceptions in this thread freezes PINCE def run(self): - output = self.overrided_func() + try: + output = self.overrided_func() + except: + print(traceback.format_exc()) + output = None self.output_ready.emit(output) def overrided_func(self): @@ -4698,6 +4703,8 @@ def __init__(self, parent=None): self.pushButton_Help.clicked.connect(self.pushButton_Help_clicked) def refresh_table(self): + if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + raise type_defs.InferiorRunningException input_text = self.lineEdit_SearchInput.text() case_sensitive = self.checkBox_CaseSensitive.isChecked() self.loading_dialog = LoadingDialogForm(self) @@ -5255,6 +5262,8 @@ def __init__(self, start="", end="", parent=None): self.tableWidget_Opcodes.contextMenuEvent = self.tableWidget_Opcodes_context_menu_event def refresh_table(self): + if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + raise type_defs.InferiorRunningException start_address = self.lineEdit_Start.text() end_address = self.lineEdit_End.text() regex = self.lineEdit_Regex.text() From eb920f2559c25a89bf8d426caaf21a7a46e70766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Wed, 10 May 2023 18:51:56 +0300 Subject: [PATCH 150/487] Fix freeze and update search table calls after detach --- GUI/MainWindow.py | 83 ++++++++++++++++++++++++----------------------- GUI/MainWindow.ui | 3 ++ PINCE.py | 38 ++++++++++++++-------- 3 files changed, 70 insertions(+), 54 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index dc5df13c..711e0889 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MainWindow.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.5.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -13,11 +13,11 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(678, 636) - self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget = QtWidgets.QWidget(parent=MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.treeWidget_AddressTable = QtWidgets.QTreeWidget(self.centralwidget) + self.treeWidget_AddressTable = QtWidgets.QTreeWidget(parent=self.centralwidget) self.treeWidget_AddressTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.treeWidget_AddressTable.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.DragDrop) self.treeWidget_AddressTable.setDefaultDropAction(QtCore.Qt.DropAction.MoveAction) @@ -29,29 +29,29 @@ def setupUi(self, MainWindow): self.horizontalLayout_8 = QtWidgets.QHBoxLayout() self.horizontalLayout_8.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinAndMaxSize) self.horizontalLayout_8.setObjectName("horizontalLayout_8") - self.pushButton_MemoryView = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_MemoryView = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_MemoryView.setEnabled(False) self.pushButton_MemoryView.setObjectName("pushButton_MemoryView") self.horizontalLayout_8.addWidget(self.pushButton_MemoryView) spacerItem = QtWidgets.QSpacerItem(120, 20, QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem) - self.pushButton_CopyToAddressTable = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_CopyToAddressTable = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_CopyToAddressTable.setText("") self.pushButton_CopyToAddressTable.setObjectName("pushButton_CopyToAddressTable") self.horizontalLayout_8.addWidget(self.pushButton_CopyToAddressTable) - self.pushButton_CleanAddressTable = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_CleanAddressTable = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_CleanAddressTable.setText("") self.pushButton_CleanAddressTable.setObjectName("pushButton_CleanAddressTable") self.horizontalLayout_8.addWidget(self.pushButton_CleanAddressTable) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem1) - self.pushButton_RefreshAdressTable = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_RefreshAdressTable = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_RefreshAdressTable.setText("") self.pushButton_RefreshAdressTable.setObjectName("pushButton_RefreshAdressTable") self.horizontalLayout_8.addWidget(self.pushButton_RefreshAdressTable) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_8.addItem(spacerItem2) - self.pushButton_AddAddressManually = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_AddAddressManually = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_AddAddressManually.setEnabled(False) self.pushButton_AddAddressManually.setObjectName("pushButton_AddAddressManually") self.horizontalLayout_8.addWidget(self.pushButton_AddAddressManually) @@ -59,7 +59,7 @@ def setupUi(self, MainWindow): self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetFixedSize) self.horizontalLayout_5.setObjectName("horizontalLayout_5") - self.pushButton_AttachProcess = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_AttachProcess = QtWidgets.QPushButton(parent=self.centralwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -68,7 +68,7 @@ def setupUi(self, MainWindow): self.pushButton_AttachProcess.setText("") self.pushButton_AttachProcess.setObjectName("pushButton_AttachProcess") self.horizontalLayout_5.addWidget(self.pushButton_AttachProcess) - self.pushButton_Open = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_Open = QtWidgets.QPushButton(parent=self.centralwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -77,7 +77,7 @@ def setupUi(self, MainWindow): self.pushButton_Open.setText("") self.pushButton_Open.setObjectName("pushButton_Open") self.horizontalLayout_5.addWidget(self.pushButton_Open) - self.pushButton_Save = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_Save = QtWidgets.QPushButton(parent=self.centralwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -86,31 +86,31 @@ def setupUi(self, MainWindow): self.pushButton_Save.setText("") self.pushButton_Save.setObjectName("pushButton_Save") self.horizontalLayout_5.addWidget(self.pushButton_Save) - self.pushButton_Wiki = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_Wiki = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_Wiki.setText("") self.pushButton_Wiki.setObjectName("pushButton_Wiki") self.horizontalLayout_5.addWidget(self.pushButton_Wiki) - self.pushButton_About = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_About = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_About.setText("") self.pushButton_About.setObjectName("pushButton_About") self.horizontalLayout_5.addWidget(self.pushButton_About) - self.label_SelectedProcess = QtWidgets.QLabel(self.centralwidget) + self.label_SelectedProcess = QtWidgets.QLabel(parent=self.centralwidget) self.label_SelectedProcess.setObjectName("label_SelectedProcess") self.horizontalLayout_5.addWidget(self.label_SelectedProcess) - self.label_InferiorStatus = QtWidgets.QLabel(self.centralwidget) + self.label_InferiorStatus = QtWidgets.QLabel(parent=self.centralwidget) self.label_InferiorStatus.setText("") self.label_InferiorStatus.setObjectName("label_InferiorStatus") self.horizontalLayout_5.addWidget(self.label_InferiorStatus) - self.progressBar = QtWidgets.QProgressBar(self.centralwidget) + self.progressBar = QtWidgets.QProgressBar(parent=self.centralwidget) self.progressBar.setProperty("value", 0) self.progressBar.setOrientation(QtCore.Qt.Orientation.Horizontal) self.progressBar.setObjectName("progressBar") self.horizontalLayout_5.addWidget(self.progressBar) - self.pushButton_Console = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_Console = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_Console.setText("") self.pushButton_Console.setObjectName("pushButton_Console") self.horizontalLayout_5.addWidget(self.pushButton_Console) - self.pushButton_Settings = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_Settings = QtWidgets.QPushButton(parent=self.centralwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -124,10 +124,10 @@ def setupUi(self, MainWindow): self.horizontalLayout_9.setObjectName("horizontalLayout_9") self.verticalLayout_6 = QtWidgets.QVBoxLayout() self.verticalLayout_6.setObjectName("verticalLayout_6") - self.label_MatchCount = QtWidgets.QLabel(self.centralwidget) + self.label_MatchCount = QtWidgets.QLabel(parent=self.centralwidget) self.label_MatchCount.setObjectName("label_MatchCount") self.verticalLayout_6.addWidget(self.label_MatchCount) - self.tableWidget_valuesearchtable = QtWidgets.QTableWidget(self.centralwidget) + self.tableWidget_valuesearchtable = QtWidgets.QTableWidget(parent=self.centralwidget) self.tableWidget_valuesearchtable.setEnabled(True) self.tableWidget_valuesearchtable.setAutoFillBackground(False) self.tableWidget_valuesearchtable.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) @@ -152,31 +152,31 @@ def setupUi(self, MainWindow): self.tableWidget_valuesearchtable.verticalHeader().setMinimumSectionSize(20) self.verticalLayout_6.addWidget(self.tableWidget_valuesearchtable) self.horizontalLayout_9.addLayout(self.verticalLayout_6) - self.QWidget_Toolbox = QtWidgets.QWidget(self.centralwidget) + self.QWidget_Toolbox = QtWidgets.QWidget(parent=self.centralwidget) self.QWidget_Toolbox.setEnabled(False) self.QWidget_Toolbox.setObjectName("QWidget_Toolbox") self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.QWidget_Toolbox) self.verticalLayout_5.setObjectName("verticalLayout_5") self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") - self.pushButton_NewFirstScan = QtWidgets.QPushButton(self.QWidget_Toolbox) + self.pushButton_NewFirstScan = QtWidgets.QPushButton(parent=self.QWidget_Toolbox) self.pushButton_NewFirstScan.setObjectName("pushButton_NewFirstScan") self.horizontalLayout_6.addWidget(self.pushButton_NewFirstScan) - self.pushButton_NextScan = QtWidgets.QPushButton(self.QWidget_Toolbox) + self.pushButton_NextScan = QtWidgets.QPushButton(parent=self.QWidget_Toolbox) self.pushButton_NextScan.setObjectName("pushButton_NextScan") self.horizontalLayout_6.addWidget(self.pushButton_NextScan) spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_6.addItem(spacerItem3) - self.pushButton_UndoScan = QtWidgets.QPushButton(self.QWidget_Toolbox) + self.pushButton_UndoScan = QtWidgets.QPushButton(parent=self.QWidget_Toolbox) self.pushButton_UndoScan.setObjectName("pushButton_UndoScan") self.horizontalLayout_6.addWidget(self.pushButton_UndoScan) self.verticalLayout_5.addLayout(self.horizontalLayout_6) - self.widget_Scan = QtWidgets.QWidget(self.QWidget_Toolbox) + self.widget_Scan = QtWidgets.QWidget(parent=self.QWidget_Toolbox) self.widget_Scan.setObjectName("widget_Scan") self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.widget_Scan) self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) self.horizontalLayout_7.setObjectName("horizontalLayout_7") - self.widget_3 = QtWidgets.QWidget(self.widget_Scan) + self.widget_3 = QtWidgets.QWidget(parent=self.widget_Scan) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -187,63 +187,64 @@ def setupUi(self, MainWindow): self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(0) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.radioButton_Bits = QtWidgets.QRadioButton(self.widget_3) + self.radioButton_Bits = QtWidgets.QRadioButton(parent=self.widget_3) self.radioButton_Bits.setObjectName("radioButton_Bits") self.verticalLayout_2.addWidget(self.radioButton_Bits) - self.radioButton_Decimal = QtWidgets.QRadioButton(self.widget_3) + self.radioButton_Decimal = QtWidgets.QRadioButton(parent=self.widget_3) + self.radioButton_Decimal.setChecked(True) self.radioButton_Decimal.setObjectName("radioButton_Decimal") self.verticalLayout_2.addWidget(self.radioButton_Decimal) - self.checkBox_Hex = QtWidgets.QCheckBox(self.widget_3) + self.checkBox_Hex = QtWidgets.QCheckBox(parent=self.widget_3) self.checkBox_Hex.setObjectName("checkBox_Hex") self.verticalLayout_2.addWidget(self.checkBox_Hex) self.horizontalLayout_7.addWidget(self.widget_3) - self.lineEdit_Scan = QtWidgets.QLineEdit(self.widget_Scan) + self.lineEdit_Scan = QtWidgets.QLineEdit(parent=self.widget_Scan) self.lineEdit_Scan.setObjectName("lineEdit_Scan") self.horizontalLayout_7.addWidget(self.lineEdit_Scan) - self.label_Between = QtWidgets.QLabel(self.widget_Scan) + self.label_Between = QtWidgets.QLabel(parent=self.widget_Scan) self.label_Between.setObjectName("label_Between") self.horizontalLayout_7.addWidget(self.label_Between) - self.lineEdit_Scan2 = QtWidgets.QLineEdit(self.widget_Scan) + self.lineEdit_Scan2 = QtWidgets.QLineEdit(parent=self.widget_Scan) self.lineEdit_Scan2.setObjectName("lineEdit_Scan2") self.horizontalLayout_7.addWidget(self.lineEdit_Scan2) self.verticalLayout_5.addWidget(self.widget_Scan) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.widget = QtWidgets.QWidget(self.QWidget_Toolbox) + self.widget = QtWidgets.QWidget(parent=self.QWidget_Toolbox) self.widget.setObjectName("widget") self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.widget) self.verticalLayout_4.setObjectName("verticalLayout_4") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.label = QtWidgets.QLabel(self.widget) + self.label = QtWidgets.QLabel(parent=self.widget) self.label.setObjectName("label") self.horizontalLayout_2.addWidget(self.label) - self.comboBox_ScanType = QtWidgets.QComboBox(self.widget) + self.comboBox_ScanType = QtWidgets.QComboBox(parent=self.widget) self.comboBox_ScanType.setObjectName("comboBox_ScanType") self.horizontalLayout_2.addWidget(self.comboBox_ScanType) self.verticalLayout_4.addLayout(self.horizontalLayout_2) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.label_2 = QtWidgets.QLabel(self.widget) + self.label_2 = QtWidgets.QLabel(parent=self.widget) self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) - self.comboBox_ValueType = QtWidgets.QComboBox(self.widget) + self.comboBox_ValueType = QtWidgets.QComboBox(parent=self.widget) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout.addWidget(self.comboBox_ValueType) self.verticalLayout_4.addLayout(self.horizontalLayout) self.horizontalLayout_10 = QtWidgets.QHBoxLayout() self.horizontalLayout_10.setObjectName("horizontalLayout_10") - self.label_ScanScope = QtWidgets.QLabel(self.widget) + self.label_ScanScope = QtWidgets.QLabel(parent=self.widget) self.label_ScanScope.setObjectName("label_ScanScope") self.horizontalLayout_10.addWidget(self.label_ScanScope) - self.comboBox_ScanScope = QtWidgets.QComboBox(self.widget) + self.comboBox_ScanScope = QtWidgets.QComboBox(parent=self.widget) self.comboBox_ScanScope.setObjectName("comboBox_ScanScope") self.horizontalLayout_10.addWidget(self.comboBox_ScanScope) self.verticalLayout_4.addLayout(self.horizontalLayout_10) spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_4.addItem(spacerItem4) self.horizontalLayout_4.addWidget(self.widget) - self.widget_2 = QtWidgets.QWidget(self.QWidget_Toolbox) + self.widget_2 = QtWidgets.QWidget(parent=self.QWidget_Toolbox) self.widget_2.setObjectName("widget_2") self.verticalLayout = QtWidgets.QVBoxLayout(self.widget_2) self.verticalLayout.setContentsMargins(0, 0, 0, 0) @@ -259,7 +260,7 @@ def setupUi(self, MainWindow): self.horizontalLayout_9.addWidget(self.QWidget_Toolbox) self.gridLayout.addLayout(self.horizontalLayout_9, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) - self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar = QtWidgets.QMenuBar(parent=MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 4fd1e376..06f46c82 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -455,6 +455,9 @@ &Decimal + + true + diff --git a/PINCE.py b/PINCE.py index c6b56ab5..35b7e654 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1037,14 +1037,7 @@ def pushButton_NewFirstScan_clicked(self): self.comboBox_ScanType_init() return if self.scan_mode == type_defs.SCAN_MODE.ONGOING: - self.scan_mode = type_defs.SCAN_MODE.NEW - self.pushButton_NewFirstScan.setText("First Scan") - self.backend.send_command("reset") - self.tableWidget_valuesearchtable.setRowCount(0) - self.comboBox_ValueType.setEnabled(True) - self.pushButton_NextScan.setEnabled(False) - self.comboBox_ScanScope.setEnabled(True) - self.progressBar.setValue(0) + self.reset_scan() else: self.scan_mode = type_defs.SCAN_MODE.ONGOING self.pushButton_NewFirstScan.setText("New Scan") @@ -1311,12 +1304,27 @@ def copy_to_address_table(self): if i % 3 == 0: self.add_entry_to_addresstable("", row.text(), row.data(Qt.ItemDataRole.UserRole)[0], length) + def reset_scan(self): + self.scan_mode = type_defs.SCAN_MODE.NEW + self.pushButton_NewFirstScan.setText("First Scan") + self.backend.send_command("reset") + self.tableWidget_valuesearchtable.setRowCount(0) + self.comboBox_ValueType.setEnabled(True) + self.pushButton_NextScan.setEnabled(False) + self.comboBox_ScanScope.setEnabled(True) + self.progressBar.setValue(0) + self.label_MatchCount.setText("Match count: 0") + def on_inferior_exit(self): - if GDB_Engine.currentpid == -1: - self.on_status_running() - GDB_Engine.init_gdb(gdb_path) - self.apply_after_init() - self.label_SelectedProcess.setText("No Process Selected") + self.pushButton_MemoryView.setEnabled(False) + self.pushButton_AddAddressManually.setEnabled(False) + self.QWidget_Toolbox.setEnabled(False) + self.lineEdit_Scan.setText("") + self.reset_scan() + self.on_status_running() + GDB_Engine.init_gdb(gdb_path) + self.apply_after_init() + self.label_SelectedProcess.setText("No Process Selected") def on_status_detached(self): self.label_SelectedProcess.setStyleSheet("color: blue") @@ -1402,6 +1410,8 @@ def freeze_loop(self): # ---------------------------------------------------- def update_search_table(self): + if GDB_Engine.currentpid == -1: + return row_count = self.tableWidget_valuesearchtable.rowCount() if row_count > 0: length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) @@ -1419,6 +1429,8 @@ def update_search_table(self): self.tableWidget_valuesearchtable.setItem(row_index, SEARCH_TABLE_VALUE_COL, value_item) def freeze(self): + if GDB_Engine.currentpid == -1: + return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) while it.value(): row = it.value() From 7afd788588385c43407003413c1d43a75f78c285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 10 May 2023 21:58:10 +0300 Subject: [PATCH 151/487] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 75375112..5d3350a6 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Pre-release screenshots: * **Infinite Scrolling:** PINCE automatically disassembles the next available instruction(s) on mouse wheel/scrollbar move. Instruction count can be changed from settings. Hex View also supports this feature **[Done]** * **Dissect Code:** You can dissect desired memory regions to find referenced calls, jumps and strings. Disassemble screen will automatically handle the referenced data and show you if there's a referenced address in the current dissasemble view. It can be used from Tools->Dissect Code in the MemoryView window. Using its hotkey instead in the MemoryView window automatically dissects the currently viewed region. You can separately view referenced calls and strings after the search from View->Referenced Calls/Strings. *Note: If you decide to uncheck 'Discard invalid strings' before the search, PINCE will try to search for regular pointers as well* **[Done]** * **Bookmarking:** Bookmark menu is dynamically created when right clicked in the disassemble screen. So unlike Cheat Engine, PINCE lets you set unlimited number of bookmarks. List of bookmarks can also be viewed from View->Bookmarks in the MemoryView window. Commenting on an address automatically bookmarks it. **[Done]** - * **Modify on the fly:** PINCE lets you modify registers on the fly. Unlike CE, you can also change XMM and FPU registers. Check [GDB expressions in the Wiki page](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) for additional information **[Done]** + * **Modify on the fly:** PINCE lets you modify registers on the fly. Check [GDB expressions in the Wiki page](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) for additional information **[Done]** * **Opcode Search:** You can search opcodes with python regular expressions. To use this feature, click Tools->Search Opcode in the MemoryView window. **[Done]** - **Debugging** **[Done/Basic]** * Has basic debugging features such as stepping, stepping over, execute till return, break, continue. Also has breakpoints, watchpoints and breakpoint conditions. Has advanced debugging utilities such as Watchpoint/Breakpoint Tracking and Tracing @@ -164,7 +164,7 @@ Gibus # Supported platforms - Ubuntu and its flavors, actively tested on Kubuntu - Debian and Debian-based (Kali, Mint etc.) -- Archlinux(tag [cagriulas](https://github.com/cagriulas) or [TsarFox](https://github.com/TsarFox) when creating an issue) +- Archlinux - SUSE - Fedora From c4f5f424e502affbaff7b3b5e0dbc34b38d5036f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 May 2023 01:59:40 +0300 Subject: [PATCH 152/487] Simplify traceback --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 35b7e654..f013a012 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2012,7 +2012,7 @@ def run(self): try: output = self.overrided_func() except: - print(traceback.format_exc()) + traceback.print_exc() output = None self.output_ready.emit(output) From 179bc1a80cb498c71c45e54b6cfaeadf9bc85e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 May 2023 02:51:49 +0300 Subject: [PATCH 153/487] Fix word wrap --- GUI/BreakpointInfoWidget.py | 3 ++- GUI/BreakpointInfoWidget.ui | 7 +++++-- GUI/DissectCodeDialog.py | 3 ++- GUI/DissectCodeDialog.ui | 7 +++++-- GUI/FloatRegisterWidget.py | 3 ++- GUI/FloatRegisterWidget.ui | 3 +++ GUI/FunctionsInfoWidget.py | 3 ++- GUI/FunctionsInfoWidget.ui | 7 +++++-- GUI/MemoryRegionsWidget.py | 3 ++- GUI/MemoryRegionsWidget.ui | 7 +++++-- GUI/RestoreInstructionsWidget.py | 1 + GUI/RestoreInstructionsWidget.ui | 3 +++ GUI/SearchOpcodeWidget.py | 3 ++- GUI/SearchOpcodeWidget.ui | 7 +++++-- GUI/SelectProcess.py | 3 ++- GUI/SelectProcess.ui | 3 +++ GUI/TrackBreakpointWidget.py | 3 ++- GUI/TrackBreakpointWidget.ui | 7 +++++-- GUI/TrackWatchpointWidget.py | 3 ++- GUI/TrackWatchpointWidget.ui | 7 +++++-- 20 files changed, 63 insertions(+), 23 deletions(-) diff --git a/GUI/BreakpointInfoWidget.py b/GUI/BreakpointInfoWidget.py index cfd7aa59..ab6dd369 100644 --- a/GUI/BreakpointInfoWidget.py +++ b/GUI/BreakpointInfoWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'BreakpointInfoWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -21,6 +21,7 @@ def setupUi(self, TabWidget): self.tableWidget_BreakpointInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_BreakpointInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_BreakpointInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_BreakpointInfo.setWordWrap(False) self.tableWidget_BreakpointInfo.setObjectName("tableWidget_BreakpointInfo") self.tableWidget_BreakpointInfo.setColumnCount(9) self.tableWidget_BreakpointInfo.setRowCount(0) diff --git a/GUI/BreakpointInfoWidget.ui b/GUI/BreakpointInfoWidget.ui index 21109d8c..d2e24cc6 100644 --- a/GUI/BreakpointInfoWidget.ui +++ b/GUI/BreakpointInfoWidget.ui @@ -32,16 +32,19 @@ QAbstractItemView::SelectRows + + false + true false - + 16 - + 16 diff --git a/GUI/DissectCodeDialog.py b/GUI/DissectCodeDialog.py index ab2e6a0f..85dd3922 100644 --- a/GUI/DissectCodeDialog.py +++ b/GUI/DissectCodeDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'DissectCodeDialog.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -21,6 +21,7 @@ def setupUi(self, Dialog): self.tableWidget_ExecutableMemoryRegions = QtWidgets.QTableWidget(self.splitter) self.tableWidget_ExecutableMemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_ExecutableMemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_ExecutableMemoryRegions.setWordWrap(False) self.tableWidget_ExecutableMemoryRegions.setObjectName("tableWidget_ExecutableMemoryRegions") self.tableWidget_ExecutableMemoryRegions.setColumnCount(2) self.tableWidget_ExecutableMemoryRegions.setRowCount(0) diff --git a/GUI/DissectCodeDialog.ui b/GUI/DissectCodeDialog.ui index 948db664..e68e14db 100644 --- a/GUI/DissectCodeDialog.ui +++ b/GUI/DissectCodeDialog.ui @@ -26,16 +26,19 @@ QAbstractItemView::SelectRows + + false + true false - + 16 - + 16 diff --git a/GUI/FloatRegisterWidget.py b/GUI/FloatRegisterWidget.py index 73798d37..3b5c8510 100644 --- a/GUI/FloatRegisterWidget.py +++ b/GUI/FloatRegisterWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'FloatRegisterWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -21,6 +21,7 @@ def setupUi(self, TabWidget): self.tableWidget_FPU.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_FPU.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_FPU.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_FPU.setWordWrap(False) self.tableWidget_FPU.setObjectName("tableWidget_FPU") self.tableWidget_FPU.setColumnCount(2) self.tableWidget_FPU.setRowCount(0) diff --git a/GUI/FloatRegisterWidget.ui b/GUI/FloatRegisterWidget.ui index 3bd78037..f67723d0 100644 --- a/GUI/FloatRegisterWidget.ui +++ b/GUI/FloatRegisterWidget.ui @@ -32,6 +32,9 @@ QAbstractItemView::SelectRows + + false + true diff --git a/GUI/FunctionsInfoWidget.py b/GUI/FunctionsInfoWidget.py index cab5405f..32784d45 100644 --- a/GUI/FunctionsInfoWidget.py +++ b/GUI/FunctionsInfoWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'FunctionsInfoWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -19,6 +19,7 @@ def setupUi(self, Form): self.tableWidget_SymbolInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_SymbolInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_SymbolInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_SymbolInfo.setWordWrap(False) self.tableWidget_SymbolInfo.setObjectName("tableWidget_SymbolInfo") self.tableWidget_SymbolInfo.setColumnCount(2) self.tableWidget_SymbolInfo.setRowCount(0) diff --git a/GUI/FunctionsInfoWidget.ui b/GUI/FunctionsInfoWidget.ui index b295e1a7..0906e9ba 100644 --- a/GUI/FunctionsInfoWidget.ui +++ b/GUI/FunctionsInfoWidget.ui @@ -28,16 +28,19 @@ true + + false + true false - + 20 - + 20 diff --git a/GUI/MemoryRegionsWidget.py b/GUI/MemoryRegionsWidget.py index 2b36c88c..d4b3e741 100644 --- a/GUI/MemoryRegionsWidget.py +++ b/GUI/MemoryRegionsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MemoryRegionsWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -19,6 +19,7 @@ def setupUi(self, Form): self.tableWidget_MemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_MemoryRegions.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_MemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_MemoryRegions.setWordWrap(False) self.tableWidget_MemoryRegions.setObjectName("tableWidget_MemoryRegions") self.tableWidget_MemoryRegions.setColumnCount(13) self.tableWidget_MemoryRegions.setRowCount(0) diff --git a/GUI/MemoryRegionsWidget.ui b/GUI/MemoryRegionsWidget.ui index 3fac6ba9..ee637d0f 100644 --- a/GUI/MemoryRegionsWidget.ui +++ b/GUI/MemoryRegionsWidget.ui @@ -28,16 +28,19 @@ true + + false + true false - + 16 - + 16 diff --git a/GUI/RestoreInstructionsWidget.py b/GUI/RestoreInstructionsWidget.py index 91d0e393..82533bef 100644 --- a/GUI/RestoreInstructionsWidget.py +++ b/GUI/RestoreInstructionsWidget.py @@ -19,6 +19,7 @@ def setupUi(self, Form): self.tableWidget_Instructions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Instructions.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Instructions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_Instructions.setWordWrap(False) self.tableWidget_Instructions.setObjectName("tableWidget_Instructions") self.tableWidget_Instructions.setColumnCount(3) self.tableWidget_Instructions.setRowCount(0) diff --git a/GUI/RestoreInstructionsWidget.ui b/GUI/RestoreInstructionsWidget.ui index 89db2a37..1a12c0af 100644 --- a/GUI/RestoreInstructionsWidget.ui +++ b/GUI/RestoreInstructionsWidget.ui @@ -28,6 +28,9 @@ true + + false + true diff --git a/GUI/SearchOpcodeWidget.py b/GUI/SearchOpcodeWidget.py index a72b0391..45761c4e 100644 --- a/GUI/SearchOpcodeWidget.py +++ b/GUI/SearchOpcodeWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SearchOpcodeWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -56,6 +56,7 @@ def setupUi(self, Form): self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_Opcodes.setWordWrap(False) self.tableWidget_Opcodes.setObjectName("tableWidget_Opcodes") self.tableWidget_Opcodes.setColumnCount(2) self.tableWidget_Opcodes.setRowCount(0) diff --git a/GUI/SearchOpcodeWidget.ui b/GUI/SearchOpcodeWidget.ui index cf12d575..0e08c267 100644 --- a/GUI/SearchOpcodeWidget.ui +++ b/GUI/SearchOpcodeWidget.ui @@ -104,16 +104,19 @@ true + + false + true false - + 16 - + 16 diff --git a/GUI/SelectProcess.py b/GUI/SelectProcess.py index 739b9128..72cdda9b 100644 --- a/GUI/SelectProcess.py +++ b/GUI/SelectProcess.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SelectProcess.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -38,6 +38,7 @@ def setupUi(self, MainWindow): self.tableWidget_ProcessTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_ProcessTable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_ProcessTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_ProcessTable.setWordWrap(False) self.tableWidget_ProcessTable.setObjectName("tableWidget_ProcessTable") self.tableWidget_ProcessTable.setColumnCount(3) self.tableWidget_ProcessTable.setRowCount(0) diff --git a/GUI/SelectProcess.ui b/GUI/SelectProcess.ui index 37573700..65bb5ce2 100644 --- a/GUI/SelectProcess.ui +++ b/GUI/SelectProcess.ui @@ -58,6 +58,9 @@ true + + false + 70 diff --git a/GUI/TrackBreakpointWidget.py b/GUI/TrackBreakpointWidget.py index f4204b86..415b6fc2 100644 --- a/GUI/TrackBreakpointWidget.py +++ b/GUI/TrackBreakpointWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TrackBreakpointWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -32,6 +32,7 @@ def setupUi(self, Form): self.tableWidget_TrackInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_TrackInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_TrackInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_TrackInfo.setWordWrap(False) self.tableWidget_TrackInfo.setObjectName("tableWidget_TrackInfo") self.tableWidget_TrackInfo.setColumnCount(4) self.tableWidget_TrackInfo.setRowCount(0) diff --git a/GUI/TrackBreakpointWidget.ui b/GUI/TrackBreakpointWidget.ui index 17401600..f5c5339f 100644 --- a/GUI/TrackBreakpointWidget.ui +++ b/GUI/TrackBreakpointWidget.ui @@ -62,16 +62,19 @@ QAbstractItemView::SelectRows + + false + true false - + 16 - + 16 diff --git a/GUI/TrackWatchpointWidget.py b/GUI/TrackWatchpointWidget.py index 08de4097..abec21cd 100644 --- a/GUI/TrackWatchpointWidget.py +++ b/GUI/TrackWatchpointWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TrackWatchpointWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -30,6 +30,7 @@ def setupUi(self, Form): self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_Opcodes.setWordWrap(False) self.tableWidget_Opcodes.setObjectName("tableWidget_Opcodes") self.tableWidget_Opcodes.setColumnCount(2) self.tableWidget_Opcodes.setRowCount(0) diff --git a/GUI/TrackWatchpointWidget.ui b/GUI/TrackWatchpointWidget.ui index 49e8ad96..08caa114 100644 --- a/GUI/TrackWatchpointWidget.ui +++ b/GUI/TrackWatchpointWidget.ui @@ -36,16 +36,19 @@ QAbstractItemView::SelectRows + + false + true false - + 16 - + 16 From 2d47b2fea21bb7d386b8cf995f9803671af7a91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 May 2023 19:19:35 +0300 Subject: [PATCH 154/487] Fix HexView --- GUI/CustomTableViews/HexView.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/GUI/CustomTableViews/HexView.py b/GUI/CustomTableViews/HexView.py index f1bce271..1eb926c1 100644 --- a/GUI/CustomTableViews/HexView.py +++ b/GUI/CustomTableViews/HexView.py @@ -37,15 +37,9 @@ def wheelEvent(self, QWheelEvent): QWheelEvent.ignore() def resize_to_contents(self): - _self_name=self.__class__.__name__ size = self.columnWidth(0) * self.model().columnCount() - if (_self_name == "QHexView"): - self.setMinimumWidth(int(size*1.875)) - self.setMaximumWidth(int(size*1.875)) - self.resizeColumnsToContents() - else: - self.setMinimumWidth(int(size)) - self.setMaximumWidth(int(size)) + self.setMinimumWidth(size) + self.setMaximumWidth(size) def get_selected_address(self): ci = self.currentIndex() From 8c615bc433d746c5f00772c2878ee34ba1ab352e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 May 2023 21:00:03 +0300 Subject: [PATCH 155/487] Fix AsciiModel --- GUI/CustomAbstractTableModels/AsciiModel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GUI/CustomAbstractTableModels/AsciiModel.py b/GUI/CustomAbstractTableModels/AsciiModel.py index 36964772..820e2176 100644 --- a/GUI/CustomAbstractTableModels/AsciiModel.py +++ b/GUI/CustomAbstractTableModels/AsciiModel.py @@ -15,7 +15,7 @@ along with this program. If not, see . """ from PyQt6.QtCore import QVariant, Qt -from PyQt6.QtGui import QColor +from PyQt6.QtGui import QColorConstants from GUI.CustomAbstractTableModels.HexModel import QHexModel from libpince import SysUtils, GDB_Engine @@ -26,11 +26,11 @@ def __init__(self, row_count, column_count, parent=None): super().__init__(row_count, column_count, parent) def data(self, QModelIndex, int_role=None): - if (not self.data_array is None and len(self.data_array) > 0 and QModelIndex.isValid()): + if self.data_array and QModelIndex.isValid(): if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: - return QVariant(QColor.red) + return QVariant(QColorConstants.Red) elif int_role == Qt.ItemDataRole.DisplayRole: return QVariant(SysUtils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()])) return QVariant() From f5d0f8da6321890e0836a06f1edfd68e5f15d9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 13 May 2023 15:10:01 +0300 Subject: [PATCH 156/487] examine_expression now reads memory regions as well --- libpince/SysUtils.py | 29 +++++++++++++++++++ libpince/common_regexes.py | 1 + .../GDBCommandExtensions.py | 4 ++- libpince/gdb_python_scripts/ScriptUtils.py | 7 ++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 8bc3bc2f..82c7a991 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -20,6 +20,8 @@ # This makes any psutil based function that's called from GDB unusable for Archlinux # Currently there's none but we can't take it for granted, can we? # TODO: Research the reason behind it or at least find a workaround +# TODO: psutil is a bit slow for what it is, replace if this slight overhead becomes a problem +# It takes about 30ms for get_region_set to run, a bit too slow innit, not really critical but slow indeed try: import psutil except ImportError: @@ -98,6 +100,33 @@ def get_memory_regions(pid): return psutil.Process(pid).memory_maps(grouped=False) +# :tag:Processes +def get_region_set(pid): + """Returns memory regions as a list. Removes path duplicates and empty paths + + Args: + pid (int): PID of the process + + Returns: + list: List of str lists -> [[addr1, file_name1], [addr2, file_name2], ...] + + Note: + grouped=True could be used for this functionality but we might also get rid of psutil in the future due to + performance issues + """ + region_set = [] + current_file = "" + for item in get_memory_regions(pid): + if not item.path: + continue + head, tail = os.path.split(item.path) + if not head or tail == current_file: + continue + current_file = tail + region_set.append(["0x"+item.addr.split("-")[0], tail]) + return region_set + + #:tag:Processes def get_region_info(pid, address): """Finds the closest valid starting/ending address and region to given address, assuming given address is in the diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index 4695e263..b0acd4f0 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -63,3 +63,4 @@ trace_instructions_call = compile(r":\s+call") # 0x7f71a4dc5fe4 : call 0x7f71a4de1100 dissect_code_valid_address = compile(r"(\s+|\[|,)" + hex_number.pattern + "(\s+|\]|,|$)") alphanumerics = compile(r"\w+") +file_with_extension = compile(r".+\.\w+") diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 2e34c3de..0c714417 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -577,8 +577,10 @@ def invoke(self, arg, from_tty): data_read_list = [] contents_recv = receive_from_pince() # contents_recv format: [expression1, expression2, ...] + + regions = SysUtils.get_region_set(pid) for expression in contents_recv: - result_tuple = ScriptUtils.examine_expression(expression) + result_tuple = ScriptUtils.examine_expression(expression, regions) data_read_list.append(result_tuple) send_to_pince(data_read_list) diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/ScriptUtils.py index 762a52f8..fbe7aab9 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/ScriptUtils.py @@ -113,10 +113,15 @@ def get_float_registers(): return contents_send -def examine_expression(expression): +def examine_expression(expression, regions=None): try: value = gdb.parse_and_eval(expression).cast(void_ptr) except Exception as e: + if regions and common_regexes.file_with_extension.search(expression): + for region in regions: + address, file_name = region + if expression in file_name: + return type_defs.tuple_examine_expression(address+" "+file_name, address, file_name) print(e, "for expression " + expression) return type_defs.tuple_examine_expression(None, None, None) result = common_regexes.address_with_symbol.search(str(value)) From 662e9ec99c17eca5d3dca4edc261fa30c7c7d163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 13 May 2023 15:41:03 +0300 Subject: [PATCH 157/487] Hotfix for examine_expression --- libpince/gdb_python_scripts/ScriptUtils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/ScriptUtils.py index fbe7aab9..7fb555f9 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/ScriptUtils.py @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import gdb, sys, traceback, functools +import gdb, sys, os, traceback, functools from collections import OrderedDict # This is some retarded hack @@ -27,6 +27,7 @@ inferior = gdb.selected_inferior() pid = inferior.pid +inferior_name = os.path.split(inferior.progspace.filename)[1] mem_file = "/proc/" + str(pid) + "/mem" void_ptr = gdb.lookup_type("void").pointer() @@ -117,7 +118,7 @@ def examine_expression(expression, regions=None): try: value = gdb.parse_and_eval(expression).cast(void_ptr) except Exception as e: - if regions and common_regexes.file_with_extension.search(expression): + if regions and (expression == inferior_name or common_regexes.file_with_extension.search(expression)): for region in regions: address, file_name = region if expression in file_name: From 0de133686f6b5b62c1b411dee7e85c2d8f91dd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 13 May 2023 16:01:20 +0300 Subject: [PATCH 158/487] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5d3350a6..9515d50f 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - - Extend string types with LE and BE variants of UTF-16 and UTF-32 - - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others Array of Bytes - - Implement a custom combobox class for comboBox_ValueType and create a context menu for String_Others item +- Having to stop the process to resolve symbols sucks, we already resolve base addresses of libs by ourselves, try to replace this gdb functionality with something else, maybe the output of nm or manual parsing - Indent docstrings properly like GDB_Engine.get_breakpoint_info does(independent from other steps) - Implement "Investigate Registers" button to gather information about the addresses registers point to(independent from other steps) - Implement selectionChanged signal of lineEdit_HexView From b3f73d36df747d7b1595c60e19a685db765961aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 13 May 2023 16:09:45 +0300 Subject: [PATCH 159/487] Remove unused file --- TODO.md | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 TODO.md diff --git a/TODO.md b/TODO.md deleted file mode 100644 index d76f3cbf..00000000 --- a/TODO.md +++ /dev/null @@ -1,21 +0,0 @@ - ---- -**2022/11/24 -- Fix scrolling via the vertical scrollbar in memoryview** - -[fixed] + Currently using the vertical scrollbar to scroll the disassembled instructions in the memoryview, and in hex view, results in endless movement of the scrollbar but no actual scrolling takes place. - ---- - ---- -**2022/11/24 -- Hex and Ascii Models in Memory View Don't show the proper values** - -[fixed] + Currently the Hex and Ascii Viewer are showing black squares, or , it should - show the hex value (in the hex view) and the Ascii value (or a . for non-ascii). - -[fixed] + Additionally, the hex digits are not showing two digits per entry (eg 12 34, instead of 1 3) - -[fixed] + Ascii text-view has for non-printable characters, this needs to be changed to . - -[fixed] + Pressing PgUp/Dn, or arrow keys does not scroll the hex view (but the mouse wheel does) - ---- From 4db6e6182daf7266a9d98079562a7c6e37759543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 14 May 2023 01:09:19 +0300 Subject: [PATCH 160/487] Fix spacing of HexView --- GUI/CustomTableViews/AsciiView.py | 1 + GUI/CustomTableViews/HexView.py | 6 ++++-- GUI/MemoryViewerWindow.py | 4 ++-- GUI/MemoryViewerWindow.ui | 8 ++++---- PINCE.py | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/GUI/CustomTableViews/AsciiView.py b/GUI/CustomTableViews/AsciiView.py index 466a0ffb..120c5914 100644 --- a/GUI/CustomTableViews/AsciiView.py +++ b/GUI/CustomTableViews/AsciiView.py @@ -21,4 +21,5 @@ class QAsciiView(QHexView): # data_array is returned from GDB_Engine.hex_dump() def __init__(self, parent=None): super().__init__(parent) + self.horizontalHeader().setMinimumSectionSize(15) self.horizontalHeader().setDefaultSectionSize(15) diff --git a/GUI/CustomTableViews/HexView.py b/GUI/CustomTableViews/HexView.py index 1eb926c1..42ad485e 100644 --- a/GUI/CustomTableViews/HexView.py +++ b/GUI/CustomTableViews/HexView.py @@ -24,8 +24,10 @@ def __init__(self, parent=None): super().__init__(parent) self.horizontalHeader().setVisible(False) self.verticalHeader().setVisible(False) - self.verticalHeader().setDefaultSectionSize(self.verticalHeader().minimumSectionSize()) - self.horizontalHeader().setDefaultSectionSize(self.horizontalHeader().minimumSectionSize()) + self.verticalHeader().setMinimumSectionSize(21) + self.verticalHeader().setDefaultSectionSize(21) + self.horizontalHeader().setMinimumSectionSize(25) + self.horizontalHeader().setDefaultSectionSize(25) self.setStyleSheet("QTableView {background-color: transparent;}") self.setShowGrid(False) self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index e5c026f7..26736cf2 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -608,7 +608,7 @@ def setupUi(self, MainWindow_MemoryView): self.line_5.setObjectName("line_5") self.horizontalLayout_5.addWidget(self.line_5) self.tableView_HexView_Hex = QHexView(self.scrollAreaWidgetContents_2) - self.tableView_HexView_Hex.setTextElideMode(QtCore.Qt.TextElideMode.ElideNone) + self.tableView_HexView_Hex.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) self.tableView_HexView_Hex.setObjectName("tableView_HexView_Hex") self.horizontalLayout_5.addWidget(self.tableView_HexView_Hex) self.line_4 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) @@ -617,7 +617,7 @@ def setupUi(self, MainWindow_MemoryView): self.line_4.setObjectName("line_4") self.horizontalLayout_5.addWidget(self.line_4) self.tableView_HexView_Ascii = QAsciiView(self.scrollAreaWidgetContents_2) - self.tableView_HexView_Ascii.setTextElideMode(QtCore.Qt.TextElideMode.ElideNone) + self.tableView_HexView_Ascii.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) self.tableView_HexView_Ascii.setObjectName("tableView_HexView_Ascii") self.horizontalLayout_5.addWidget(self.tableView_HexView_Ascii) spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 32790667..67ccfb37 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -1326,8 +1326,8 @@ - - Qt::ElideNone + + QAbstractScrollArea::AdjustToContents @@ -1340,8 +1340,8 @@ - - Qt::ElideNone + + QAbstractScrollArea::AdjustToContents diff --git a/PINCE.py b/PINCE.py index f013a012..d1a5b4de 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2604,7 +2604,7 @@ def __init__(self, parent=None): self.splitter_Disassemble_Registers.setStretchFactor(0, 1) self.splitter_MainMiddle.setStretchFactor(1, 1) - self.widget_StackView.resize(420, self.widget_StackView.height()) # blaze it + self.widget_StackView.resize(660, self.widget_StackView.height()) self.widget_Registers.resize(330, self.widget_Registers.height()) def initialize_register_view(self): From 802eb929a89a89992320c4cdcb512419e085fb71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 16 May 2023 14:00:59 +0300 Subject: [PATCH 161/487] Add support for offsets --- libpince/common_regexes.py | 1 + libpince/gdb_python_scripts/ScriptUtils.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index b0acd4f0..509d25c0 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -64,3 +64,4 @@ dissect_code_valid_address = compile(r"(\s+|\[|,)" + hex_number.pattern + "(\s+|\]|,|$)") alphanumerics = compile(r"\w+") file_with_extension = compile(r".+\.\w+") +simple_math_exp = compile("[0-9a-fA-FxX/*+\-]+") diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/ScriptUtils.py index 7fb555f9..bba2c788 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/ScriptUtils.py @@ -118,12 +118,22 @@ def examine_expression(expression, regions=None): try: value = gdb.parse_and_eval(expression).cast(void_ptr) except Exception as e: - if regions and (expression == inferior_name or common_regexes.file_with_extension.search(expression)): + if "+" in expression: + expression, offset = expression.split("+") + else: + offset = "0" + if regions and common_regexes.simple_math_exp.search(offset) and \ + (expression == inferior_name or common_regexes.file_with_extension.search(expression)): for region in regions: address, file_name = region if expression in file_name: + try: + address = hex(eval(address+"+"+offset)) + except Exception as e: + print(e) + return type_defs.tuple_examine_expression(None, None, None) return type_defs.tuple_examine_expression(address+" "+file_name, address, file_name) - print(e, "for expression " + expression) + print(e) return type_defs.tuple_examine_expression(None, None, None) result = common_regexes.address_with_symbol.search(str(value)) return type_defs.tuple_examine_expression(*result.groups()) From bfce4f64511c6bb9d4de2868deb1496e3c75de47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 17 May 2023 22:33:01 +0300 Subject: [PATCH 162/487] Support basic math operators --- libpince/common_regexes.py | 2 +- libpince/gdb_python_scripts/ScriptUtils.py | 32 ++++++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index 509d25c0..f52f072d 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -64,4 +64,4 @@ dissect_code_valid_address = compile(r"(\s+|\[|,)" + hex_number.pattern + "(\s+|\]|,|$)") alphanumerics = compile(r"\w+") file_with_extension = compile(r".+\.\w+") -simple_math_exp = compile("[0-9a-fA-FxX/*+\-]+") +offset_expression = compile("[/*+\-][0-9a-fA-FxX/*+\-]+$") diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/ScriptUtils.py index bba2c788..ed5c85a0 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/ScriptUtils.py @@ -118,21 +118,23 @@ def examine_expression(expression, regions=None): try: value = gdb.parse_and_eval(expression).cast(void_ptr) except Exception as e: - if "+" in expression: - expression, offset = expression.split("+") - else: - offset = "0" - if regions and common_regexes.simple_math_exp.search(offset) and \ - (expression == inferior_name or common_regexes.file_with_extension.search(expression)): - for region in regions: - address, file_name = region - if expression in file_name: - try: - address = hex(eval(address+"+"+offset)) - except Exception as e: - print(e) - return type_defs.tuple_examine_expression(None, None, None) - return type_defs.tuple_examine_expression(address+" "+file_name, address, file_name) + if regions: # this check comes first for optimization + offset = common_regexes.offset_expression.search(expression) + if offset: + offset = offset.group(0) + expression = expression.split(offset[0])[0] + else: + offset = "+0" + if expression == inferior_name or common_regexes.file_with_extension.search(expression): + for region in regions: + address, file_name = region + if expression in file_name: + try: + address = hex(eval(address+offset)) + except Exception as e: + print(e) + return type_defs.tuple_examine_expression(None, None, None) + return type_defs.tuple_examine_expression(address+file_name, address, file_name) print(e) return type_defs.tuple_examine_expression(None, None, None) result = common_regexes.address_with_symbol.search(str(value)) From a252c6d16a17ba293fd21326e513c50b3b3fe1fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 18 May 2023 18:50:28 +0300 Subject: [PATCH 163/487] Fix inferior_name --- libpince/SysUtils.py | 14 ++++++++++++++ libpince/gdb_python_scripts/ScriptUtils.py | 6 +++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 82c7a991..979bd406 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -61,6 +61,20 @@ def get_process_information(pid): return psutil.Process(pid) +#:tag:Processes +def get_process_name(pid): + """Returns the process name of given pid + + Args: + pid (int): PID of the process + + Returns: + str: Process name + """ + with open("/proc/"+str(pid)+"/comm") as f: + return f.read()[:-1] + + #:tag:Processes def search_processes(process_name): """Searches currently running processes and returns a list of psutil.Process objects corresponding to processes that diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/ScriptUtils.py index ed5c85a0..7b5a18ad 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/ScriptUtils.py @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import gdb, sys, os, traceback, functools +import gdb, sys, traceback, functools from collections import OrderedDict # This is some retarded hack @@ -23,11 +23,11 @@ GDBINIT_AA_PATH = gdb.parse_and_eval("$GDBINIT_AA_PATH").string() sys.path.append(PINCE_PATH) # Adds the PINCE directory to PYTHONPATH to import libraries from PINCE -from libpince import type_defs, common_regexes +from libpince import SysUtils, type_defs, common_regexes inferior = gdb.selected_inferior() pid = inferior.pid -inferior_name = os.path.split(inferior.progspace.filename)[1] +inferior_name = SysUtils.get_process_name(pid) mem_file = "/proc/" + str(pid) + "/mem" void_ptr = gdb.lookup_type("void").pointer() From 6ad73c650f5eb599faedcd96e030cdef2cbf8ebf Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Thu, 18 May 2023 20:38:23 +0200 Subject: [PATCH 164/487] add Indicator for no Process --- PINCE.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/PINCE.py b/PINCE.py index d1a5b4de..7d5cf74d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -518,6 +518,11 @@ def __init__(self): self.pushButton_About.setIcon(QIcon(QPixmap(icons_directory + "/information.png"))) self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) + self.flashAttachButton = True + self.flashAttachButtonTimer = QTimer() + self.flashAttachButtonTimer.timeout.connect(self.flash_attach_button) + self.flashAttachButton_gradiantState = 0 + self.flashAttachButtonTimer.start(100) self.auto_attach() def set_default_settings(self): @@ -621,6 +626,7 @@ def auto_attach(self): continue if compiled_re.search(name): self.attach_to_pid(process.pid) + self.flashAttachButton = False return else: for target in auto_attach_list.split(";"): @@ -631,6 +637,7 @@ def auto_attach(self): continue if name.find(target) != -1: self.attach_to_pid(process.pid) + self.flashAttachButton = False return # Keyboard package has an issue with exceptions, any trigger function that throws an exception stops the event loop @@ -1289,6 +1296,9 @@ def on_new_process(self): self.pushButton_AddAddressManually.setEnabled(True) self.pushButton_MemoryView.setEnabled(True) + # stop flashing attach button, timer will stop automatically on false value + self.flashAttachButton = False + def delete_address_table_contents(self): if self.treeWidget_AddressTable.topLevelItemCount() == 0: return @@ -1324,6 +1334,8 @@ def on_inferior_exit(self): self.on_status_running() GDB_Engine.init_gdb(gdb_path) self.apply_after_init() + self.flashAttachButton = True + self.flashAttachButtonTimer.start(100) self.label_SelectedProcess.setText("No Process Selected") def on_status_detached(self): @@ -1576,6 +1588,39 @@ def read_address_table_entries(self, row, serialize=False): def read_address_table_recursively(self, row): return self.read_address_table_entries(row, True) + \ ([self.read_address_table_recursively(row.child(i)) for i in range(row.childCount())],) + + # Flashing Attach Button when the process is not attached + def flash_attach_button(self): + if not self.flashAttachButton: + self.flashAttachButtonTimer.stop() + self.pushButton_AttachProcess.setStyleSheet("") + return + gradiant0 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 255), stop:0.166 rgba(255, 255, 0, 255), stop:0.333 rgba(0, 255, 0, 255), stop:0.5 rgba(0, 255, 255, 255), stop:0.666 rgba(0, 0, 255, 255), stop:0.833 rgba(255, 0, 255, 255), stop:1 rgba(255, 0, 0, 255));" + gradiant1 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 255, 255), stop:0.166 rgba(255, 0, 0, 255), stop:0.333 rgba(255, 255, 0, 255), stop:0.5 rgba(0, 255, 0, 255), stop:0.666 rgba(0, 255, 255, 255), stop:0.833 rgba(0, 0, 255, 255), stop:1 rgba(255, 0, 255, 255));" + gradiant2 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 255, 255), stop:0.166 rgba(255, 0, 255, 255), stop:0.333 rgba(255, 0, 0, 255), stop:0.5 rgba(255, 255, 0, 255), stop:0.666 rgba(0, 255, 0, 255), stop:0.833 rgba(0, 255, 255, 255), stop:1 rgba(0, 0, 255, 255));" + gradiant3 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 255, 255, 255), stop:0.166 rgba(0, 0, 255, 255), stop:0.333 rgba(255, 0, 255, 255), stop:0.5 rgba(255, 0, 0, 255), stop:0.666 rgba(255, 255, 0, 255), stop:0.833 rgba(0, 255, 0, 255), stop:1 rgba(0, 255, 255, 255));" + gradiant4 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 255, 0, 255), stop:0.166 rgba(0, 255, 255, 255), stop:0.333 rgba(0, 0, 255, 255), stop:0.5 rgba(255, 0, 255, 255), stop:0.666 rgba(255, 0, 0, 255), stop:0.833 rgba(255, 255, 0, 255), stop:1 rgba(0, 255, 0, 255));" + gradiant5 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 0, 255), stop:0.166 rgba(0, 255, 0, 255), stop:0.333 rgba(0, 255, 255, 255), stop:0.5 rgba(0, 0, 255, 255), stop:0.666 rgba(255, 0, 255, 255), stop:0.833 rgba(255, 0, 0, 255), stop:1 rgba(255, 255, 0, 255));" + + + case = self.flashAttachButton_gradiantState % 6 + + if case == 0: + self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant0) + elif case == 1: + self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant1) + elif case == 2: + self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant2) + elif case == 3: + self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant3) + elif case == 4: + self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant4) + elif case == 5: + self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant5) + + self.flashAttachButton_gradiantState += 1 + if self.flashAttachButton_gradiantState > 399: + self.flashAttachButton_gradiantState = 0 # process select window From d414209c2e0d2e9eb8dd638f2af8e024f3c9e903 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Thu, 18 May 2023 22:21:09 +0200 Subject: [PATCH 165/487] changed Color from Gradiant to green Also cleaned up the new code, no longer unecessary lists. direct calculation of gradient --- PINCE.py | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/PINCE.py b/PINCE.py index 7d5cf74d..b9f25166 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1595,31 +1595,17 @@ def flash_attach_button(self): self.flashAttachButtonTimer.stop() self.pushButton_AttachProcess.setStyleSheet("") return - gradiant0 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 255), stop:0.166 rgba(255, 255, 0, 255), stop:0.333 rgba(0, 255, 0, 255), stop:0.5 rgba(0, 255, 255, 255), stop:0.666 rgba(0, 0, 255, 255), stop:0.833 rgba(255, 0, 255, 255), stop:1 rgba(255, 0, 0, 255));" - gradiant1 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 255, 255), stop:0.166 rgba(255, 0, 0, 255), stop:0.333 rgba(255, 255, 0, 255), stop:0.5 rgba(0, 255, 0, 255), stop:0.666 rgba(0, 255, 255, 255), stop:0.833 rgba(0, 0, 255, 255), stop:1 rgba(255, 0, 255, 255));" - gradiant2 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 0, 255, 255), stop:0.166 rgba(255, 0, 255, 255), stop:0.333 rgba(255, 0, 0, 255), stop:0.5 rgba(255, 255, 0, 255), stop:0.666 rgba(0, 255, 0, 255), stop:0.833 rgba(0, 255, 255, 255), stop:1 rgba(0, 0, 255, 255));" - gradiant3 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 255, 255, 255), stop:0.166 rgba(0, 0, 255, 255), stop:0.333 rgba(255, 0, 255, 255), stop:0.5 rgba(255, 0, 0, 255), stop:0.666 rgba(255, 255, 0, 255), stop:0.833 rgba(0, 255, 0, 255), stop:1 rgba(0, 255, 255, 255));" - gradiant4 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(0, 255, 0, 255), stop:0.166 rgba(0, 255, 255, 255), stop:0.333 rgba(0, 0, 255, 255), stop:0.5 rgba(255, 0, 255, 255), stop:0.666 rgba(255, 0, 0, 255), stop:0.833 rgba(255, 255, 0, 255), stop:1 rgba(0, 255, 0, 255));" - gradiant5 = "qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 0, 255), stop:0.166 rgba(0, 255, 0, 255), stop:0.333 rgba(0, 255, 255, 255), stop:0.5 rgba(0, 0, 255, 255), stop:0.666 rgba(255, 0, 255, 255), stop:0.833 rgba(255, 0, 0, 255), stop:1 rgba(255, 255, 0, 255));" - - - case = self.flashAttachButton_gradiantState % 6 - - if case == 0: - self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant0) - elif case == 1: - self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant1) - elif case == 2: - self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant2) - elif case == 3: - self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant3) - elif case == 4: - self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant4) - elif case == 5: - self.pushButton_AttachProcess.setStyleSheet("border: 2px solid " + gradiant5) + case = self.flashAttachButton_gradiantState % 64 + + if case < 32: + borderstring = "border: 2px solid rgba(0,255,0," + str(case / 32) + ");" + else: + borderstring = "border: 2px solid rgba(0,255,0," + str((64 - case) / 32) + ");" + + self.pushButton_AttachProcess.setStyleSheet(borderstring) self.flashAttachButton_gradiantState += 1 - if self.flashAttachButton_gradiantState > 399: + if self.flashAttachButton_gradiantState > 7000: self.flashAttachButton_gradiantState = 0 From da6c01b5883e77f23b97ab937e7d59a64fb7d2a2 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Fri, 19 May 2023 11:19:14 +0200 Subject: [PATCH 166/487] sped up animation by increasing alpha steps --- PINCE.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index b9f25166..d4a57d65 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1596,12 +1596,12 @@ def flash_attach_button(self): self.pushButton_AttachProcess.setStyleSheet("") return - case = self.flashAttachButton_gradiantState % 64 + case = self.flashAttachButton_gradiantState % 32 - if case < 32: - borderstring = "border: 2px solid rgba(0,255,0," + str(case / 32) + ");" + if case < 16: + borderstring = "border: 2px solid rgba(0,255,0," + str(case / 16) + ");" else: - borderstring = "border: 2px solid rgba(0,255,0," + str((64 - case) / 32) + ");" + borderstring = "border: 2px solid rgba(0,255,0," + str((32 - case) / 16) + ");" self.pushButton_AttachProcess.setStyleSheet(borderstring) self.flashAttachButton_gradiantState += 1 From f224451d0571ad70348658abe2fb1ed64cf42df4 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Fri, 19 May 2023 11:23:39 +0200 Subject: [PATCH 167/487] rm Styling from Tooltip Styling now only affects button, Tooltip is still normal Default behaviour inherits Styling to Children Components --- PINCE.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index d4a57d65..8d724d5a 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1599,9 +1599,9 @@ def flash_attach_button(self): case = self.flashAttachButton_gradiantState % 32 if case < 16: - borderstring = "border: 2px solid rgba(0,255,0," + str(case / 16) + ");" + borderstring = "QPushButton {border: 2px solid rgba(0,255,0," + str(case / 16) + ");}" else: - borderstring = "border: 2px solid rgba(0,255,0," + str((32 - case) / 16) + ");" + borderstring = "QPushButton {border: 2px solid rgba(0,255,0," + str((32 - case) / 16) + ");}" self.pushButton_AttachProcess.setStyleSheet(borderstring) self.flashAttachButton_gradiantState += 1 From e7fa688ba54d4c4067b980b2e2bc17aeb40b5970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 19 May 2023 16:05:15 +0300 Subject: [PATCH 168/487] Hotfix for flash_attach_button --- PINCE.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index 8d724d5a..da734b3f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1599,13 +1599,13 @@ def flash_attach_button(self): case = self.flashAttachButton_gradiantState % 32 if case < 16: - borderstring = "QPushButton {border: 2px solid rgba(0,255,0," + str(case / 16) + ");}" + borderstring = "QPushButton {border: 3px solid rgba(0,255,0," + str(case / 16) + ");}" else: - borderstring = "QPushButton {border: 2px solid rgba(0,255,0," + str((32 - case) / 16) + ");}" + borderstring = "QPushButton {border: 3px solid rgba(0,255,0," + str((32 - case) / 16) + ");}" self.pushButton_AttachProcess.setStyleSheet(borderstring) self.flashAttachButton_gradiantState += 1 - if self.flashAttachButton_gradiantState > 7000: + if self.flashAttachButton_gradiantState > 768: # 32*24 self.flashAttachButton_gradiantState = 0 From 2b2d0042570badfd710260eba0369141de5cbbbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 20 May 2023 23:15:15 +0300 Subject: [PATCH 169/487] Replace psutil with regex --- .travis.yml | 2 +- GUI/MemoryRegionsWidget.py | 40 +----- GUI/MemoryRegionsWidget.ui | 47 +------ Notes.txt | 2 +- PINCE.py | 101 +++++---------- install_pince.sh | 3 +- libpince/GDB_Engine.py | 4 +- libpince/SysUtils.py | 122 ++++++------------ libpince/common_regexes.py | 15 ++- .../GDBCommandExtensions.py | 5 +- libpince/gdb_python_scripts/ScriptUtils.py | 3 +- libpince/type_defs.py | 4 +- run_tests.py | 13 +- 13 files changed, 104 insertions(+), 257 deletions(-) diff --git a/.travis.yml b/.travis.yml index aedb5ea1..c9499fe5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ before_install: - wget https://bootstrap.pypa.io/get-pip.py - sudo python3 get-pip.py - - sudo pip3 install psutil pexpect distorm3 pygdbmi + - sudo pip3 install pexpect distorm3 pygdbmi - sudo mv /usr/bin/lsb_release_masked /usr/bin/lsb_release diff --git a/GUI/MemoryRegionsWidget.py b/GUI/MemoryRegionsWidget.py index d4b3e741..369879a7 100644 --- a/GUI/MemoryRegionsWidget.py +++ b/GUI/MemoryRegionsWidget.py @@ -21,7 +21,7 @@ def setupUi(self, Form): self.tableWidget_MemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_MemoryRegions.setWordWrap(False) self.tableWidget_MemoryRegions.setObjectName("tableWidget_MemoryRegions") - self.tableWidget_MemoryRegions.setColumnCount(13) + self.tableWidget_MemoryRegions.setColumnCount(4) self.tableWidget_MemoryRegions.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.tableWidget_MemoryRegions.setHorizontalHeaderItem(0, item) @@ -31,24 +31,6 @@ def setupUi(self, Form): self.tableWidget_MemoryRegions.setHorizontalHeaderItem(2, item) item = QtWidgets.QTableWidgetItem() self.tableWidget_MemoryRegions.setHorizontalHeaderItem(3, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(4, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(5, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(6, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(7, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(8, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(9, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(10, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(11, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_MemoryRegions.setHorizontalHeaderItem(12, item) self.tableWidget_MemoryRegions.horizontalHeader().setStretchLastSection(True) self.tableWidget_MemoryRegions.verticalHeader().setVisible(False) self.tableWidget_MemoryRegions.verticalHeader().setDefaultSectionSize(16) @@ -67,24 +49,6 @@ def retranslateUi(self, Form): item = self.tableWidget_MemoryRegions.horizontalHeaderItem(1) item.setText(_translate("Form", "Perms")) item = self.tableWidget_MemoryRegions.horizontalHeaderItem(2) - item.setText(_translate("Form", "Size")) + item.setText(_translate("Form", "Offset")) item = self.tableWidget_MemoryRegions.horizontalHeaderItem(3) item.setText(_translate("Form", "Path")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(4) - item.setText(_translate("Form", "RSS")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(5) - item.setText(_translate("Form", "PSS")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(6) - item.setText(_translate("Form", "Shared_Clean")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(7) - item.setText(_translate("Form", "Shared_Dirty")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(8) - item.setText(_translate("Form", "Private_Clean")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(9) - item.setText(_translate("Form", "Private_Dirty")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(10) - item.setText(_translate("Form", "Referenced")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(11) - item.setText(_translate("Form", "Anonymous")) - item = self.tableWidget_MemoryRegions.horizontalHeaderItem(12) - item.setText(_translate("Form", "Swap")) diff --git a/GUI/MemoryRegionsWidget.ui b/GUI/MemoryRegionsWidget.ui index ee637d0f..b4738af0 100644 --- a/GUI/MemoryRegionsWidget.ui +++ b/GUI/MemoryRegionsWidget.ui @@ -55,7 +55,7 @@ - Size + Offset @@ -63,51 +63,6 @@ Path - - - RSS - - - - - PSS - - - - - Shared_Clean - - - - - Shared_Dirty - - - - - Private_Clean - - - - - Private_Dirty - - - - - Referenced - - - - - Anonymous - - - - - Swap - - diff --git a/Notes.txt b/Notes.txt index 14cc66e6..e1f6278c 100644 --- a/Notes.txt +++ b/Notes.txt @@ -1,7 +1,7 @@ Code Relocations: --libpince GuiUtils.py is used to contain GUI related utility functions - SysUtils.py is used to contain all useful but non-GDB related libraries such as psutil + SysUtils.py is used to contain non-GDB related utility functions GDB_Engine.py is used to contain all GDB related functions type_defs.py is used to contain all static&shared variable definitions All codes that'll be injected to the inferior go to the folder "Injection" diff --git a/PINCE.py b/PINCE.py index da734b3f..fb771517 100755 --- a/PINCE.py +++ b/PINCE.py @@ -36,7 +36,7 @@ from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, \ QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QThreadPool, pyqtSlot from time import sleep, time -import os, sys, traceback, signal, re, copy, io, queue, collections, ast, psutil, pexpect +import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect from libpince import GuiUtils, SysUtils, GDB_Engine, type_defs from libpince.libscanmem.scanmem import Scanmem @@ -244,17 +244,8 @@ def get_hotkeys(): # represents the index of columns in memory regions table MEMORY_REGIONS_ADDR_COL = 0 MEMORY_REGIONS_PERM_COL = 1 -MEMORY_REGIONS_SIZE_COL = 2 +MEMORY_REGIONS_OFFSET_COL = 2 MEMORY_REGIONS_PATH_COL = 3 -MEMORY_REGIONS_RSS_COL = 4 -MEMORY_REGIONS_PSS_COL = 5 -MEMORY_REGIONS_SHRCLN_COL = 6 -MEMORY_REGIONS_SHRDRTY_COL = 7 -MEMORY_REGIONS_PRIVCLN_COL = 8 -MEMORY_REGIONS_PRIVDRTY_COL = 9 -MEMORY_REGIONS_REF_COL = 10 -MEMORY_REGIONS_ANON_COL = 11 -MEMORY_REGIONS_SWAP_COL = 12 # represents the index of columns in dissect code table DISSECT_CODE_ADDR_COL = 0 @@ -619,24 +610,16 @@ def auto_attach(self): except: print("Auto-attach failed: " + auto_attach_list + " isn't a valid regex") return - for process in SysUtils.iterate_processes(): - try: - name = process.name() - except psutil.NoSuchProcess: - continue + for pid, _, name in SysUtils.get_process_list(): if compiled_re.search(name): - self.attach_to_pid(process.pid) + self.attach_to_pid(pid) self.flashAttachButton = False return else: for target in auto_attach_list.split(";"): - for process in SysUtils.iterate_processes(): - try: - name = process.name() - except psutil.NoSuchProcess: - continue + for pid, _, name in SysUtils.get_process_list(): if name.find(target) != -1: - self.attach_to_pid(process.pid) + self.attach_to_pid(pid) self.flashAttachButton = False return @@ -1281,12 +1264,10 @@ def create_new_process(self, file_path, args, ld_preload_path): self.on_inferior_exit() return False - # This is called whenever a new process is created/attached to by PINCE - # in order to change the form appearance + # Changes appearance whenever a new process is created or attached def on_new_process(self): - # TODO add scanmem attachment here - p = SysUtils.get_process_information(GDB_Engine.currentpid) - self.label_SelectedProcess.setText(str(p.pid) + " - " + p.name()) + name = SysUtils.get_process_name(GDB_Engine.currentpid) + self.label_SelectedProcess.setText(str(GDB_Engine.currentpid) + " - " + name) # enable scan GUI self.lineEdit_Scan.setPlaceholderText("Scan for") @@ -1615,7 +1596,7 @@ def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) GuiUtils.center_to_parent(self) - self.refresh_process_table(self.tableWidget_ProcessTable, SysUtils.iterate_processes()) + self.refresh_process_table(self.tableWidget_ProcessTable, SysUtils.get_process_list()) self.pushButton_Close.clicked.connect(self.close) self.pushButton_Open.clicked.connect(self.pushButton_Open_clicked) self.pushButton_CreateProcess.clicked.connect(self.pushButton_CreateProcess_clicked) @@ -1642,17 +1623,11 @@ def keyPressEvent(self, e): # lists currently working processes to table def refresh_process_table(self, tablewidget, processlist): tablewidget.setRowCount(0) - for process in processlist: - pid = str(process.pid) - try: - username = process.username() - name = process.name() - except psutil.NoSuchProcess: - continue + for pid, user, name in processlist: current_row = tablewidget.rowCount() tablewidget.insertRow(current_row) tablewidget.setItem(current_row, 0, QTableWidgetItem(pid)) - tablewidget.setItem(current_row, 1, QTableWidgetItem(username)) + tablewidget.setItem(current_row, 1, QTableWidgetItem(user)) tablewidget.setItem(current_row, 2, QTableWidgetItem(name)) # gets the pid out of the selection to attach @@ -2692,7 +2667,7 @@ def initialize_disassemble_view(self): def initialize_hex_view(self): self.cached_breakpoint_info = [] self.hex_view_last_selected_address_int = 0 - self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None) + self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) self.widget_HexView.wheelEvent = self.widget_HexView_wheel_event self.tableView_HexView_Hex.contextMenuEvent = self.widget_HexView_context_menu_event self.tableView_HexView_Ascii.contextMenuEvent = self.widget_HexView_context_menu_event @@ -2999,10 +2974,10 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL information = SysUtils.get_region_info(GDB_Engine.currentpid, int_address) if information: self.hex_view_current_region = information - self.label_HexView_Information.setText("Protection:" + information.region.perms + " | Base:" + + self.label_HexView_Information.setText("Protection:" + information.perms + " | Base:" + hex(information.start) + "-" + hex(information.end)) else: - self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None) + self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) self.label_HexView_Information.setText("This region is invalid") self.tableWidget_HexView_Address.setRowCount(0) self.tableWidget_HexView_Address.setRowCount(HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT) @@ -5392,29 +5367,15 @@ def __init__(self, parent=None): self.shortcut_refresh.activated.connect(self.refresh_table) def refresh_table(self): - memory_regions = SysUtils.get_memory_regions(GDB_Engine.currentpid) + memory_regions = SysUtils.get_regions(GDB_Engine.currentpid) self.tableWidget_MemoryRegions.setRowCount(0) self.tableWidget_MemoryRegions.setRowCount(len(memory_regions)) - for row, region in enumerate(memory_regions): - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_ADDR_COL, QTableWidgetItem(region.addr)) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PERM_COL, QTableWidgetItem(region.perms)) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_SIZE_COL, QTableWidgetItem(hex(region.size))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PATH_COL, QTableWidgetItem(region.path)) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_RSS_COL, QTableWidgetItem(hex(region.rss))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PSS_COL, QTableWidgetItem(hex(region.pss))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_SHRCLN_COL, - QTableWidgetItem(hex(region.shared_clean))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_SHRDRTY_COL, - QTableWidgetItem(hex(region.shared_dirty))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PRIVCLN_COL, - QTableWidgetItem(hex(region.private_clean))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PRIVDRTY_COL, - QTableWidgetItem(hex(region.private_dirty))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_REF_COL, - QTableWidgetItem(hex(region.referenced))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_ANON_COL, - QTableWidgetItem(hex(region.anonymous))) - self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_SWAP_COL, QTableWidgetItem(hex(region.swap))) + for row, (start, end, perms, offset, _, _, path) in enumerate(memory_regions): + address = start+"-"+end + self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_ADDR_COL, QTableWidgetItem(address)) + self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PERM_COL, QTableWidgetItem(perms)) + self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_OFFSET_COL, QTableWidgetItem(offset)) + self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PATH_COL, QTableWidgetItem(path)) GuiUtils.resize_to_contents(self.tableWidget_MemoryRegions) def tableWidget_MemoryRegions_context_menu_event(self, event): @@ -5427,17 +5388,17 @@ def copy_to_clipboard(row, column): refresh = menu.addAction("Refresh[R]") menu.addSeparator() copy_addresses = menu.addAction("Copy Addresses") - copy_size = menu.addAction("Copy Size") + copy_offset = menu.addAction("Copy Offset") copy_path = menu.addAction("Copy Path") if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_addresses, copy_size, copy_path]) + GuiUtils.delete_menu_entries(menu, [copy_addresses, copy_offset, copy_path]) font_size = self.tableWidget_MemoryRegions.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) actions = { refresh: self.refresh_table, copy_addresses: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_ADDR_COL), - copy_size: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_SIZE_COL), + copy_offset: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_OFFSET_COL), copy_path: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_PATH_COL) } try: @@ -5530,13 +5491,15 @@ def update_dissect_results(self): self.label_CallReferenceCount.setText(str(len(referenced_calls))) def show_memory_regions(self): - executable_regions = SysUtils.filter_memory_regions(GDB_Engine.currentpid, "perms", "..x.") - self.region_list = executable_regions + executable_regions = SysUtils.filter_regions(GDB_Engine.currentpid, "permissions", "..x.") + self.region_list = [] self.tableWidget_ExecutableMemoryRegions.setRowCount(0) self.tableWidget_ExecutableMemoryRegions.setRowCount(len(executable_regions)) - for row, region in enumerate(executable_regions): - self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_ADDR_COL, QTableWidgetItem(region.addr)) - self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_PATH_COL, QTableWidgetItem(region.path)) + for row, (start, end, _, _, _, _, path) in enumerate(executable_regions): + address = start+"-"+end + self.region_list.append((start, end)) + self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_ADDR_COL, QTableWidgetItem(address)) + self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_PATH_COL, QTableWidgetItem(path)) GuiUtils.resize_to_contents(self.tableWidget_ExecutableMemoryRegions) def scan_finished(self): diff --git a/install_pince.sh b/install_pince.sh index 871b26e9..2107ce1c 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -108,13 +108,14 @@ ask_pkg_mgr() { return 0 } + # About xcb packages -> https://github.com/cdgriffith/FastFlix/wiki/Common-questions-and-problems PKG_NAMES_ALL="python3-pip gdb libtool intltool" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays -PKG_NAMES_PIP="pyqt6 psutil pexpect distorm3 pygdbmi keyboard pygobject" +PKG_NAMES_PIP="pyqt6 pexpect distorm3 pygdbmi keyboard pygobject" INSTALL_COMMAND="install" diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 6ba74dcc..ea3a1a28 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -1971,8 +1971,8 @@ def dissect_code(region_list, discard_invalid_strings=True): Use function get_dissect_code_data() to gather the results Args: - region_list (list): A list of psutil._pslinux.pmmap_ext objects - Can be returned from functions like SysUtils.filter_memory_regions + region_list (list): A list of (start_address, end_address) -> (str, str) + Can be returned from functions like SysUtils.filter_regions discard_invalid_strings (bool): Entries that can't be decoded as utf-8 won't be included in referenced strings """ send_command("pince-dissect-code", send_with_file=True, file_contents_send=(region_list, discard_invalid_strings)) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 979bd406..410259df 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -16,17 +16,6 @@ along with this program. If not, see . """ -# Fixes the ImportError problem in GDBCommandExtensions.py for Archlinux -# This makes any psutil based function that's called from GDB unusable for Archlinux -# Currently there's none but we can't take it for granted, can we? -# TODO: Research the reason behind it or at least find a workaround -# TODO: psutil is a bit slow for what it is, replace if this slight overhead becomes a problem -# It takes about 30ms for get_region_set to run, a bit too slow innit, not really critical but slow indeed -try: - import psutil -except ImportError: - print("WARNING: GDB couldn't locate the package psutil, psutil based user-defined functions won't work\n" + - "If you are getting this message without invoking GDB, it means that installation has failed, well, sort of") import os, shutil, sys, binascii, pickle, json, traceback, re, pwd, pathlib, distorm3 from . import type_defs, common_regexes from collections import OrderedDict @@ -35,30 +24,13 @@ #:tag:Processes -def iterate_processes(): - """Returns a generator of psutil.Process objects corresponding to currently running processes +def get_process_list(): + """Returns a list of processes Returns: - generator: Generator of psutil.Process objects - - Note: - Calling any function from the iterated processes will give the psutil.NoSuchProcess exception if the iterated - process doesn't exist anymore. Use functions in a try/except block for safety - """ - return psutil.process_iter() - - -#:tag:Processes -def get_process_information(pid): - """Returns a psutil.Process object corresponding to given pid - - Args: - pid (int): PID of the process - - Returns: - psutil.Process: psutil.Process object corresponding to the given pid + list: List of (pid, user, process_name) -> (str, str, str) """ - return psutil.Process(pid) + return common_regexes.ps.findall(os.popen("ps -eo pid,user,comm").read()) #:tag:Processes @@ -77,67 +49,56 @@ def get_process_name(pid): #:tag:Processes def search_processes(process_name): - """Searches currently running processes and returns a list of psutil.Process objects corresponding to processes that - has the str process_name in them + """Searches processes and returns a list of the ones that contain process_name Args: process_name (str): Name of the process that'll be searched for Returns: - list: List of psutil.Process objects corresponding to the filtered processes - - Note: - Calling any function from the iterated processes will give the psutil.NoSuchProcess exception if the iterated - process doesn't exist anymore. Use functions in a try/except block for safety + list: List of (pid, user, process_name) -> (str, str, str) """ processlist = [] - for p in psutil.process_iter(): - try: - name = p.name() - except psutil.NoSuchProcess: - continue - if re.search(process_name, name, re.IGNORECASE): - processlist.append(p) + for pid, user, name in get_process_list(): + if process_name.lower() in name.lower(): + processlist.append((pid, user, name)) return processlist #:tag:Processes -def get_memory_regions(pid): - """Returns memory regions as a list of psutil._pslinux.pmmap_ext objects +def get_regions(pid): + """Returns memory regions of a process Args: pid (int): PID of the process Returns: - list: List of psutil._pslinux.pmmap_ext objects corresponding to the given pid + list: List of (start_address, end_address, permissions, map_offset, device_node, inode, path) -> all str """ - return psutil.Process(pid).memory_maps(grouped=False) + with open("/proc/"+str(pid)+"/maps") as f: + return common_regexes.maps.findall(f.read()) # :tag:Processes def get_region_set(pid): - """Returns memory regions as a list. Removes path duplicates and empty paths + """Returns memory regions of a process, removes path duplicates and empty paths Args: pid (int): PID of the process Returns: - list: List of str lists -> [[addr1, file_name1], [addr2, file_name2], ...] - - Note: - grouped=True could be used for this functionality but we might also get rid of psutil in the future due to - performance issues + list: List of (start_address, file_name) -> (str, str) """ region_set = [] current_file = "" - for item in get_memory_regions(pid): - if not item.path: + for item in get_regions(pid): + start_addr, _, _, _, _, _, path = item + if not path: continue - head, tail = os.path.split(item.path) + head, tail = os.path.split(path) if not head or tail == current_file: continue current_file = tail - region_set.append(["0x"+item.addr.split("-")[0], tail]) + region_set.append(("0x"+start_addr, tail)) return region_set @@ -151,51 +112,48 @@ def get_region_info(pid, address): address (int,str): Can be an int or a hex str Returns: - type_defs.tuple_region_info: Starting address as int, ending address as int and region corresponding to - the given address as psutil._pslinux.pmmap_ext object + list: List of (start_address, end_address, permissions, file_name) -> (int, int, str, str) None: If the given address isn't in any valid address range - - Note: - This function is very slow because of the poor performance on psutil's part. You might want to optimize your - code while using this function. Check MemoryViewWindowForm.hex_dump_address() for an optimization example """ if type(pid) != int: pid = int(pid) if type(address) != int: address = int(address, 0) - region_list = get_memory_regions(pid) - for item in region_list: - splitted_address = item.addr.split("-") - start = int(splitted_address[0], 16) - end = int(splitted_address[1], 16) + region_list = get_regions(pid) + for start, end, perms, _, _, _, path in region_list: + start = int(start, 16) + end = int(end, 16) + file_name = os.path.split(path)[1] if start <= address < end: - return type_defs.tuple_region_info(start, end, item) + return type_defs.tuple_region_info(start, end, perms, file_name) #:tag:Processes -def filter_memory_regions(pid, attribute, regex, case_sensitive=False): +def filter_regions(pid, attribute, regex, case_sensitive=False): """Filters memory regions by searching for the given regex within the given attribute Args: pid (int): PID of the process - attribute (str): The attribute that'll be filtered. Can be "addr", "perms" or "path" + attribute (str): The attribute that'll be filtered. Can be one of the below + start_address, end_address, permissions, map_offset, device_node, inode, path regex (str): Regex statement that'll be searched case_sensitive (bool): If True, search will be case sensitive Returns: - list: A list of psutil._pslinux.pmmap_ext objects + list: List of (start_address, end_address, permissions, map_offset, device_node, inode, path) -> all str """ - assert attribute in ["addr", "perms", "path"], "invalid attribute" + index = ["start_address", "end_address", "permissions", + "map_offset", "device_node", "inode", "path"].index(attribute) + if index == -1: + raise Exception("Invalid attribute") if case_sensitive: compiled_regex = re.compile(regex) else: compiled_regex = re.compile(regex, re.IGNORECASE) filtered_regions = [] - p = psutil.Process(pid) - for m in p.memory_maps(grouped=False): - current_attribute = getattr(m, attribute) - if compiled_regex.search(current_attribute): - filtered_regions.append(m) + for region in get_regions(pid): + if compiled_regex.search(region[index]): + filtered_regions.append(region) return filtered_regions @@ -220,7 +178,7 @@ def is_traced(pid): if tracer_pid == "0": return False else: - return psutil.Process(int(tracer_pid)).name() + return get_process_name(tracer_pid) #:tag:Processes diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index f52f072d..bc6f5abd 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from re import compile +from re import compile, VERBOSE # The comments near regular expressions shows the expected gdb output, hope it helps to the future developers @@ -49,6 +49,19 @@ docstring_variable = compile(r"(\w+)\s*=") docstring_function_or_variable = compile(r"def\s+(\w+)|" + docstring_variable.pattern) whitespaces = compile(r"\s+") +ps = compile(r""" + (\d+)\s+ # PID + (\S+)\s+ # Username + (.*)\s+ # Process name +""", VERBOSE) +maps = compile(r""" + ([0-9a-f]+)-([0-9a-f]+)\s+ # Address (start-end) + (\S+)\s+ # Permissions + ([0-9a-f]+)\s+ # Map offset + (\S+)\s+ # Device node + (\d+)\s+ # Inode + (.*)\s+ # Pathname +""", VERBOSE) # --------------------------------------------GuiUtils------------------------------------------------------------------ diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 0c714417..cd3b30a7 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -461,9 +461,8 @@ def invoke(self, arg, from_tty): ref_str_count = len(referenced_strings_dict) ref_jmp_count = len(referenced_jumps_dict) ref_call_count = len(referenced_calls_dict) - for region_index, region in enumerate(region_list): - region_info = region.addr, "Region " + str(region_index + 1) + " of " + str(region_count) - start_addr, end_addr = region.addr.split("-") + for region_index, (start_addr, end_addr) in enumerate(region_list): + region_info = start_addr+"-"+end_addr, "Region " + str(region_index + 1) + " of " + str(region_count) start_addr = int(start_addr, 16) # Becomes address of the last disassembled instruction later on end_addr = int(end_addr, 16) region_finished = False diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/ScriptUtils.py index 7b5a18ad..d2ba1429 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/ScriptUtils.py @@ -126,8 +126,7 @@ def examine_expression(expression, regions=None): else: offset = "+0" if expression == inferior_name or common_regexes.file_with_extension.search(expression): - for region in regions: - address, file_name = region + for address, file_name in regions: if expression in file_name: try: address = hex(eval(address+offset)) diff --git a/libpince/type_defs.py b/libpince/type_defs.py index d9f1766a..fb5c3b49 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -401,8 +401,8 @@ class SCAN_SCOPE: tuple_breakpoint_info = collections.namedtuple("tuple_breakpoint_info", "number breakpoint_type \ disp enabled address size on_hit hit_count enable_count condition") -# start, end-->int, region-->psutil.Process.memory_maps()[item] -tuple_region_info = collections.namedtuple("tuple_region_info", "start end region") +# start, end-->int, perms-->str, file_name-->str +tuple_region_info = collections.namedtuple("tuple_region_info", "start end perms file_name") # all fields-->str/None tuple_examine_expression = collections.namedtuple("tuple_examine_expression", "all address symbol") diff --git a/run_tests.py b/run_tests.py index 2214e2ad..877c0bc6 100644 --- a/run_tests.py +++ b/run_tests.py @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import unittest, argparse, psutil +import unittest, argparse from libpince import GDB_Engine, SysUtils desc = 'Runs all unit tests by creating or attaching to a process' @@ -38,18 +38,13 @@ if not process_list: parser.error("There's no process with the name " + args.a) if len(process_list) > 1: - for p in process_list: - try: - name = p.name() - except psutil.NoSuchProcess: - print("Process with pid", p.pid, "does not exist anymore") - continue + for pid, user, name in process_list: print(name) print("There are more than one process with the name " + args.a) exit() - pid = process_list[0].pid + pid = process_list[0][0] if not GDB_Engine.can_attach(pid): - parser.error("Failed to attach to the process with pid " + str(pid)) + parser.error("Failed to attach to the process with pid " + pid) GDB_Engine.attach(pid) elif args.c: if not GDB_Engine.create_process(args.c, args.o, args.l): From c6b1ddfcfcdde9c957400a9138d6854a25961641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 20 May 2023 23:45:10 +0300 Subject: [PATCH 170/487] Remove deprecated logging commands --- libpince/GDB_Engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index ea3a1a28..25899959 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -514,10 +514,10 @@ def set_logging(state): Args: state (bool): Sets logging on if True, off if False """ - send_command("set logging off") + send_command("set logging enabled off") send_command("set logging file " + SysUtils.get_logging_file(currentpid)) if state: - send_command("set logging on") + send_command("set logging enabled on") #:tag:GDBCommunication From fe256e826932b1e1e23d9fb1496ae1e1f952cbba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 21 May 2023 00:06:14 +0300 Subject: [PATCH 171/487] Add module field to region info --- PINCE.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index fb771517..9bccec08 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2975,7 +2975,8 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL if information: self.hex_view_current_region = information self.label_HexView_Information.setText("Protection:" + information.perms + " | Base:" + - hex(information.start) + "-" + hex(information.end)) + hex(information.start) + "-" + hex(information.end) + + " | Module:" + information.file_name) else: self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) self.label_HexView_Information.setText("This region is invalid") From 1f750cfd6110450f3c3e4ac3f953ca4568989363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 22 May 2023 19:35:01 +0300 Subject: [PATCH 172/487] Change scrolling mode to ScrollPerPixel --- GUI/BreakpointInfoWidget.py | 1 + GUI/BreakpointInfoWidget.ui | 3 +++ GUI/MemoryRegionsWidget.py | 1 + GUI/MemoryRegionsWidget.ui | 3 +++ GUI/MemoryViewerWindow.py | 3 ++- GUI/MemoryViewerWindow.ui | 5 ++++- GUI/TrackBreakpointWidget.py | 1 + GUI/TrackBreakpointWidget.ui | 3 +++ 8 files changed, 18 insertions(+), 2 deletions(-) diff --git a/GUI/BreakpointInfoWidget.py b/GUI/BreakpointInfoWidget.py index ab6dd369..634fae32 100644 --- a/GUI/BreakpointInfoWidget.py +++ b/GUI/BreakpointInfoWidget.py @@ -21,6 +21,7 @@ def setupUi(self, TabWidget): self.tableWidget_BreakpointInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_BreakpointInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_BreakpointInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_BreakpointInfo.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) self.tableWidget_BreakpointInfo.setWordWrap(False) self.tableWidget_BreakpointInfo.setObjectName("tableWidget_BreakpointInfo") self.tableWidget_BreakpointInfo.setColumnCount(9) diff --git a/GUI/BreakpointInfoWidget.ui b/GUI/BreakpointInfoWidget.ui index d2e24cc6..5bbff2c7 100644 --- a/GUI/BreakpointInfoWidget.ui +++ b/GUI/BreakpointInfoWidget.ui @@ -32,6 +32,9 @@ QAbstractItemView::SelectRows + + QAbstractItemView::ScrollPerPixel + false diff --git a/GUI/MemoryRegionsWidget.py b/GUI/MemoryRegionsWidget.py index 369879a7..7c7a48cc 100644 --- a/GUI/MemoryRegionsWidget.py +++ b/GUI/MemoryRegionsWidget.py @@ -19,6 +19,7 @@ def setupUi(self, Form): self.tableWidget_MemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_MemoryRegions.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_MemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_MemoryRegions.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) self.tableWidget_MemoryRegions.setWordWrap(False) self.tableWidget_MemoryRegions.setObjectName("tableWidget_MemoryRegions") self.tableWidget_MemoryRegions.setColumnCount(4) diff --git a/GUI/MemoryRegionsWidget.ui b/GUI/MemoryRegionsWidget.ui index b4738af0..73d494ab 100644 --- a/GUI/MemoryRegionsWidget.ui +++ b/GUI/MemoryRegionsWidget.ui @@ -25,6 +25,9 @@ QAbstractItemView::SelectRows + + QAbstractItemView::ScrollPerPixel + true diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 26736cf2..24d9398d 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -46,6 +46,7 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_Disassemble.setAlternatingRowColors(True) self.tableWidget_Disassemble.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Disassemble.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_Disassemble.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) self.tableWidget_Disassemble.setShowGrid(False) self.tableWidget_Disassemble.setWordWrap(False) self.tableWidget_Disassemble.setObjectName("tableWidget_Disassemble") @@ -580,7 +581,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Hex.setWidgetResizable(True) self.scrollArea_Hex.setObjectName("scrollArea_Hex") self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() - self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 545, 200)) + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 524, 200)) self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") self.gridLayout_11 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) self.gridLayout_11.setContentsMargins(0, 0, 0, 0) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 67ccfb37..79c7620f 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -96,6 +96,9 @@ QAbstractItemView::SelectRows + + QAbstractItemView::ScrollPerPixel + false @@ -1265,7 +1268,7 @@ 0 0 - 545 + 524 200 diff --git a/GUI/TrackBreakpointWidget.py b/GUI/TrackBreakpointWidget.py index 415b6fc2..cd9d9632 100644 --- a/GUI/TrackBreakpointWidget.py +++ b/GUI/TrackBreakpointWidget.py @@ -32,6 +32,7 @@ def setupUi(self, Form): self.tableWidget_TrackInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_TrackInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_TrackInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_TrackInfo.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) self.tableWidget_TrackInfo.setWordWrap(False) self.tableWidget_TrackInfo.setObjectName("tableWidget_TrackInfo") self.tableWidget_TrackInfo.setColumnCount(4) diff --git a/GUI/TrackBreakpointWidget.ui b/GUI/TrackBreakpointWidget.ui index f5c5339f..f58c8fd4 100644 --- a/GUI/TrackBreakpointWidget.ui +++ b/GUI/TrackBreakpointWidget.ui @@ -62,6 +62,9 @@ QAbstractItemView::SelectRows + + QAbstractItemView::ScrollPerPixel + false From f8a436e91fb11431b169230cc1c25f9728bfd0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 22 May 2023 19:56:05 +0300 Subject: [PATCH 173/487] Update Notes.txt --- Notes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Notes.txt b/Notes.txt index e1f6278c..81c99876 100644 --- a/Notes.txt +++ b/Notes.txt @@ -47,3 +47,5 @@ A full PR will look like this: /media/logo/your_username/pince_small.png 23/11/2018 - Don't use get_current_item or get_current_row within currentItemChanged or currentChanged signals. Qt doesn't update selected rows on first currentChanged or currentItemChanged calls + +22/05/2023 - For QTableWidget and QTableView, disabling wordWrap and using ScrollPerPixel as the horizontal scroll mode can help the user experience. Consider doing these when creating a new QTableWidget or QTableView From 0e69fc4fc50ce50be504e99748bb0528029e593b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 22 May 2023 21:25:18 +0300 Subject: [PATCH 174/487] Simplify examples --- PINCE.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/PINCE.py b/PINCE.py index 9bccec08..b0322a6a 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2293,10 +2293,10 @@ def checkBox_AutoUpdateAddressTable_state_changed(self): def checkBox_AutoAttachRegex_state_changed(self): if self.checkBox_AutoAttachRegex.isChecked(): self.lineEdit_AutoAttachList.setPlaceholderText("Mouse over on this text for examples") - self.lineEdit_AutoAttachList.setToolTip("'asdf|qwer' searches for asdf or qwer\n" + - "'[as]df' searches for both adf and sdf\n" + - "Use the char '\\' to escape special chars such as '['\n" + - "'\[asdf\]' searches for opcodes that contain '[asdf]'") + self.lineEdit_AutoAttachList.setToolTip("asdf|qwer --> search for asdf or qwer\n" + + "[as]df --> search for both adf and sdf\n" + + "Use the char \\ to escape special chars such as [\n" + + "\[asdf\] --> search for opcodes that contain [asdf]") else: self.lineEdit_AutoAttachList.setPlaceholderText("Separate processes with ;") self.lineEdit_AutoAttachList.setToolTip("") @@ -4396,14 +4396,14 @@ def __init__(self, address, instruction, parent=None): GuiUtils.center_to_parent(self) self.setWindowTitle("Addresses accessed by instruction '" + instruction + "'") label_text = "Enter the register expression(s) you want to track" \ - "\nRegister names should start with a '$' sign" \ - "\nEach expression should be separated with a comma" \ + "\nRegister names must start with $" \ + "\nEach expression must be separated with a comma" \ "\n\nFor instance:" \ - "\nLet's say the instruction is 'mov [rax+rbx],30'" \ - "\nThen you should enter '$rax+$rbx'(without quotes)" \ + "\nLet's say the instruction is mov [rax+rbx],30" \ + "\nThen you should enter $rax+$rbx" \ "\nSo PINCE can track address [rax+rbx]" \ "\n\nAnother example:" \ - "\nIf you enter '$rax,$rbx*$rcx+4,$rbp'(without quotes)" \ + "\nIf you enter $rax,$rbx*$rcx+4,$rbp" \ "\nPINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]" register_expression_dialog = InputDialogForm(item_list=[(label_text, "")]) if register_expression_dialog.exec(): @@ -4795,8 +4795,8 @@ def tableWidget_SymbolInfo_item_double_clicked(self, index): def pushButton_Help_clicked(self): text = "\tHere's some useful regex tips:" \ - "\n'^string' searches for everything that starts with 'string'" \ - "\n'[ab]cd' searches for both 'acd' and 'bcd'" \ + "\n^quaso --> search for everything that starts with quaso" \ + "\n[ab]cd --> search for both acd and bcd" \ "\n\n\tHow to interpret symbols:" \ "\nA symbol that looks like 'func(param)@plt' consists of 3 pieces" \ "\nfunc, func(param), func(param)@plt" \ @@ -5312,10 +5312,10 @@ def apply_data(self, disas_data): def pushButton_Help_clicked(self): text = "\tHere's some useful regex examples:" \ - "\n'call|rax' searches for opcodes that contain 'call' or 'rax'" \ - "\n'[re]cx' searches for both 'rcx' and 'ecx'" \ - "\nUse the char '\\' to escape special chars such as '['" \ - "\n'\[rsp\]' searches for opcodes that contain '[rsp]'" + "\ncall|rax --> search for opcodes that contain call or rax" \ + "\n[re]cx --> search for both rcx and ecx" \ + "\nUse the char \\ to escape special chars such as [" \ + "\n\[rsp\] --> search for opcodes that contain [rsp]" InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() From ba87538ec7f874e7217835f83e8bb6b61107caf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 22 May 2023 21:48:12 +0300 Subject: [PATCH 175/487] Fix TrackBreakpointWidget when cancelled --- PINCE.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/PINCE.py b/PINCE.py index b0322a6a..f0245af0 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3755,8 +3755,21 @@ def exec_track_breakpoint_dialog(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_instruction = self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() - track_breakpoint_widget = TrackBreakpointWidgetForm(current_address, current_instruction, self) - track_breakpoint_widget.show() + label_text = "Enter the register expression(s) you want to track" \ + "\nRegister names must start with $" \ + "\nEach expression must be separated with a comma" \ + "\n\nFor instance:" \ + "\nLet's say the instruction is mov [rax+rbx],30" \ + "\nThen you should enter $rax+$rbx" \ + "\nSo PINCE can track address [rax+rbx]" \ + "\n\nAnother example:" \ + "\nIf you enter $rax,$rbx*$rcx+4,$rbp" \ + "\nPINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]" + register_expression_dialog = InputDialogForm(item_list=[(label_text, "")]) + if register_expression_dialog.exec(): + exp = register_expression_dialog.get_values() + track_breakpoint_widget = TrackBreakpointWidgetForm(current_address, current_instruction, exp, self) + track_breakpoint_widget.show() def exec_disassemble_go_to_dialog(self): if GDB_Engine.currentpid == -1: @@ -4386,7 +4399,7 @@ def closeEvent(self, QCloseEvent): class TrackBreakpointWidgetForm(QWidget, TrackBreakpointWidget): - def __init__(self, address, instruction, parent=None): + def __init__(self, address, instruction, register_expressions, parent=None): super().__init__() self.setupUi(self) self.parent = lambda: parent @@ -4395,27 +4408,13 @@ def __init__(self, address, instruction, parent=None): self.setWindowFlags(Qt.WindowType.Window) GuiUtils.center_to_parent(self) self.setWindowTitle("Addresses accessed by instruction '" + instruction + "'") - label_text = "Enter the register expression(s) you want to track" \ - "\nRegister names must start with $" \ - "\nEach expression must be separated with a comma" \ - "\n\nFor instance:" \ - "\nLet's say the instruction is mov [rax+rbx],30" \ - "\nThen you should enter $rax+$rbx" \ - "\nSo PINCE can track address [rax+rbx]" \ - "\n\nAnother example:" \ - "\nIf you enter $rax,$rbx*$rcx+4,$rbp" \ - "\nPINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]" - register_expression_dialog = InputDialogForm(item_list=[(label_text, "")]) - if register_expression_dialog.exec(): - register_expressions = register_expression_dialog.get_values() - else: - return breakpoint = GDB_Engine.track_breakpoint(address, register_expressions) if not breakpoint: QMessageBox.information(self, "Error", "Unable to track breakpoint at expression " + address) return self.label_Info.setText("Pause the process to refresh 'Value' part of the table(" + - Hotkeys.pause_hotkey.get_active_key() + " or " + Hotkeys.break_hotkey.get_active_key() + ")") + Hotkeys.pause_hotkey.get_active_key() + " or " + + Hotkeys.break_hotkey.get_active_key() + ")") self.address = address self.breakpoint = breakpoint self.info = {} From 68123b58b761ed643a97bd9cca99bd77075865e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 24 May 2023 00:10:01 +0300 Subject: [PATCH 176/487] Fix ps and maps regexes --- libpince/SysUtils.py | 12 ++++++++++-- libpince/common_regexes.py | 6 +++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 410259df..8c0aa7bb 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -30,7 +30,12 @@ def get_process_list(): Returns: list: List of (pid, user, process_name) -> (str, str, str) """ - return common_regexes.ps.findall(os.popen("ps -eo pid,user,comm").read()) + process_list = [] + for line in os.popen("ps -eo pid,user,comm").read().splitlines(): + info = common_regexes.ps.match(line) + if info: + process_list.append(common_regexes.ps.match(line).groups()) + return process_list #:tag:Processes @@ -75,7 +80,10 @@ def get_regions(pid): list: List of (start_address, end_address, permissions, map_offset, device_node, inode, path) -> all str """ with open("/proc/"+str(pid)+"/maps") as f: - return common_regexes.maps.findall(f.read()) + regions = [] + for line in f.read().splitlines(): + regions.append(common_regexes.maps.match(line).groups()) + return regions # :tag:Processes diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index bc6f5abd..80d9e658 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -50,9 +50,9 @@ docstring_function_or_variable = compile(r"def\s+(\w+)|" + docstring_variable.pattern) whitespaces = compile(r"\s+") ps = compile(r""" - (\d+)\s+ # PID + \s+(\d+)\s+ # PID (\S+)\s+ # Username - (.*)\s+ # Process name + (.*)$ # Process name """, VERBOSE) maps = compile(r""" ([0-9a-f]+)-([0-9a-f]+)\s+ # Address (start-end) @@ -60,7 +60,7 @@ ([0-9a-f]+)\s+ # Map offset (\S+)\s+ # Device node (\d+)\s+ # Inode - (.*)\s+ # Pathname + (.*)$ # Pathname """, VERBOSE) # --------------------------------------------GuiUtils------------------------------------------------------------------ From cb53e26abf46765f51802ecfff795b6cb4fefd77 Mon Sep 17 00:00:00 2001 From: detiam Date: Wed, 24 May 2023 16:33:34 +0800 Subject: [PATCH 177/487] fix failed to open url in some cases --- libpince/SysUtils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 8c0aa7bb..ad478178 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -817,7 +817,7 @@ def execute_shell_command_as_user(command): command (str): Command that'll be invoked from the shell """ uid, gid = get_user_ids() - os.system("sudo -u '#" + uid + "' " + command) + os.system("sudo -Eu '#" + uid + "' " + command) #:tag:Utilities From 511a5beb46569302bc8d5c4519562aa4aa56298e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 24 May 2023 12:15:52 +0300 Subject: [PATCH 178/487] Close trace window when prompt gets cancelled --- PINCE.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index f0245af0..bf5dd3b9 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2710,8 +2710,7 @@ def initialize_hex_view(self): def show_trace_window(self): if GDB_Engine.currentpid == -1: return - trace_instructions_window = TraceInstructionsWindowForm(prompt_dialog=False) - trace_instructions_window.showMaximized() + TraceInstructionsWindowForm(prompt_dialog=False) def step_instruction(self): if GDB_Engine.currentpid == -1: @@ -3745,8 +3744,7 @@ def exec_trace_instructions_dialog(self): selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) - trace_instructions_window = TraceInstructionsWindowForm(current_address, parent=self) - trace_instructions_window.showMaximized() + TraceInstructionsWindowForm(current_address, parent=self) def exec_track_breakpoint_dialog(self): if GDB_Engine.currentpid == -1: @@ -4604,11 +4602,15 @@ def __init__(self, address="", prompt_dialog=True, parent=None): breakpoint = GDB_Engine.trace_instructions(*params) if not breakpoint: QMessageBox.information(self, "Error", "Failed to set breakpoint at address " + address) + self.close() return + self.showMaximized() self.breakpoint = breakpoint self.wait_dialog = TraceInstructionsWaitWidgetForm(address, breakpoint, self) self.wait_dialog.widget_closed.connect(self.show_trace_info) self.wait_dialog.show() + else: + self.close() def display_collected_data(self, QTreeWidgetItem_current): self.textBrowser_RegisterInfo.clear() From b496a8ec5c73ba9d828e72ef0ebe70eae179545c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 26 May 2023 23:35:21 +0300 Subject: [PATCH 179/487] Change scanmem url --- .gitmodules | 2 +- README.md | 2 +- install_pince.sh | 4 ++-- scanmem | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index 1f513c4c..979d6037 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "scanmem"] path = scanmem - url = https://github.com/scanmem/scanmem.git + url = https://github.com/brkzlr/scanmem-PINCE diff --git a/README.md b/README.md index 9515d50f..75d27c6a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Pre-release screenshots: ![pince9](https://user-images.githubusercontent.com/5638719/219640522-85cac1a9-e425-4b4f-abeb-a61104caa618.png) # Features -- **Memory searching:** PINCE uses [libscanmem](https://github.com/scanmem/scanmem) to search the memory efficiently **[Done]** +- **Memory searching:** PINCE uses a specialized fork of [libscanmem](https://github.com/brkzlr/scanmem-PINCE) to search the memory efficiently **[Done]** - **Variable Inspection&Modification** **[Done/Basic]** * **CheatEngine-like value type support:** Currently supports all types of CE and scanmem along with extended strings(utf-8, utf-16, utf-32) **[Done]** * **Symbol Recognition:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) **[Done]** diff --git a/install_pince.sh b/install_pince.sh index 2107ce1c..58e45444 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -66,8 +66,8 @@ install_scanmem() { compile_scanmem || return 1 fi cp --preserve .libs/libscanmem.so ../libpince/libscanmem/ - cp --preserve gui/scanmem.py ../libpince/libscanmem - cp --preserve gui/misc.py ../libpince/libscanmem + cp --preserve wrappers/scanmem.py ../libpince/libscanmem + cp --preserve wrappers/misc.py ../libpince/libscanmem echo "Exiting scanmem" ) || return 1 # required for relative import, since it will throw an import error if it's just `import misc` diff --git a/scanmem b/scanmem index ac32e5d7..6589a87a 160000 --- a/scanmem +++ b/scanmem @@ -1 +1 @@ -Subproject commit ac32e5d7d7429ec2123c5ff63559bc9ad37b4f09 +Subproject commit 6589a87af742a83fe7ca3646d7f3da307715a545 From 527ea3ef6fb92eb528f27b295e115ba8a35aeaac Mon Sep 17 00:00:00 2001 From: ofcaah Date: Sun, 28 May 2023 20:54:01 +0200 Subject: [PATCH 180/487] Update SysUtils.py due to regex used to validate a line returned by ps -eo, each line that doesn't begin with blank char is ignored. This results in processes with PID higher than 999999 to be ignored and not listed in process selector. This trivial change works around the problem by forcing PID column in ps output to always be 11 characters wide. --- libpince/SysUtils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index ad478178..d3d7d2c6 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -31,7 +31,7 @@ def get_process_list(): list: List of (pid, user, process_name) -> (str, str, str) """ process_list = [] - for line in os.popen("ps -eo pid,user,comm").read().splitlines(): + for line in os.popen("ps -eo pid:11,user,comm").read().splitlines(): info = common_regexes.ps.match(line) if info: process_list.append(common_regexes.ps.match(line).groups()) From ad35aaf14468d6b62afe0ab5130d383aedaeaac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 31 May 2023 20:40:32 +0300 Subject: [PATCH 181/487] Implement undo scan --- PINCE.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index bf5dd3b9..40877512 100755 --- a/PINCE.py +++ b/PINCE.py @@ -362,11 +362,7 @@ def run(self): self.process_running.emit() -# TODO undo scan, we would probably need to make some data structure we -# could pass to scanmem which then would set the current matches -# the mainwindow class MainForm(QMainWindow, MainWindow): - def __init__(self): """ Declare regular expressions for hexadecimal and decimal input @@ -435,6 +431,7 @@ def __init__(self): libscanmem_path = os.path.join(os.getcwd(), "libpince", "libscanmem", "libscanmem.so") self.backend = Scanmem(libscanmem_path) self.backend.send_command("option noptrace 1") + self.backend.send_command("option undo_limit 5") self.memory_view_window = MemoryViewWindowForm(self) self.about_widget = AboutWidgetForm() self.await_exit_thread = AwaitProcessExit() @@ -467,6 +464,7 @@ def __init__(self): self.pushButton_Open.clicked.connect(self.pushButton_Open_clicked) self.pushButton_Save.clicked.connect(self.pushButton_Save_clicked) self.pushButton_NewFirstScan.clicked.connect(self.pushButton_NewFirstScan_clicked) + self.pushButton_UndoScan.clicked.connect(self.pushButton_UndoScan_clicked) self.pushButton_NextScan.clicked.connect(self.pushButton_NextScan_clicked) self.scan_mode = type_defs.SCAN_MODE.NEW self.pushButton_NewFirstScan_clicked() @@ -1033,14 +1031,17 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_NewFirstScan.setText("New Scan") self.comboBox_ValueType.setEnabled(False) self.pushButton_NextScan.setEnabled(True) + self.pushButton_UndoScan.setEnabled(True) search_scope = self.comboBox_ScanScope.currentData(Qt.ItemDataRole.UserRole) self.backend.send_command("option region_scan_level " + str(search_scope)) self.backend.send_command("reset") self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan - self.comboBox_ScanType_init() + def pushButton_UndoScan_clicked(self): + self.pushButton_NextScan_clicked("undo") + def comboBox_ScanType_current_index_changed(self): hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, type_defs.SCAN_TYPE.UNCHANGED, type_defs.SCAN_TYPE.UNKNOWN] @@ -1118,11 +1119,12 @@ def validate_search(self, search_for, search_for2): return cmp_symbols[type_index] + " " + search_for return search_for - def pushButton_NextScan_clicked(self): + def pushButton_NextScan_clicked(self, search_for=None): if GDB_Engine.currentpid == -1: return global ProgressRun - search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) + if not search_for: + search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) # ProgressBar global threadpool @@ -1301,8 +1303,9 @@ def reset_scan(self): self.backend.send_command("reset") self.tableWidget_valuesearchtable.setRowCount(0) self.comboBox_ValueType.setEnabled(True) - self.pushButton_NextScan.setEnabled(False) self.comboBox_ScanScope.setEnabled(True) + self.pushButton_NextScan.setEnabled(False) + self.pushButton_UndoScan.setEnabled(False) self.progressBar.setValue(0) self.label_MatchCount.setText("Match count: 0") From 13a80988e25cb09b2658d0832f24fd9a95fdd8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 2 Jun 2023 23:03:21 +0300 Subject: [PATCH 182/487] Implement single line injection --- GUI/EditInstructionDialog.py | 9 ++-- GUI/EditInstructionDialog.ui | 9 ++-- PINCE.py | 96 +++++++++++++++++++----------------- install_pince.sh | 2 +- libpince/SysUtils.py | 32 +++++++++++- 5 files changed, 90 insertions(+), 58 deletions(-) diff --git a/GUI/EditInstructionDialog.py b/GUI/EditInstructionDialog.py index fce254b2..a2024439 100644 --- a/GUI/EditInstructionDialog.py +++ b/GUI/EditInstructionDialog.py @@ -17,9 +17,9 @@ def setupUi(self, Dialog): Dialog.setMaximumSize(QtCore.QSize(16777215, 124)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") - self.lineEdit_OpCodes = QtWidgets.QLineEdit(Dialog) - self.lineEdit_OpCodes.setObjectName("lineEdit_OpCodes") - self.gridLayout.addWidget(self.lineEdit_OpCodes, 1, 0, 1, 1) + self.lineEdit_Bytes = QtWidgets.QLineEdit(Dialog) + self.lineEdit_Bytes.setObjectName("lineEdit_Bytes") + self.gridLayout.addWidget(self.lineEdit_Bytes, 1, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -40,8 +40,6 @@ def setupUi(self, Dialog): self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) self.lineEdit_Instruction = QtWidgets.QLineEdit(Dialog) - self.lineEdit_Instruction.setEnabled(False) - self.lineEdit_Instruction.setReadOnly(True) self.lineEdit_Instruction.setObjectName("lineEdit_Instruction") self.horizontalLayout.addWidget(self.lineEdit_Instruction) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) @@ -56,3 +54,4 @@ def retranslateUi(self, Dialog): Dialog.setWindowTitle(_translate("Dialog", "Edit Instruction")) self.label.setText(_translate("Dialog", "Address:")) self.label_2.setText(_translate("Dialog", "Instruction:")) + self.lineEdit_Instruction.setToolTip(_translate("Dialog", "Multiple entries are separated with ;")) diff --git a/GUI/EditInstructionDialog.ui b/GUI/EditInstructionDialog.ui index fedf26cf..a1376f0e 100644 --- a/GUI/EditInstructionDialog.ui +++ b/GUI/EditInstructionDialog.ui @@ -24,7 +24,7 @@ - + @@ -67,11 +67,8 @@ - - false - - - true + + Multiple entries are separated with ; diff --git a/PINCE.py b/PINCE.py index 40877512..37c0be64 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2749,8 +2749,8 @@ def edit_instruction(self): selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) - opcode = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() - EditInstructionDialogForm(current_address, opcode, self).exec() + bytes_aob = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() + EditInstructionDialogForm(current_address, bytes_aob, self).exec() def nop_instruction(self): if GDB_Engine.currentpid == -1: @@ -4135,6 +4135,8 @@ def refresh(self): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) instr_name = SysUtils.get_opcode_name(address, aob, GDB_Engine.get_inferior_arch()) + if not instr_name: + instr_name = "??" self.tableWidget_Instructions.setItem(row, INSTR_NAME_COL, QTableWidgetItem(instr_name)) GuiUtils.resize_to_contents(self.tableWidget_Instructions) @@ -4817,52 +4819,48 @@ def closeEvent(self, QCloseEvent): class EditInstructionDialogForm(QDialog, EditInstructionDialog): - def __init__(self, address, opcode, parent=None): + def __init__(self, address, bytes_aob, parent=None): super().__init__(parent=parent) self.setupUi(self) - self.orig_opcode = opcode - self.orig_instr = SysUtils.get_opcode_name(int(address, 0), opcode, GDB_Engine.get_inferior_arch()) - self.is_valid = False - self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) + self.orig_bytes = bytes_aob self.lineEdit_Address.setText(address) - self.lineEdit_OpCodes.setText(opcode) - self.lineEdit_Instruction.setText(self.orig_instr) - self.lineEdit_OpCodes.textEdited.connect(self.lineEdit_OpCodes_text_edited) - - def set_not_valid(self, instruction, is_original_opcode): - if is_original_opcode: - self.lineEdit_OpCodes.setStyleSheet("") + self.lineEdit_Bytes.setText(bytes_aob) + self.lineEdit_Bytes_text_edited() + self.lineEdit_Bytes.textEdited.connect(self.lineEdit_Bytes_text_edited) + self.lineEdit_Instruction.textEdited.connect(self.lineEdit_Instruction_text_edited) + + def set_valid(self, valid): + if valid: + self.is_valid = True + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True) else: - self.lineEdit_OpCodes.setStyleSheet("QLineEdit {background-color: red;}") - self.lineEdit_Instruction.setText(instruction) - self.is_valid = False - self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) - - def lineEdit_OpCodes_text_edited(self): - aob_string = self.lineEdit_OpCodes.text() - if not SysUtils.parse_string(aob_string, type_defs.VALUE_INDEX.INDEX_AOB): - self.set_not_valid("???", False) - return - - if len(aob_string) != len(self.orig_opcode): - self.set_not_valid("???", False) - return - - if aob_string == self.orig_opcode: - self.set_not_valid(self.orig_instr, True) - return - - self.lineEdit_OpCodes.setStyleSheet("") - self.is_valid = True - self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True) - self.refresh_view() + self.is_valid = False + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) + + def lineEdit_Bytes_text_edited(self): + bytes_aob = self.lineEdit_Bytes.text() + if SysUtils.parse_string(bytes_aob, type_defs.VALUE_INDEX.INDEX_AOB): + address = int(self.lineEdit_Address.text(), 0) + instruction = SysUtils.get_opcode_name(address, bytes_aob, GDB_Engine.inferior_arch) + if instruction: + self.set_valid(True) + self.lineEdit_Instruction.setText(instruction) + return + self.set_valid(False) + self.lineEdit_Instruction.setText("??") - def refresh_view(self): - self.lineEdit_Instruction.clear() + def lineEdit_Instruction_text_edited(self): + instruction = self.lineEdit_Instruction.text() address = int(self.lineEdit_Address.text(), 0) - opcode = self.lineEdit_OpCodes.text() - instr_str = SysUtils.get_opcode_name(address, opcode, GDB_Engine.get_inferior_arch()) - self.lineEdit_Instruction.setText(instr_str) + result = SysUtils.assemble(instruction, address, GDB_Engine.inferior_arch) + if result: + byte_list = result[0] + self.set_valid(True) + bytes_str = " ".join([format(num, '02x') for num in byte_list]) + self.lineEdit_Bytes.setText(bytes_str) + else: + self.set_valid(False) + self.lineEdit_Bytes.setText("??") def accept(self): if not self.is_valid: @@ -4870,8 +4868,18 @@ def accept(self): # No need to check for validity since address is not editable and opcode is checked in text_edited address = int(self.lineEdit_Address.text(), 0) - opcode = self.lineEdit_OpCodes.text() - GDB_Engine.modify_instruction(address, opcode) + bytes_aob = self.lineEdit_Bytes.text() + if bytes_aob != self.orig_bytes: + new_length = len(bytes_aob.split()) + old_length = len(self.orig_bytes.split()) + if new_length < old_length: + bytes_aob += " 90"*(old_length-new_length) # Append NOPs if we are short on bytes + elif new_length > old_length: + if not InputDialogForm( + item_list=[("New opcode is " + str(new_length) + " bytes long but old opcode is only " + + str(old_length) + " bytes long\nThis will cause an overflow, proceed?",)]).exec(): + return + GDB_Engine.modify_instruction(address, bytes_aob) self.parent().refresh_hex_view() self.parent().refresh_disassemble_view() super(EditInstructionDialogForm, self).accept() diff --git a/install_pince.sh b/install_pince.sh index 58e45444..0505f6f3 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -115,7 +115,7 @@ PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-co PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays -PKG_NAMES_PIP="pyqt6 pexpect distorm3 pygdbmi keyboard pygobject" +PKG_NAMES_PIP="pyqt6 pexpect distorm3 keystone-engine pygdbmi keyboard pygobject" INSTALL_COMMAND="install" diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index d3d7d2c6..1a24af53 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -18,10 +18,14 @@ import os, shutil, sys, binascii, pickle, json, traceback, re, pwd, pathlib, distorm3 from . import type_defs, common_regexes +from keystone import Ks, KsError, KS_ARCH_X86, KS_MODE_32, KS_MODE_64 from collections import OrderedDict from importlib.machinery import SourceFileLoader from pygdbmi import gdbmiparser +# Keystone initialization +ks_32 = Ks(KS_ARCH_X86, KS_MODE_32) +ks_64 = Ks(KS_ARCH_X86, KS_MODE_64) #:tag:Processes def get_process_list(): @@ -86,7 +90,7 @@ def get_regions(pid): return regions -# :tag:Processes +#:tag:Processes def get_region_set(pid): """Returns memory regions of a process, removes path duplicates and empty paths @@ -682,6 +686,7 @@ def get_opcode_name(address, opcode_aob, arch_type): Returns: str: Assembly instruction name that decodes to the supplied OpCode + None: If there was an error """ if arch_type == type_defs.INFERIOR_ARCH.ARCH_64: disas_option = distorm3.Decode64Bits @@ -690,11 +695,33 @@ def get_opcode_name(address, opcode_aob, arch_type): try: bytecode = bytes.fromhex(opcode_aob.replace(" ", "")) except ValueError: - return "???" + return disas_data = distorm3.Decode(address, bytecode, disas_option) return disas_data[0][2] +#:tag:Utilities +def assemble(instructions, address, inferior_arch): + """Assembles the given instructions + + Args: + instructions (str): A string of instructions, multiple entries separated by ; + address (int): Address of the instruction + inferior_arch (int): Can be a member of type_defs.INFERIOR_ARCH + + Returns: + tuple: A tuple of (list, int) --> Assembled bytes (list of int) and instruction count (int) + None: If there was an error + """ + try: + if inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64: + return ks_64.asm(instructions, address) + else: + return ks_32.asm(instructions, address) + except KsError as e: + print(e) + + #:tag:ValueType def aob_to_str(list_of_bytes, encoding="ascii"): """Converts given array of hex strings to str @@ -742,6 +769,7 @@ def aob_to_str(list_of_bytes, encoding="ascii"): hexBytes=bytes.fromhex(hexString) return hexBytes.decode(encoding, "surrogateescape") + #:tag:ValueType def str_to_aob(string, encoding="ascii"): """Converts given string to aob string From a2bdb04799e1a139891ce9a98ba4fdfd1df095cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 3 Jun 2023 00:23:22 +0300 Subject: [PATCH 183/487] Support multiple instructions with get_opcodes --- PINCE.py | 4 ++-- libpince/SysUtils.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/PINCE.py b/PINCE.py index 37c0be64..8da1ffdb 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4134,7 +4134,7 @@ def refresh(self): for row, (address, aob) in enumerate(modified_instructions.items()): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) - instr_name = SysUtils.get_opcode_name(address, aob, GDB_Engine.get_inferior_arch()) + instr_name = SysUtils.get_opcodes(address, aob, GDB_Engine.get_inferior_arch()) if not instr_name: instr_name = "??" self.tableWidget_Instructions.setItem(row, INSTR_NAME_COL, QTableWidgetItem(instr_name)) @@ -4841,7 +4841,7 @@ def lineEdit_Bytes_text_edited(self): bytes_aob = self.lineEdit_Bytes.text() if SysUtils.parse_string(bytes_aob, type_defs.VALUE_INDEX.INDEX_AOB): address = int(self.lineEdit_Address.text(), 0) - instruction = SysUtils.get_opcode_name(address, bytes_aob, GDB_Engine.inferior_arch) + instruction = SysUtils.get_opcodes(address, bytes_aob, GDB_Engine.inferior_arch) if instruction: self.set_valid(True) self.lineEdit_Instruction.setText(instruction) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 1a24af53..a85c7c19 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -676,28 +676,28 @@ def modulo_address(int_address, arch_type): #:tag:Utilities -def get_opcode_name(address, opcode_aob, arch_type): - """Returns the instruction name from the opcode +def get_opcodes(address, aob, inferior_arch): + """Returns the instructions from the given array of bytes Args: address (int): The address where the opcode starts from - opcode_aob (str): String that contains an opcode written as an array of bytes - arch_type (int): Architecture type (x86, x64). Can be a member of type_defs.INFERIOR_ARCH + aob (str): Bytes of the opcode as an array of bytes + inferior_arch (int): Architecture type (x86, x64). Can be a member of type_defs.INFERIOR_ARCH Returns: - str: Assembly instruction name that decodes to the supplied OpCode + str: Opcodes, multiple entries are separated with ; None: If there was an error """ - if arch_type == type_defs.INFERIOR_ARCH.ARCH_64: + if inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64: disas_option = distorm3.Decode64Bits - elif arch_type == type_defs.INFERIOR_ARCH.ARCH_32: + elif inferior_arch == type_defs.INFERIOR_ARCH.ARCH_32: disas_option = distorm3.Decode32Bits try: - bytecode = bytes.fromhex(opcode_aob.replace(" ", "")) + bytecode = bytes.fromhex(aob.replace(" ", "")) except ValueError: return disas_data = distorm3.Decode(address, bytecode, disas_option) - return disas_data[0][2] + return "; ".join([data[2] for data in disas_data]) #:tag:Utilities From f95e7c8084d5e7b05ee7b87d03fbee9970db7df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 3 Jun 2023 01:10:45 +0300 Subject: [PATCH 184/487] Update README.md --- README.md | 78 +++++++++++++++++++++---------------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 75d27c6a..69c43093 100644 --- a/README.md +++ b/README.md @@ -25,41 +25,39 @@ Pre-release screenshots: ![pince9](https://user-images.githubusercontent.com/5638719/219640522-85cac1a9-e425-4b4f-abeb-a61104caa618.png) # Features -- **Memory searching:** PINCE uses a specialized fork of [libscanmem](https://github.com/brkzlr/scanmem-PINCE) to search the memory efficiently **[Done]** -- **Variable Inspection&Modification** **[Done/Basic]** - * **CheatEngine-like value type support:** Currently supports all types of CE and scanmem along with extended strings(utf-8, utf-16, utf-32) **[Done]** - * **Symbol Recognition:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) **[Done]** - * **Automatic Variable Allocation:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) **[Done]** - * **Dynamic Address Table:** Supports drag&drop, recursive copy&pasting&inserting and many more **[Done]** - * **Smart casting:** PINCE lets you modify multiple different-type values together as long as the input is parsable. All parsing/memory errors are directed to the terminal **[Done]** - * **Continuous Address Table Update:** You can adjust update timer or cancel updating by modifying settings **[Done]** - * **Variable Locking:** PINCE lets you freeze(constantly write a value to memory cell) variables **[Done]** -- **Memory View** **[Done/Basic]** - * **Infinite Scrolling:** PINCE automatically disassembles the next available instruction(s) on mouse wheel/scrollbar move. Instruction count can be changed from settings. Hex View also supports this feature **[Done]** - * **Dissect Code:** You can dissect desired memory regions to find referenced calls, jumps and strings. Disassemble screen will automatically handle the referenced data and show you if there's a referenced address in the current dissasemble view. It can be used from Tools->Dissect Code in the MemoryView window. Using its hotkey instead in the MemoryView window automatically dissects the currently viewed region. You can separately view referenced calls and strings after the search from View->Referenced Calls/Strings. *Note: If you decide to uncheck 'Discard invalid strings' before the search, PINCE will try to search for regular pointers as well* **[Done]** - * **Bookmarking:** Bookmark menu is dynamically created when right clicked in the disassemble screen. So unlike Cheat Engine, PINCE lets you set unlimited number of bookmarks. List of bookmarks can also be viewed from View->Bookmarks in the MemoryView window. Commenting on an address automatically bookmarks it. **[Done]** - * **Modify on the fly:** PINCE lets you modify registers on the fly. Check [GDB expressions in the Wiki page](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) for additional information **[Done]** - * **Opcode Search:** You can search opcodes with python regular expressions. To use this feature, click Tools->Search Opcode in the MemoryView window. **[Done]** -- **Debugging** **[Done/Basic]** +- **Memory searching:** PINCE uses a specialized fork of [libscanmem](https://github.com/brkzlr/scanmem-PINCE) to search the memory efficiently +- **Variable Inspection&Modification** + * **CheatEngine-like value type support:** Currently supports all types of CE and scanmem along with extended strings(utf-8, utf-16, utf-32) + * **Symbol Recognition:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) + * **Automatic Variable Allocation:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) + * **Dynamic Address Table:** Supports drag&drop, recursive copy&pasting&inserting and many more + * **Smart casting:** PINCE lets you modify multiple different-type values together as long as the input is parsable. All parsing/memory errors are directed to the terminal + * **Continuous Address Table Update:** You can adjust update timer or cancel updating by modifying settings + * **Variable Locking:** PINCE lets you freeze(constantly write a value to memory cell) variables +- **Memory View** + * **Assembler:** PINCE uses keystone engine to assemble code on the fly + * **Dissect Code:** You can dissect desired memory regions to find referenced calls, jumps and strings. Disassemble screen will automatically handle the referenced data and show you if there's a referenced address in the current dissasemble view. It can be used from Tools->Dissect Code in the MemoryView window. Using its hotkey instead in the MemoryView window automatically dissects the currently viewed region. You can separately view referenced calls and strings after the search from View->Referenced Calls/Strings. *Note: If you decide to uncheck 'Discard invalid strings' before the search, PINCE will try to search for regular pointers as well* + * **Bookmarking:** Bookmark menu is dynamically created when right clicked in the disassemble screen. So unlike Cheat Engine, PINCE lets you set unlimited number of bookmarks. List of bookmarks can also be viewed from View->Bookmarks in the MemoryView window. Commenting on an address automatically bookmarks it + * **Modify on the fly:** PINCE lets you modify registers on the fly. Check [GDB expressions in the Wiki page](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) for additional information + * **Opcode Search:** You can search opcodes with python regular expressions. To use this feature, click Tools->Search Opcode in the MemoryView window +- **Debugging** * Has basic debugging features such as stepping, stepping over, execute till return, break, continue. Also has breakpoints, watchpoints and breakpoint conditions. Has advanced debugging utilities such as Watchpoint/Breakpoint Tracking and Tracing - * **Chained Breakpoints:** Just like CE, PINCE allows you to set multiple, connected breakpoints at once. If an event(such as condition modification or deletion) happens in one of the breakpoints, other connected breakpoints will get affected as well **[Done]** - * **Watchpoint Tracking:** Allows you to see which instructions have been accessing to the specified address, just like "What accesses/writes to this address" feature in CE **[Done]** - * **Breakpoint Tracking:** Allows you to track down addresses calculated by the given register expressions at the specified instruction, just like "Find out what addresses this instruction accesses" feature in CE with a little addon, you can enter multiple register expressions, this allows you to check the value of "esi" even if the instruction is something irrelevant like "mov [eax],edx" **[Done]** - * **Tracing:** Almost the same with CE. But unlike CE, you can stop tracing whenever you want. Created from scratch with shittons of custom features instead of using gdb's trace&collect commands because some people have too much time on their hands **[Done]** - * **Collision Detection:** GDB normally permits setting unlimited watchpoints next to each other. But this behaviour leads to unexpected outcomes such as causing GDB or the inferior become completely inoperable. GDB also doesn't care about the number(max 4) or the size(x86->max 4, x64->max 8) of hardware breakpoints. Fortunately, PINCE checks for these problems whenever you set a new breakpoint and detects them before they happen and then inhibits them in a smart way. Lets say you want to set a breakpoint in the size of 32 bytes. But the maximum size for a breakpoint is 8! So, PINCE creates 4 different breakpoints with the size of 8 bytes and then chains them for future actions **[Done]** -- **Code Injection** **[Working on it]** - * **Run-time injection:** Only .so injection is supported for now. In Memory View window, click Tools->Inject .so file to select the .so file. An example for creating .so file can be found in "libpince/Injection/". PINCE will be able to inject single line instructions or code caves in near future **[Partially Done?]** -- **GDB Console** **[Done]** + * **Chained Breakpoints:** Just like CE, PINCE allows you to set multiple, connected breakpoints at once. If an event(such as condition modification or deletion) happens in one of the breakpoints, other connected breakpoints will get affected as well + * **Watchpoint Tracking:** Allows you to see which instructions have been accessing to the specified address, just like "What accesses/writes to this address" feature in CE + * **Breakpoint Tracking:** Allows you to track down addresses calculated by the given register expressions at the specified instruction, just like "Find out what addresses this instruction accesses" feature in CE with a little addon, you can enter multiple register expressions, this allows you to check the value of "esi" even if the instruction is something irrelevant like "mov [eax],edx" + * **Tracing:** Almost the same with CE. But unlike CE, you can stop tracing whenever you want. Created from scratch with shittons of custom features instead of using gdb's trace&collect commands because some people have too much time on their hands + * **Collision Detection:** GDB normally permits setting unlimited watchpoints next to each other. But this behaviour leads to unexpected outcomes such as causing GDB or the inferior become completely inoperable. GDB also doesn't care about the number(max 4) or the size(x86->max 4, x64->max 8) of hardware breakpoints. Fortunately, PINCE checks for these problems whenever you set a new breakpoint and detects them before they happen and then inhibits them in a smart way. Lets say you want to set a breakpoint in the size of 32 bytes. But the maximum size for a breakpoint is 8! So, PINCE creates 4 different breakpoints with the size of 8 bytes and then chains them for future actions +- **Code Injection** + * **Run-time injection:** Only .so injection is supported for now. In Memory View window, click Tools->Inject .so file to select the .so file. An example for creating .so file can be found in "libpince/Injection/". PINCE will be able to inject single line instructions or code caves in near future +- **GDB Console** * Is the power of PINCE not enough for you? Then you can use the gdb console provided by PINCE, it's on the top right in main window -- **Simplified/Optimized gdb command alternatives** **[Working on it]** - * Custom scripts instead of using gdb's x command for reading memory **[Done]** - * Custom scripts instead of using gdb's set command for modifying memory **[Done]** +- **Simplified/Optimized gdb command alternatives** + * Custom scripts instead of using gdb's x command for reading memory + * Custom scripts instead of using gdb's set command for modifying memory - **libpince - A reusable python library** * PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget is automatically generated by looking at the docstrings of the source files. PINCE has a unique parsing technique that allows parsing variables. Check the function get_variable_comments in SysUtils for the details. This feature might be replaced with Sphinx in the future - **Extendable with .so files at runtime** * See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) -- **Automatic Trainer Generation:** **[Planned]** - * PINCE provides a trainer auto-generated from current address table on demand by using libpince and PyQT6 together # Installing ``` @@ -85,18 +83,6 @@ sudo apt-get install qt6-tools-dev (designer and pyuic6) sudo pip3 install line_profiler (for performance testing) ``` How to use line_profiler: Add ```@profile``` tag to the desired function and run PINCE with ```sudo kernprof -l -v PINCE.py``` -# History -- A few weeks till 17/01/2016 : Learned GDB, process of analysis -- 17/01/2016-22/01/2016 : Basic design, grasping of Python3 and Pyqt6, proof-testing -- 22/01/2016 : First commit -- 19/02/2016 : Moved to Github from Bitbucket -- 25/02/2016 : First successful implementation of thread injection[Update-08/05/2016 : PINCE now uses ```linux-inject``` as a secondary injection method] -- 18/06/2016 : PINCE now supports all-stop mode instead of non-stop mode -- 21/06/2016 : Variable Inspection&Modification is finished(At basic level) -- 21/08/2016 : Memory View is finished(At basic level) -- 24/08/2016 : PINCE no more uses linux-inject because of stability issues(a fix for the [race conditions in the inferior](https://github.com/gaffe23/linux-inject/issues/7) would be nice) -- 26/12/2016 : Debugging is finished(At basic level) -- 19/05/2020 : libscanmem integration is complete, enjoy memory searching. Huge thanks to fisu, xk and 12345ieee (libscanmem team) # Current Roadmap - Refactor file naming conventions(decide on snake_case or camelCase for modules etc) @@ -110,8 +96,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - - Extend string types with LE and BE variants of UTF-16 and UTF-32 - - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others Array of Bytes - - Implement a custom combobox class for comboBox_ValueType and create a context menu for String_Others item -- Having to stop the process to resolve symbols sucks, we already resolve base addresses of libs by ourselves, try to replace this gdb functionality with something else, maybe the output of nm or manual parsing -- Indent docstrings properly like GDB_Engine.get_breakpoint_info does(independent from other steps) +- Having to stop the process to resolve symbols sucks, we already resolve base addresses of libs by ourselves, try to replace this gdb functionality with something else, like parsing from the memory - Implement "Investigate Registers" button to gather information about the addresses registers point to(independent from other steps) - Implement selectionChanged signal of lineEdit_HexView - Implement multi selection for HexView @@ -120,18 +105,14 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - Extend search_referenced_strings with relative search - Consider adding type guessing for the StackView(independent from other steps) - Move GUI classes of PINCE.py to their own files -- Handle signals and internal errors that causes gdb to halt, such as SIGSEGV and overlapping breakpoints(independent from other steps) - Use gdb python API breakpoints instead of breakpoint commands for optimization, also find a way to eliminate output coming from stepping commands such as ```stepi``` or ```nexti```(independent from other steps) - Implement a psuedo-terminal for the inferior like edb does(independent from other steps) - Implement libpince engine - Implement auto-ESP&aimbot (depends on libpince engine) - Try to optimize TrackBreakpoint and TrackWatchpoint return data structures further, adding an id field might simplify traversing of the tree, performance tests are required(independent from other steps) - Extend tagging system to PINCE GUI functions -- Implement inject_with_advanced_injection(independent from other steps) -- Implement single-line code injection -- Implement multi-line code injection +- Implement multi-line code injection, this will also help with previously dropped inject_with_advanced_injection - Break on/Catch signals and syscalls -- Move non-communication functions in GDB_Engine to ScriptUtils and create corresponding fields in GDB_Engine and GDBCommandExtensions automatically. This lets entire functionality of libpince to be used with both python scripts and gdb python scripts, thus allowing it to be used as a plugin for projects such as radare2 - Flowcharts based on disassembled output - Automatic function bypassing(make it return the desired value, hook specific parts etc.) - Implement speedhack(independent from other steps) @@ -144,7 +125,6 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - Implement extra MemoryViewerWindow tabs(independent from other steps) - ~~Consider removing the command file layer of IPC system for GDB_Engine.send_command to speed up things~~(independent from other steps)[Update-29/04/2018 : Delaying this until GDB/MI implements a native multiline command feature or improves ```interpreter-exec``` command to cover every single multiline command type(including ```define``` commands)] - Implement thread info widget -- Add ability to change logo and other assets if people contribute more than one asset per usage - Implement developer mode in settings. Developer mode will include features like dissection of GUI elements on events such as mouse-over(independent from other steps) - Add ability to include non-absolute calls for dissect code feature(i.e call rax). Should be considered after the first version release. Might be useful for multi-breakpoint related features - Implement toggling of arrows for easier navigation for dissected regions(independent from other steps) From fcbf70551c984bb81a74fc68f41917e9c3c6866a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 3 Jun 2023 23:14:03 +0300 Subject: [PATCH 185/487] Fix #189 --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index 0505f6f3..abefa095 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -25,7 +25,7 @@ if [ "$(id -u)" = "0" ]; then exit 1 fi -CURRENT_USER="$(who mom likes | awk '{print $1}')" +CURRENT_USER="$(whoami)" exit_on_error() { if [ "$?" -ne 0 ]; then From 027ec543b81864c428947a60a4a27f00869c69be Mon Sep 17 00:00:00 2001 From: salihmarangoz Date: Sat, 3 Jun 2023 03:01:04 +0200 Subject: [PATCH 186/487] Limit make jobs to 4 --- install_gdb.sh | 2 +- install_pince.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install_gdb.sh b/install_gdb.sh index d8b39f0c..7c6f766f 100755 --- a/install_gdb.sh +++ b/install_gdb.sh @@ -40,7 +40,7 @@ echo "Please install them manually for this to work, this issue will be addresse sudo apt-get install python3-dev libgmp3-dev -CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j MAKEINFO=true && sudo make -C gdb install +CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j4 MAKEINFO=true && sudo make -j4 -C gdb install if [ ! -e bin/gdb ] ; then echo "Failed to install GDB, restart the installation process" diff --git a/install_pince.sh b/install_pince.sh index abefa095..1668bbd2 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -40,7 +40,7 @@ exit_on_error() { compile_scanmem() { sh autogen.sh || return 1 ./configure --prefix="$(pwd)" || return 1 - make -j libscanmem.la || return 1 + make -j4 libscanmem.la || return 1 chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file return 0 } From a529d3863ea65897269220d78ce73b02a9247e1e Mon Sep 17 00:00:00 2001 From: salihmarangoz Date: Sat, 3 Jun 2023 23:01:34 +0200 Subject: [PATCH 187/487] Added a dynamical limit to number of jobs for make command --- install_gdb.sh | 15 +++++++++++++-- install_pince.sh | 13 ++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/install_gdb.sh b/install_gdb.sh index 7c6f766f..e90f0bcf 100755 --- a/install_gdb.sh +++ b/install_gdb.sh @@ -21,6 +21,17 @@ along with this program. If not, see . GDB_VERSION="gdb-11.2" +if [ -z "$NUM_MAKE_JOBS" ]; then + NUM_MAKE_JOBS=$(lscpu -p=core | uniq | awk '!/#/' | wc -l) + MAX_NUM_MAKE_JOBS=8 + if (( NUM_MAKE_JOBS > MAX_NUM_MAKE_JOBS )); then # set an upper limit to prevent Out-Of-Memory + NUM_MAKE_JOBS=$MAX_NUM_MAKE_JOBS + fi + if ! echo "$NUM_MAKE_JOBS" | grep -Eq '^[0-9]+$'; then # fallback + NUM_MAKE_JOBS=$MAX_NUM_MAKE_JOBS + fi +fi + mkdir -p gdb_pince cd gdb_pince || exit @@ -38,9 +49,9 @@ echo "-------------------------------------------------------------------------" echo "If you're not on debian or a similar distro with the 'apt' package manager the follow will not work if you don't have gcc and g++ installed" echo "Please install them manually for this to work, this issue will be addressed at a later date" -sudo apt-get install python3-dev libgmp3-dev +apt-get install python3-dev libgmp3-dev -CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j4 MAKEINFO=true && sudo make -j4 -C gdb install +CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j"$NUM_MAKE_JOBS" MAKEINFO=true && sudo make -C gdb install if [ ! -e bin/gdb ] ; then echo "Failed to install GDB, restart the installation process" diff --git a/install_pince.sh b/install_pince.sh index 1668bbd2..4405a3d9 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -27,6 +27,17 @@ fi CURRENT_USER="$(whoami)" +if [ -z "$NUM_MAKE_JOBS" ]; then + NUM_MAKE_JOBS=$(lscpu -p=core | uniq | awk '!/#/' | wc -l) + MAX_NUM_MAKE_JOBS=8 + if (( NUM_MAKE_JOBS > MAX_NUM_MAKE_JOBS )); then # set an upper limit to prevent Out-Of-Memory + NUM_MAKE_JOBS=$MAX_NUM_MAKE_JOBS + fi + if ! echo "$NUM_MAKE_JOBS" | grep -Eq '^[0-9]+$'; then # fallback + NUM_MAKE_JOBS=$MAX_NUM_MAKE_JOBS + fi +fi + exit_on_error() { if [ "$?" -ne 0 ]; then echo @@ -40,7 +51,7 @@ exit_on_error() { compile_scanmem() { sh autogen.sh || return 1 ./configure --prefix="$(pwd)" || return 1 - make -j4 libscanmem.la || return 1 + make -j"$NUM_MAKE_JOBS" libscanmem.la || return 1 chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file return 0 } From d56ee4031a5d67bf52fc8c6be63e9bffd5480603 Mon Sep 17 00:00:00 2001 From: salihmarangoz Date: Sat, 3 Jun 2023 23:03:48 +0200 Subject: [PATCH 188/487] Reverting a small mistake --- install_gdb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_gdb.sh b/install_gdb.sh index e90f0bcf..67d35ad6 100755 --- a/install_gdb.sh +++ b/install_gdb.sh @@ -49,7 +49,7 @@ echo "-------------------------------------------------------------------------" echo "If you're not on debian or a similar distro with the 'apt' package manager the follow will not work if you don't have gcc and g++ installed" echo "Please install them manually for this to work, this issue will be addressed at a later date" -apt-get install python3-dev libgmp3-dev +sudo apt-get install python3-dev libgmp3-dev CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j"$NUM_MAKE_JOBS" MAKEINFO=true && sudo make -C gdb install From 8fb26fbbff4c01fa4ebbd173518b2cdf0c2380a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 4 Jun 2023 13:49:34 +0300 Subject: [PATCH 189/487] Use -gt for POSIX compatibility --- install_gdb.sh | 2 +- install_pince.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install_gdb.sh b/install_gdb.sh index 67d35ad6..1eed7358 100755 --- a/install_gdb.sh +++ b/install_gdb.sh @@ -24,7 +24,7 @@ GDB_VERSION="gdb-11.2" if [ -z "$NUM_MAKE_JOBS" ]; then NUM_MAKE_JOBS=$(lscpu -p=core | uniq | awk '!/#/' | wc -l) MAX_NUM_MAKE_JOBS=8 - if (( NUM_MAKE_JOBS > MAX_NUM_MAKE_JOBS )); then # set an upper limit to prevent Out-Of-Memory + if [ "$NUM_MAKE_JOBS" -gt "$MAX_NUM_MAKE_JOBS" ]; then # set an upper limit to prevent Out-Of-Memory NUM_MAKE_JOBS=$MAX_NUM_MAKE_JOBS fi if ! echo "$NUM_MAKE_JOBS" | grep -Eq '^[0-9]+$'; then # fallback diff --git a/install_pince.sh b/install_pince.sh index 4405a3d9..87dd6fc4 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -30,7 +30,7 @@ CURRENT_USER="$(whoami)" if [ -z "$NUM_MAKE_JOBS" ]; then NUM_MAKE_JOBS=$(lscpu -p=core | uniq | awk '!/#/' | wc -l) MAX_NUM_MAKE_JOBS=8 - if (( NUM_MAKE_JOBS > MAX_NUM_MAKE_JOBS )); then # set an upper limit to prevent Out-Of-Memory + if [ "$NUM_MAKE_JOBS" -gt "$MAX_NUM_MAKE_JOBS" ]; then # set an upper limit to prevent Out-Of-Memory NUM_MAKE_JOBS=$MAX_NUM_MAKE_JOBS fi if ! echo "$NUM_MAKE_JOBS" | grep -Eq '^[0-9]+$'; then # fallback From 1db8f1be9c37956355791dcfaef44253a76191d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 5 Jun 2023 18:26:13 +0300 Subject: [PATCH 190/487] snake_case consistency for functions --- PINCE.py | 5 +- libpince/GDB_Engine.py | 20 +++---- libpince/GuiUtils.py | 2 +- libpince/SysUtils.py | 52 +++++++++---------- .../GDBCommandExtensions.py | 4 +- libpince/type_defs.py | 6 +-- 6 files changed, 44 insertions(+), 45 deletions(-) diff --git a/PINCE.py b/PINCE.py index 8da1ffdb..3b4ba7b8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -494,7 +494,6 @@ def __init__(self): self.treeWidget_AddressTable.expanded.connect(self.resize_address_table) self.treeWidget_AddressTable.collapsed.connect(self.resize_address_table) icons_directory = GuiUtils.get_icons_directory() - current_dir = SysUtils.get_current_script_directory() self.pushButton_AttachProcess.setIcon(QIcon(QPixmap(icons_directory + "/monitor.png"))) self.pushButton_Open.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) self.pushButton_Save.setIcon(QIcon(QPixmap(icons_directory + "/disk.png"))) @@ -994,7 +993,7 @@ def pushButton_MemoryView_clicked(self): self.memory_view_window.activateWindow() def pushButton_Wiki_clicked(self): - SysUtils.execute_shell_command_as_user('python3 -m webbrowser "https://github.com/korcankaraokcu/PINCE/wiki"') + SysUtils.execute_command_as_user('python3 -m webbrowser "https://github.com/korcankaraokcu/PINCE/wiki"') def pushButton_About_clicked(self): self.about_widget.show() @@ -3207,7 +3206,7 @@ def on_process_stop(self): return self.updating_memoryview = True time0 = time() - thread_info = GDB_Engine.get_current_thread_information() + thread_info = GDB_Engine.get_thread_info() if thread_info: self.setWindowTitle("Memory Viewer - Currently debugging " + thread_info) else: diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 25899959..c042dc18 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -204,10 +204,10 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, raise type_defs.InferiorRunningException gdb_output = "" if send_with_file: - send_file = SysUtils.get_IPC_from_PINCE_file(currentpid) + send_file = SysUtils.get_ipc_from_pince_file(currentpid) pickle.dump(file_contents_send, open(send_file, "wb")) if recv_with_file or cli_output: - recv_file = SysUtils.get_IPC_to_PINCE_file(currentpid) + recv_file = SysUtils.get_ipc_to_pince_file(currentpid) # Truncating the recv_file because we wouldn't like to see output of previous command in case of errors open(recv_file, "w").close() @@ -463,7 +463,7 @@ def unignore_signal(signal_name): #:tag:GDBCommunication def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): - r"""Spawns gdb and initializes/resets some of the global variables + """Spawns gdb and initializes/resets some of the global variables Args: gdb_path (str): Path of the gdb binary @@ -482,7 +482,7 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): detach() # Temporary IPC_PATH, this little hack is needed because send_command requires a valid IPC_PATH - SysUtils.create_PINCE_IPC_PATH(currentpid) + SysUtils.create_ipc_path(currentpid) breakpoint_on_hit_dict.clear() chained_breakpoints.clear() @@ -547,7 +547,7 @@ def init_referenced_dicts(pid): #:tag:Debug def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): - r"""Attaches gdb to the target and initializes some of the global variables + """Attaches gdb to the target and initializes some of the global variables Args: pid (int,str): PID of the process that'll be attached to @@ -583,7 +583,7 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): global mem_file currentpid = pid mem_file = "/proc/" + str(currentpid) + "/mem" - SysUtils.create_PINCE_IPC_PATH(pid) + SysUtils.create_ipc_path(pid) send_command("attach " + str(pid)) set_pince_paths() init_referenced_dicts(pid) @@ -599,7 +599,7 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): #:tag:Debug def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs.PATHS.GDB_PATH): - r"""Creates a new process for debugging and initializes some of the global variables + """Creates a new process for debugging and initializes some of the global variables Current process will be detached even if the create_process call fails Make sure to save your data before calling this monstrosity @@ -642,7 +642,7 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs pid = get_inferior_pid() currentpid = int(pid) mem_file = "/proc/" + str(currentpid) + "/mem" - SysUtils.create_PINCE_IPC_PATH(pid) + SysUtils.create_ipc_path(pid) set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() @@ -667,7 +667,7 @@ def detach(): gdb_initialized = False child.close() if old_pid != -1: - SysUtils.delete_PINCE_IPC_PATH(old_pid) + SysUtils.delete_ipc_path(old_pid) print("Detached from the process with PID:" + str(old_pid)) @@ -1004,7 +1004,7 @@ def parse_and_eval(expression, cast=str): #:tag:Threads -def get_current_thread_information(): +def get_thread_info(): """Invokes "info threads" command and returns the line corresponding to the current thread Returns: diff --git a/libpince/GuiUtils.py b/libpince/GuiUtils.py index 48ee8dcf..eef1dc80 100644 --- a/libpince/GuiUtils.py +++ b/libpince/GuiUtils.py @@ -25,7 +25,7 @@ def get_icons_directory(): Returns: str: Path to the icons directory """ - return SysUtils.get_current_script_directory() + "/media/icons" + return SysUtils.get_script_directory() + "/media/icons" #:tag:GUI diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index a85c7c19..77118b9d 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -207,11 +207,11 @@ def is_process_valid(pid): #:tag:Utilities -def get_current_script_directory(): - """Get current working directory +def get_script_directory(): + """Get main script directory Returns: - str: A string pointing to the current working directory + str: A string pointing to the main script directory """ return sys.path[0] @@ -223,7 +223,7 @@ def get_media_directory(): Returns: str: A string pointing to the media directory """ - return get_current_script_directory() + "/media" + return get_script_directory() + "/media" #:tag:Utilities @@ -233,7 +233,7 @@ def get_logo_directory(): Returns: str: A string pointing to the logo directory """ - return get_current_script_directory() + "/media/logo" + return get_script_directory() + "/media/logo" #:tag:Utilities @@ -273,24 +273,24 @@ def is_path_valid(dest_path, issue_path=""): #:tag:GDBCommunication -def delete_PINCE_IPC_PATH(pid): +def delete_ipc_path(pid): """Deletes the IPC directory of given pid Args: pid (int,str): PID of the process """ - is_path_valid(get_PINCE_IPC_directory(pid), "delete") + is_path_valid(get_ipc_path(pid), "delete") #:tag:GDBCommunication -def create_PINCE_IPC_PATH(pid): +def create_ipc_path(pid): """Creates the IPC directory of given pid Args: pid (int,str): PID of the process """ - delete_PINCE_IPC_PATH(pid) - is_path_valid(get_PINCE_IPC_directory(pid), "create") + delete_ipc_path(pid) + is_path_valid(get_ipc_path(pid), "create") # Opening the command file with 'w' each time GDB_Engine.send_command() gets invoked slows down the process # Instead, here we create the command file for only once when IPC path gets initialized @@ -300,7 +300,7 @@ def create_PINCE_IPC_PATH(pid): #:tag:GDBCommunication -def get_PINCE_IPC_directory(pid): +def get_ipc_path(pid): """Get the IPC directory of given pid Args: @@ -322,7 +322,7 @@ def get_logging_file(pid): Returns: str: Path of gdb logfile """ - return get_PINCE_IPC_directory(pid) + "/gdb_log.txt" + return get_ipc_path(pid) + "/gdb_log.txt" #:tag:GDBCommunication @@ -335,7 +335,7 @@ def get_gdb_command_file(pid): Returns: str: Path of gdb command file """ - return get_PINCE_IPC_directory(pid) + "/gdb_command.txt" + return get_ipc_path(pid) + "/gdb_command.txt" #:tag:BreakWatchpoints @@ -349,7 +349,7 @@ def get_track_watchpoint_file(pid, watchpoint_list): Returns: str: Path of track watchpoint file """ - return get_PINCE_IPC_directory(pid) + "/" + str(watchpoint_list) + "_track_watchpoint.txt" + return get_ipc_path(pid) + "/" + str(watchpoint_list) + "_track_watchpoint.txt" #:tag:BreakWatchpoints @@ -363,7 +363,7 @@ def get_track_breakpoint_file(pid, breakpoint): Returns: str: Path of track breakpoint file """ - return get_PINCE_IPC_directory(pid) + "/" + breakpoint + "_track_breakpoint.txt" + return get_ipc_path(pid) + "/" + breakpoint + "_track_breakpoint.txt" #:tag:Tools @@ -377,7 +377,7 @@ def get_trace_instructions_file(pid, breakpoint): Returns: str: Path of trace instructions file """ - return get_PINCE_IPC_directory(pid) + "/" + breakpoint + "_trace.txt" + return get_ipc_path(pid) + "/" + breakpoint + "_trace.txt" #:tag:Utilities @@ -469,7 +469,7 @@ def get_trace_instructions_status_file(pid, breakpoint): Returns: str: Path of trace instructions status file """ - return get_PINCE_IPC_directory(pid) + "/" + breakpoint + "_trace_status.txt" + return get_ipc_path(pid) + "/" + breakpoint + "_trace_status.txt" #:tag:Tools @@ -482,7 +482,7 @@ def get_dissect_code_status_file(pid): Returns: str: Path of dissect code status file """ - return get_PINCE_IPC_directory(pid) + "/dissect_code_status.txt" + return get_ipc_path(pid) + "/dissect_code_status.txt" #:tag:Tools @@ -495,7 +495,7 @@ def get_referenced_strings_file(pid): Returns: str: Path of referenced strings dict file """ - return get_PINCE_IPC_directory(pid) + "/referenced_strings_dict.txt" + return get_ipc_path(pid) + "/referenced_strings_dict.txt" #:tag:Tools @@ -508,7 +508,7 @@ def get_referenced_jumps_file(pid): Returns: str: Path of referenced jumps dict file """ - return get_PINCE_IPC_directory(pid) + "/referenced_jumps_dict.txt" + return get_ipc_path(pid) + "/referenced_jumps_dict.txt" #:tag:Tools @@ -521,11 +521,11 @@ def get_referenced_calls_file(pid): Returns: str: Path of referenced calls dict file """ - return get_PINCE_IPC_directory(pid) + "/referenced_calls_dict.txt" + return get_ipc_path(pid) + "/referenced_calls_dict.txt" #:tag:GDBCommunication -def get_IPC_from_PINCE_file(pid): +def get_ipc_from_pince_file(pid): """Get the path of IPC file sent to custom gdb commands from PINCE for given pid Args: @@ -534,11 +534,11 @@ def get_IPC_from_PINCE_file(pid): Returns: str: Path of IPC file """ - return get_PINCE_IPC_directory(pid) + type_defs.IPC_PATHS.IPC_FROM_PINCE_PATH + return get_ipc_path(pid) + type_defs.IPC_PATHS.IPC_FROM_PINCE_PATH #:tag:GDBCommunication -def get_IPC_to_PINCE_file(pid): +def get_ipc_to_pince_file(pid): """Get the path of IPC file sent to PINCE from custom gdb commands for given pid Args: @@ -547,7 +547,7 @@ def get_IPC_to_PINCE_file(pid): Returns: str: Path of IPC file """ - return get_PINCE_IPC_directory(pid) + type_defs.IPC_PATHS.IPC_TO_PINCE_PATH + return get_ipc_path(pid) + type_defs.IPC_PATHS.IPC_TO_PINCE_PATH #:tag:ValueType @@ -838,7 +838,7 @@ def split_symbol(symbol_string): #:tag:Utilities -def execute_shell_command_as_user(command): +def execute_command_as_user(command): """Executes given command as user Args: diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index cd3b30a7..916a5267 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -28,8 +28,8 @@ inferior = gdb.selected_inferior() pid = inferior.pid -recv_file = SysUtils.get_IPC_from_PINCE_file(pid) -send_file = SysUtils.get_IPC_to_PINCE_file(pid) +recv_file = SysUtils.get_ipc_from_pince_file(pid) +send_file = SysUtils.get_ipc_to_pince_file(pid) lib = None diff --git a/libpince/type_defs.py b/libpince/type_defs.py index fb5c3b49..4f2e0c49 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -29,9 +29,9 @@ class PATHS: class IPC_PATHS: - PINCE_IPC_PATH = "/dev/shm/PINCE-connection/" # Use SysUtils.get_PINCE_IPC_directory() - IPC_FROM_PINCE_PATH = "/from_PINCE_file" # Use SysUtils.get_IPC_from_PINCE_file() - IPC_TO_PINCE_PATH = "/to_PINCE_file" # Use SysUtils.get_IPC_to_PINCE_file() + PINCE_IPC_PATH = "/dev/shm/PINCE-connection/" # Use SysUtils.get_ipc_path() + IPC_FROM_PINCE_PATH = "/from_PINCE_file" # Use SysUtils.get_ipc_from_pince_file() + IPC_TO_PINCE_PATH = "/to_PINCE_file" # Use SysUtils.get_ipc_to_pince_file() class USER_PATHS: From 97adab709bfb078ec7c1643b1c36a79294e40b61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 5 Jun 2023 18:43:11 +0300 Subject: [PATCH 191/487] Update scanmem --- PINCE.py | 1 - scanmem | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 3b4ba7b8..5180c06c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -431,7 +431,6 @@ def __init__(self): libscanmem_path = os.path.join(os.getcwd(), "libpince", "libscanmem", "libscanmem.so") self.backend = Scanmem(libscanmem_path) self.backend.send_command("option noptrace 1") - self.backend.send_command("option undo_limit 5") self.memory_view_window = MemoryViewWindowForm(self) self.about_widget = AboutWidgetForm() self.await_exit_thread = AwaitProcessExit() diff --git a/scanmem b/scanmem index 6589a87a..65f8e700 160000 --- a/scanmem +++ b/scanmem @@ -1 +1 @@ -Subproject commit 6589a87af742a83fe7ca3646d7f3da307715a545 +Subproject commit 65f8e700c56d9858fe01dba393d9b8238040b8ee From aeab5f61259b72ea229f66ba46ccb79e0f50f275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 9 Jun 2023 19:52:06 +0300 Subject: [PATCH 192/487] Remove unused file --- libpince/PINCEBackend.py | 114 --------------------------------------- 1 file changed, 114 deletions(-) delete mode 100644 libpince/PINCEBackend.py diff --git a/libpince/PINCEBackend.py b/libpince/PINCEBackend.py deleted file mode 100644 index dd67c7b9..00000000 --- a/libpince/PINCEBackend.py +++ /dev/null @@ -1,114 +0,0 @@ -""" - GameConquerorBackend: communication with libscanmem - - Copyright (C) 2010,2011,2013 Wang Lu - Copyright (C) 2018 Sebastian Parschauer - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -""" - -import ctypes, tempfile, os, sys -from ctypes import byref -import re - -# taken from https://github.com/scanmem/scanmem/blob/6a5e2e86ebacd87bed132dea354433d722081abf/gui/backend.py -# see https://github.com/scanmem/scanmem/issues/225 for future improvements -class PINCEBackend(): - BACKEND_FUNCTIONS = { - "sm_init": (ctypes.c_bool, ), - "sm_cleanup": (None, ), - "sm_set_backend": (None, ), - "sm_backend_exec_cmd" : (None, ctypes.c_char_p), - "sm_get_num_matches" : (ctypes.c_ulong, ), - "sm_get_version" : (ctypes.c_char_p, ), - "sm_get_scan_progress" : (ctypes.c_double, ), - "sm_set_stop_flag" : (None, ctypes.c_bool), - "sm_process_is_dead": (ctypes.c_bool, ) - } - - """ - scans the current dirrectory (PINCE/libpince) for libscanmem - @param libname - """ - def __init__(self, libname="scanmem.so"): - self.lib = ctypes.CDLL(os.path.dirname(__file__) + os.path.sep + libname) - self.libc = ctypes.CDLL("libc.so.6") - self.init_sm_funcs() - self.lib.sm_init() - - def init_sm_funcs(self): - for k, v in PINCEBackend.BACKEND_FUNCTIONS.items(): - f = getattr(self.lib, k) - f.restype = v[0] - f.argtypes = v[1:] - - def sm_cleanup(self): - self.lib.sm_cleanup() - - # Used for most of the things, like searching etc - def sm_exec_cmd(self, cmd, get_output = False): - if get_output: - with tempfile.TemporaryFile() as directed_file: - backup_stdout_fileno = os.dup(sys.stdout.fileno()) - os.dup2(directed_file.fileno(), sys.stdout.fileno()) - - self.lib.sm_backend_exec_cmd(ctypes.c_char_p(cmd.encode("ascii"))) - - os.dup2(backup_stdout_fileno, sys.stdout.fileno()) - os.close(backup_stdout_fileno) - directed_file.seek(0) - return directed_file.read() - else: - self.lib.sm_backend_exec_cmd(ctypes.c_char_p(cmd.encode("ascii"))) - def sm_get_num_matches(self): - return self.lib.sm_get_num_matches() - - def sm_get_version(self): - return self.lib.sm_get_version() - - def sm_get_scan_progress(self): - return self.lib.sm_get_scan_progress() - - def sm_set_stop_flag(self, stop_flag): - self.lib.sm_set_stop_flag(stop_flag) - - def sm_process_is_dead(self, pid): - self.lib.sm_process_is_dead(pid) - - """ - @param string the string that's returned by libscanmem - @returns a dictionary with the key as the n:th match, and value the rest of the structure that's returned - """ - def parse_string(self, string): - # based on information from the scanmem source, the format for a line from scanmem is: - # n address region id* offset region type value type(s) - #[4425] 7fd3ef3cf488, 31 + 8cf488, misc, 12, [I8 ] - # * region id = line number in /proc/pid/maps - # region id can later be probably be used to get like "executable + offset" - if string == None: - return None - ret = dict() - string = string.decode("utf-8").splitlines() - if string == None: - return None - line_match = re.compile(r"^\[ *(\d+)\] +([\da-f]+), +\d+ \+ +([\da-f]+), +(\w+), (.*), +\[([\w ]+)\]$") - for row in string: - (n, address, offset, region_type, value, t) = line_match.match(row).groups() - ret[n] = { - "address": address, - "offset": offset, - "region_type": region_type, - "value": value, - "type": t - } From 28a51df4a07e1c3eded66b7f4b11c592ce8fbf84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 10 Jun 2023 20:48:44 +0300 Subject: [PATCH 193/487] Fix padding issues for disassemble --- PINCE.py | 22 +++++++++++----------- libpince/GDB_Engine.py | 13 +++++++++---- libpince/common_regexes.py | 6 +++++- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/PINCE.py b/PINCE.py index 5180c06c..4ffffa4b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3057,9 +3057,9 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his self.tableWidget_Disassemble.setRowCount(0) self.tableWidget_Disassemble.setRowCount(len(disas_data)) jmp_dict, call_dict = GDB_Engine.get_dissect_code_data(False, True, True) - for row, item in enumerate(disas_data): + for row, (address_info, bytes_aob, opcode) in enumerate(disas_data): comment = "" - current_address = int(SysUtils.extract_address(item[0]), 16) + current_address = int(SysUtils.extract_address(address_info), 16) current_address_str = hex(current_address) jmp_ref_exists = False call_ref_exists = False @@ -3100,9 +3100,9 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his real_ref_count += len(jmp_referrers) if call_ref_exists: real_ref_count += len(call_referrers) - item[0] = "{" + str(real_ref_count) + "}" + item[0] + address_info = "{" + str(real_ref_count) + "}" + address_info if current_address == program_counter_int: - item[0] = ">>>" + item[0] + address_info = ">>>" + address_info try: row_colour[row].append(PC_COLOUR) except KeyError: @@ -3113,7 +3113,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his row_colour[row].append(BOOKMARK_COLOUR) except KeyError: row_colour[row] = [BOOKMARK_COLOUR] - item[0] = "(M)" + item[0] + address_info = "(M)" + address_info comment = self.tableWidget_Disassemble.bookmarks[bookmark_item] break for breakpoint in breakpoint_info: @@ -3132,13 +3132,13 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his if breakpoint.enable_count: breakpoint_mark += "-" + breakpoint.enable_count breakpoint_mark += ")" - item[0] = breakpoint_mark + item[0] + address_info = breakpoint_mark + address_info break if current_address == self.disassemble_last_selected_address_int: self.tableWidget_Disassemble.selectRow(row) - addr_item = QTableWidgetItem(item[0]) - bytes_item = QTableWidgetItem(item[1]) - opcodes_item = QTableWidgetItem(item[2]) + addr_item = QTableWidgetItem(address_info) + bytes_item = QTableWidgetItem(bytes_aob) + opcodes_item = QTableWidgetItem(opcode) comment_item = QTableWidgetItem(comment) if jmp_ref_exists or call_ref_exists: addr_item.setToolTip(tooltip_text) @@ -5907,8 +5907,8 @@ def listWidget_Referrers_current_changed(self, QModelIndex_current): self.textBrowser_DisasInfo.clear() disas_data = GDB_Engine.disassemble( SysUtils.extract_address(self.listWidget_Referrers.item(QModelIndex_current.row()).text()), "+200") - for item in disas_data: - self.textBrowser_DisasInfo.append(item[0] + item[2]) + for address_info, _, opcode in disas_data: + self.textBrowser_DisasInfo.append(address_info + opcode) cursor = self.textBrowser_DisasInfo.textCursor() cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_DisasInfo.setTextCursor(cursor) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index c042dc18..e62e009e 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -943,14 +943,19 @@ def disassemble(expression, offset_or_address): expression (str): Any gdb expression offset_or_address (str): If you pass this parameter as an offset, you should add "+" in front of it (e.g "+42" or "+0x42"). If you pass this parameter as an hex address, the address range between the expression - and the secondary address is disassembled. - If the second parameter is an address. it always should be bigger than the first address. + and the secondary address is disassembled + If the second parameter is an address, it always should be bigger than the first address Returns: - list: A list of str values in this format-->[[address1,bytes1,opcodes1],[address2, ...], ...] + list: A list of str values in this format-->[(address1, bytes1, opcodes1), (address2, ...), ...] """ output = send_command("disas /r " + expression + "," + offset_or_address) - return [list(item) for item in common_regexes.disassemble_output.findall(output)] + disas_data = [] + for line in output.splitlines(): + result = common_regexes.disassemble_output.search(line) + if result: + disas_data.append(result.groups()) + return disas_data #:tag:GDBExpressions diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index 80d9e658..b27f1138 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -39,7 +39,11 @@ # The command will always start with the word "source", check GDB_Engine.send_command function for the cause gdb_command_source = lambda command_file: compile(r"&\".*source\s" + command_file + r"\\n\"") # &"command\n" # 0x00007fd81d4c7400 <__printf+0>:\t48 81 ec d8 00 00 00\tsub rsp,0xd8\n -disassemble_output = compile(r"(" + hex_number.pattern + r".*)\\t(.+)\\t(.+)\\n") +disassemble_output = compile(r""" + ([0-9a-fA-F]+.*)\\t # Address with symbol + (.*?[0-9a-fA-F]{2})\s*\\t # Bytes, ignore padding + (.+)\\n # Opcode +""", VERBOSE) info_functions_non_debugging = compile(hex_number_grouped.pattern + r"\s+(.*)") max_completions_reached = compile(r"\*\*\*\s+List\s+may\s+be\s+truncated,\s+max-completions\s+reached\.\s+\*\*\*") From a5d9114565ea0d5bccdcf92dda209b5fb63c2aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 10 Jun 2023 23:07:49 +0300 Subject: [PATCH 194/487] Fix MemoryViewer key_event issues when no address is selected --- PINCE.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PINCE.py b/PINCE.py index 4ffffa4b..f6b79f99 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3378,6 +3378,8 @@ def tableWidget_Stack_key_press_event(self, event): if GDB_Engine.currentpid == -1: return selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) + if selected_row == -1: + return current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3550,6 +3552,8 @@ def tableWidget_Disassemble_key_press_event(self, event): if GDB_Engine.currentpid == -1: return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + if selected_row == -1: + selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_address_int = int(current_address, 16) From 19142ee87145de173de6e96351bfa5e76a52eb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 11 Jun 2023 08:41:17 +0300 Subject: [PATCH 195/487] Fix get_selected_address --- GUI/CustomTableViews/HexView.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/GUI/CustomTableViews/HexView.py b/GUI/CustomTableViews/HexView.py index 42ad485e..d123cd74 100644 --- a/GUI/CustomTableViews/HexView.py +++ b/GUI/CustomTableViews/HexView.py @@ -44,6 +44,9 @@ def resize_to_contents(self): self.setMaximumWidth(size) def get_selected_address(self): - ci = self.currentIndex() - current_address = self.model().current_address + ci.row() * self.model().columnCount() + ci.column() + index_list = self.selectionModel().selectedIndexes() # Use selectionModel instead of currentIndex + current_address = self.model().current_address + if index_list: + cell = index_list[0] + current_address = current_address + cell.row() * self.model().columnCount() + cell.column() return SysUtils.modulo_address(current_address, GDB_Engine.inferior_arch) From dfbd47dcab2f8c0eb831083e05994679a19ab706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 11 Jun 2023 17:21:16 +0300 Subject: [PATCH 196/487] Further fix MemoryViewer key_event issues --- PINCE.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PINCE.py b/PINCE.py index f6b79f99..5e7fbe19 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3726,6 +3726,8 @@ def dissect_current_region(self): if GDB_Engine.currentpid == -1: return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + if selected_row == -1: + selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) dissect_code_dialog = DissectCodeDialogForm(int_address=int(current_address, 16)) @@ -3747,6 +3749,8 @@ def exec_trace_instructions_dialog(self): if GDB_Engine.currentpid == -1: return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + if selected_row == -1: + selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) TraceInstructionsWindowForm(current_address, parent=self) @@ -3778,6 +3782,8 @@ def exec_disassemble_go_to_dialog(self): if GDB_Engine.currentpid == -1: return selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + if selected_row == -1: + selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) From 307885327555ca73a73ef626bad2cdecc9419303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 11 Jun 2023 18:59:04 +0300 Subject: [PATCH 197/487] Fix call order for on_hex_view_current_changed --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 5e7fbe19..3cc1661b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2948,10 +2948,10 @@ def on_hex_view_current_changed(self, QModelIndex_current): if GDB_Engine.currentpid == -1: return self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) - self.hex_view_last_selected_address_int = self.tableView_HexView_Hex.get_selected_address() self.tableView_HexView_Ascii.selectionModel().setCurrentIndex(QModelIndex_current, QItemSelectionModel.SelectionFlag.ClearAndSelect) self.tableWidget_HexView_Address.selectRow(QModelIndex_current.row()) + self.hex_view_last_selected_address_int = self.tableView_HexView_Hex.get_selected_address() self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) def on_ascii_view_current_changed(self, QModelIndex_current): From 16586da9a0d785dc007f87feb243c6707a5ae15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 11 Jun 2023 19:30:16 +0300 Subject: [PATCH 198/487] Remove redundant code in get_process_list --- libpince/SysUtils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index 77118b9d..c634096b 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -38,7 +38,7 @@ def get_process_list(): for line in os.popen("ps -eo pid:11,user,comm").read().splitlines(): info = common_regexes.ps.match(line) if info: - process_list.append(common_regexes.ps.match(line).groups()) + process_list.append(info.groups()) return process_list From 51b9f1e7b09b571ec11f729efd54500d77239b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 12 Jun 2023 19:23:10 +0300 Subject: [PATCH 199/487] Fix a bug where keyPressEvent would be called twice --- PINCE.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/PINCE.py b/PINCE.py index 3cc1661b..82816a43 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2670,15 +2670,19 @@ def initialize_hex_view(self): self.hex_view_last_selected_address_int = 0 self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) self.widget_HexView.wheelEvent = self.widget_HexView_wheel_event + + # Saving the original function because super() doesn't work when we override functions like this + self.widget_HexView.keyPressEvent_original = self.widget_HexView.keyPressEvent + self.widget_HexView.keyPressEvent = self.widget_HexView_key_press_event + self.tableView_HexView_Hex.contextMenuEvent = self.widget_HexView_context_menu_event self.tableView_HexView_Ascii.contextMenuEvent = self.widget_HexView_context_menu_event self.tableView_HexView_Hex.doubleClicked.connect(self.exec_hex_view_edit_dialog) self.tableView_HexView_Ascii.doubleClicked.connect(self.exec_hex_view_edit_dialog) - # Saving the original function because super() doesn't work when we override functions like this - self.tableView_HexView_Hex.keyPressEvent_original = self.tableView_HexView_Hex.keyPressEvent - self.tableView_HexView_Hex.keyPressEvent = self.widget_HexView_key_press_event - self.tableView_HexView_Ascii.keyPressEvent = self.widget_HexView_key_press_event + # Ignoring the event sends it directly to the parent, which is widget_HexView + self.tableView_HexView_Hex.keyPressEvent = QEvent.ignore + self.tableView_HexView_Ascii.keyPressEvent = QEvent.ignore self.bHexViewScrolling = False # rejects new scroll requests while scrolling self.verticalScrollBar_HexView.wheelEvent = QEvent.ignore @@ -2686,7 +2690,6 @@ def initialize_hex_view(self): self.verticalScrollBar_HexView.sliderChange = self.hex_view_scrollbar_sliderchanged self.tableWidget_HexView_Address.wheelEvent = QEvent.ignore - self.scrollArea_Hex.keyPressEvent = self.widget_HexView_key_press_event self.tableWidget_HexView_Address.setAutoScroll(False) self.tableWidget_HexView_Address.setStyleSheet("QTableWidget {background-color: transparent;}") self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) @@ -3546,7 +3549,7 @@ def widget_HexView_key_press_event(self, event): actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: pass - self.tableView_HexView_Hex.keyPressEvent_original(event) + self.widget_HexView.keyPressEvent_original(event) def tableWidget_Disassemble_key_press_event(self, event): if GDB_Engine.currentpid == -1: From 7111db9946318a89dfc1634e3ac07db211e8e242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 12 Jun 2023 19:47:10 +0300 Subject: [PATCH 200/487] Fix global vars and function names for consistency --- PINCE.py | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/PINCE.py b/PINCE.py index 82816a43..19071e85 100755 --- a/PINCE.py +++ b/PINCE.py @@ -91,7 +91,7 @@ current_settings_version = "master-22" # Increase version by one if you change settings. Format: branch_name-version update_table = bool table_update_interval = int -FreezeInterval = int +freeze_interval = int show_messagebox_on_exception = bool gdb_output_mode = tuple auto_attach_list = str @@ -265,8 +265,8 @@ def get_hotkeys(): saved_addresses_changed_list = list() # vars for communication/storage with the non blocking threads -Exiting = 0 -ProgressRun = 0 +exiting = 0 +progress_running = 0 threadpool = QThreadPool() # Placeholder number, may have to be changed in the future @@ -570,11 +570,11 @@ def apply_settings(self): global bring_disassemble_to_front global instructions_per_scroll global gdb_path - global FreezeInterval + global freeze_interval update_table = self.settings.value("General/auto_update_address_table", type=bool) table_update_interval = self.settings.value("General/address_table_update_interval", type=int) - FreezeInterval = self.settings.value("General/freeze_interval", type=int) + freeze_interval = self.settings.value("General/freeze_interval", type=int) show_messagebox_on_exception = self.settings.value("General/show_messagebox_on_exception", type=bool) gdb_output_mode = self.settings.value("General/gdb_output_mode", type=tuple) auto_attach_list = self.settings.value("General/auto_attach_list", type=str) @@ -1120,7 +1120,7 @@ def validate_search(self, search_for, search_for2): def pushButton_NextScan_clicked(self, search_for=None): if GDB_Engine.currentpid == -1: return - global ProgressRun + global progress_running if not search_for: search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) @@ -1129,7 +1129,7 @@ def pushButton_NextScan_clicked(self, search_for=None): threadpool.start(Worker(self.update_progress_bar)) self.backend.send_command(search_for) matches = self.backend.matches() - ProgressRun = 0 + progress_running = 0 match_count = self.backend.get_match_count() if match_count > 10000: self.label_MatchCount.setText("Match count: {} (10000 shown)".format(match_count)) @@ -1367,17 +1367,17 @@ def treeWidget_AddressTable_item_double_clicked(self, row, column): # Async Functions def update_progress_bar(self): - global ProgressRun - global Exiting + global progress_running + global exiting self.progressBar.setValue(0) - ProgressRun = 1 - while ProgressRun == 1 and Exiting == 0: + progress_running = 1 + while progress_running == 1 and exiting == 0: sleep(0.1) value = int(round(self.backend.get_scan_progress() * 100)) self.progressBar.setValue(value) def update_address_table_loop(self): - while Exiting == 0: + while exiting == 0: sleep(table_update_interval / 1000) if update_table: try: @@ -1386,7 +1386,7 @@ def update_address_table_loop(self): print("Update Address Table failed :(") def update_search_table_loop(self): - while Exiting == 0: + while exiting == 0: sleep(0.5) try: self.update_search_table() @@ -1394,8 +1394,8 @@ def update_search_table_loop(self): print("Update Search Table failed :(") def freeze_loop(self): - while Exiting == 0: - sleep(FreezeInterval / 1000) + while exiting == 0: + sleep(freeze_interval / 1000) try: self.freeze() except: @@ -2154,7 +2154,7 @@ def accept(self): QMessageBox.information(self, "Error", "Update interval must be an int") return try: - freezeinterval = int(self.lineEdit_FreezeInterval.text()) + current_freeze_interval = int(self.lineEdit_FreezeInterval.text()) except: QMessageBox.information(self, "Error", "Freeze interval must be an int") return @@ -2169,10 +2169,10 @@ def accept(self): return if not self.checkBox_AutoUpdateAddressTable.isChecked(): pass - elif current_table_update_interval < 0 or freezeinterval < 0: + elif current_table_update_interval < 0 or current_freeze_interval < 0: QMessageBox.information(self, "Error", "Interval cannot be a negative number") return - elif current_table_update_interval == 0 or freezeinterval == 0: + elif current_table_update_interval == 0 or current_freeze_interval == 0: # Easter egg #2 if not InputDialogForm(item_list=[("You are asking for it, aren't you?",)]).exec(): @@ -2186,7 +2186,7 @@ def accept(self): self.settings.setValue("General/auto_update_address_table", self.checkBox_AutoUpdateAddressTable.isChecked()) if self.checkBox_AutoUpdateAddressTable.isChecked(): self.settings.setValue("General/address_table_update_interval", current_table_update_interval) - self.settings.setValue("General/freeze_interval", freezeinterval) + self.settings.setValue("General/freeze_interval", current_freeze_interval) self.settings.setValue("General/show_messagebox_on_exception", self.checkBox_MessageBoxOnException.isChecked()) current_gdb_output_mode = type_defs.gdb_output_mode(self.checkBox_OutputModeAsync.isChecked(), self.checkBox_OutputModeCommand.isChecked(), @@ -2227,8 +2227,7 @@ def config_gui(self): self.settings.value("General/auto_update_address_table", type=bool)) self.lineEdit_UpdateInterval.setText( str(self.settings.value("General/address_table_update_interval", type=int))) - self.lineEdit_FreezeInterval.setText( - str(self.settings.value("General/freeze_interval", type=int))) + self.lineEdit_FreezeInterval.setText(str(self.settings.value("General/freeze_interval", type=int))) self.checkBox_MessageBoxOnException.setChecked( self.settings.value("General/show_messagebox_on_exception", type=bool)) self.checkBox_OutputModeAsync.setChecked(self.settings.value("General/gdb_output_mode").async_output) @@ -5956,14 +5955,14 @@ def closeEvent(self, QCloseEvent): instances.remove(self) -def exitHandler(): - global Exiting - Exiting = 1 +def handle_exit(): + global exiting + exiting = 1 if __name__ == "__main__": app = QApplication(sys.argv) - app.aboutToQuit.connect(exitHandler) + app.aboutToQuit.connect(handle_exit) window = MainForm() window.show() sys.exit(app.exec()) From 5cf533dee3f2de8d8b2f1040b4c837ebb54d2d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 9 Jul 2023 18:06:20 +0300 Subject: [PATCH 201/487] Prepare translation constants --- .gitignore | 1 + PINCE.py | 693 ++--- README.md | 2 +- compile_ts.sh | 1 + i18n/ts/it_IT.ts | 2760 +++++++++++++++++ libpince/GDB_Engine.py | 34 +- libpince/SysUtils.py | 8 +- .../GDBCommandExtensions.py | 10 +- libpince/type_defs.py | 31 +- tr/tr.py | 315 ++ 10 files changed, 3430 insertions(+), 425 deletions(-) create mode 100755 compile_ts.sh create mode 100644 i18n/ts/it_IT.ts create mode 100644 tr/tr.py diff --git a/.gitignore b/.gitignore index bec68f53..775ef761 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ libscanmem.so* libpince/libscanmem/* *.directory *.lprof +*.qm *.py[cod] *$py.class gdb_pince/* diff --git a/PINCE.py b/PINCE.py index 19071e85..0ef4af38 100755 --- a/PINCE.py +++ b/PINCE.py @@ -34,12 +34,14 @@ QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, \ QPushButton, QFrame from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, \ - QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QThreadPool, pyqtSlot + QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QThreadPool, \ + QTranslator, QLocale, pyqtSlot from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect from libpince import GuiUtils, SysUtils, GDB_Engine, type_defs from libpince.libscanmem.scanmem import Scanmem +from tr.tr import TranslationConstants as tr from GUI.MainWindow import Ui_MainWindow as MainWindow from GUI.SelectProcess import Ui_MainWindow as ProcessWindow @@ -85,6 +87,19 @@ from keyboard import add_hotkey, remove_hotkey from operator import add as opAdd, sub as opSub +if __name__ == '__main__': + app = QApplication(sys.argv) + QSettings.setPath(QSettings.Format.NativeFormat, QSettings.Scope.UserScope, + SysUtils.get_user_path(type_defs.USER_PATHS.CONFIG_PATH)) + settings = QSettings() + translator = QTranslator() + locale = settings.value("General/locale", type=str) + if not locale: + locale = QLocale.system().name() + translator.load(f'i18n/qm/{locale}.qm') + app.installTranslator(translator) + tr.translate() + instances = [] # Holds temporary instances that will be deleted later on # settings @@ -135,15 +150,15 @@ def get_active_key(self): return self.default return self.custom - pause_hotkey = Hotkey("pause_hotkey", "Pause the process", "F1") - break_hotkey = Hotkey("break_hotkey", "Break the process", "F2") - continue_hotkey = Hotkey("continue_hotkey", "Continue the process", "F3") - toggle_attach_hotkey = Hotkey("toggle_attach_hotkey", "Toggle attach/detach", "Shift+F10") - exact_scan_hotkey = Hotkey("exact_scan_hotkey", "Next Scan - Exact", "") - increased_scan_hotkey = Hotkey("increased_scan_hotkey", "Next Scan - Increased", "") - decreased_scan_hotkey = Hotkey("decreased_scan_hotkey", "Next Scan - Decreased", "") - changed_scan_hotkey = Hotkey("changed_scan_hotkey", "Next Scan - Changed", "") - unchanged_scan_hotkey = Hotkey("unchanged_scan_hotkey", "Next Scan - Unchanged", "") + pause_hotkey = Hotkey("pause_hotkey", tr.PAUSE_HOTKEY, "F1") + break_hotkey = Hotkey("break_hotkey", tr.BREAK_HOTKEY, "F2") + continue_hotkey = Hotkey("continue_hotkey", tr.CONTINUE_HOTKEY, "F3") + toggle_attach_hotkey = Hotkey("toggle_attach_hotkey", tr.TOGGLE_ATTACH_HOTKEY, "Shift+F10") + exact_scan_hotkey = Hotkey("exact_scan_hotkey", tr.EXACT_SCAN_HOTKEY, "") + increased_scan_hotkey = Hotkey("increased_scan_hotkey", tr.INC_SCAN_HOTKEY, "") + decreased_scan_hotkey = Hotkey("decreased_scan_hotkey", tr.DEC_SCAN_HOTKEY, "") + changed_scan_hotkey = Hotkey("changed_scan_hotkey", tr.CHANGED_SCAN_HOTKEY, "") + unchanged_scan_hotkey = Hotkey("unchanged_scan_hotkey", tr.UNCHANGED_SCAN_HOTKEY, "") @staticmethod def get_hotkeys(): @@ -291,11 +306,10 @@ def except_hook(exception_type, value, tb): focused_widget = app.focusWidget() if focused_widget: if exception_type == type_defs.GDBInitializeException: - QMessageBox.information(focused_widget, "Error", "GDB isn't initialized yet") + QMessageBox.information(focused_widget, tr.ERROR, tr.GDB_INIT) elif exception_type == type_defs.InferiorRunningException: - error_dialog = InputDialogForm(item_list=[( - "Process is running" + "\nPress " + Hotkeys.break_hotkey.get_active_key() + " to stop process" + - "\n\nGo to Settings->General to disable this dialog",)], + error_dialog = InputDialogForm( + item_list=[(tr.PROCESS_RUNNING.format(Hotkeys.break_hotkey.get_active_key()),)], buttons=[QDialogButtonBox.StandardButton.Ok]) error_dialog.exec() traceback.print_exception(exception_type, value, tb) @@ -398,8 +412,6 @@ def __init__(self): app.setOrganizationName("PINCE") app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") app.setApplicationName("PINCE") - QSettings.setPath(QSettings.Format.NativeFormat, QSettings.Scope.UserScope, - SysUtils.get_user_path(type_defs.USER_PATHS.CONFIG_PATH)) self.settings = QSettings() if not SysUtils.is_path_valid(self.settings.fileName()): self.set_default_settings() @@ -415,19 +427,18 @@ def __init__(self): try: self.apply_settings() except Exception as e: - print("An exception occurred while trying to load settings, rolling back to the default configuration\n", e) + print("An exception occurred while loading settings, rolling back to the default configuration\n", e) self.settings.clear() self.set_default_settings() try: GDB_Engine.init_gdb(gdb_path) except pexpect.EOF: - text = "Unable to initialize GDB\n" \ - "You might want to reinstall GDB or use the system GDB\n" \ - "To change the current GDB path, check Settings->Debug" - InputDialogForm(item_list=[(text, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() + InputDialogForm(item_list=[(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() else: self.apply_after_init() - # this should be changed, only works if you use the current directory, fails if you for example install it to some place like bin + + # This should be changed, only works if you use the current directory + # Fails if you for example install it to some place like bin libscanmem_path = os.path.join(os.getcwd(), "libpince", "libscanmem", "libscanmem.so") self.backend = Scanmem(libscanmem_path) self.backend.send_command("option noptrace 1") @@ -455,6 +466,7 @@ def __init__(self): self.shortcut_save_file = QShortcut(QKeySequence("Ctrl+S"), self) self.shortcut_save_file.activated.connect(self.pushButton_Save_clicked) GuiUtils.append_shortcut_to_tooltip(self.pushButton_Save, self.shortcut_save_file) + # Saving the original function because super() doesn't work when we override functions like this self.treeWidget_AddressTable.keyPressEvent_original = self.treeWidget_AddressTable.keyPressEvent self.treeWidget_AddressTable.keyPressEvent = self.treeWidget_AddressTable_key_press_event @@ -654,37 +666,38 @@ def treeWidget_AddressTable_context_menu_event(self, event): if self.treeWidget_AddressTable.topLevelItemCount() == 0: return current_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + header = self.treeWidget_AddressTable.headerItem() menu = QMenu() - edit_menu = menu.addMenu("Edit") - edit_desc = edit_menu.addAction("Description[Ctrl+Enter]") - edit_address = edit_menu.addAction("Address[Ctrl+Alt+Enter]") - edit_type = edit_menu.addAction("Type[Alt+Enter]") - edit_value = edit_menu.addAction("Value[Enter]") - show_hex = menu.addAction("Show as hexadecimal") - show_dec = menu.addAction("Show as decimal") - show_unsigned = menu.addAction("Show as unsigned") - show_signed = menu.addAction("Show as signed") - toggle_record = menu.addAction("Toggle selected records[Space]") - freeze_menu = menu.addMenu("Freeze") - freeze_default = freeze_menu.addAction("Default") - freeze_inc = freeze_menu.addAction("Incremental") - freeze_dec = freeze_menu.addAction("Decremental") + edit_menu = menu.addMenu(tr.EDIT) + edit_desc = edit_menu.addAction(f"{header.text(DESC_COL)}[Ctrl+Enter]") + edit_address = edit_menu.addAction(f"{header.text(ADDR_COL)}[Ctrl+Alt+Enter]") + edit_type = edit_menu.addAction(f"{header.text(TYPE_COL)}[Alt+Enter]") + edit_value = edit_menu.addAction(f"{header.text(VALUE_COL)}[Enter]") + show_hex = menu.addAction(tr.SHOW_HEX) + show_dec = menu.addAction(tr.SHOW_DEC) + show_unsigned = menu.addAction(tr.SHOW_UNSIGNED) + show_signed = menu.addAction(tr.SHOW_SIGNED) + toggle_record = menu.addAction(f"{tr.TOGGLE_RECORDS}[Space]") + freeze_menu = menu.addMenu(tr.FREEZE) + freeze_default = freeze_menu.addAction(tr.DEFAULT) + freeze_inc = freeze_menu.addAction(tr.INCREMENTAL) + freeze_dec = freeze_menu.addAction(tr.DECREMENTAL) menu.addSeparator() - browse_region = menu.addAction("Browse this memory region[Ctrl+B]") - disassemble = menu.addAction("Disassemble this address[Ctrl+D]") + browse_region = menu.addAction(f"{tr.BROWSE_MEMORY_REGION}[Ctrl+B]") + disassemble = menu.addAction(f"{tr.DISASSEMBLE_ADDRESS}[Ctrl+D]") menu.addSeparator() - cut_record = menu.addAction("Cut selected records[Ctrl+X]") - copy_record = menu.addAction("Copy selected records[Ctrl+C]") - cut_record_recursively = menu.addAction("Cut selected records (recursive)[X]") - copy_record_recursively = menu.addAction("Copy selected records (recursive)[C]") - paste_record_before = menu.addAction("Paste selected records before[Ctrl+V]") - paste_record_after = menu.addAction("Paste selected records after[V]") - paste_record_inside = menu.addAction("Paste selected records inside[I]") - delete_record = menu.addAction("Delete selected records[Del]") + cut_record = menu.addAction(f"{tr.CUT_RECORDS}[Ctrl+X]") + copy_record = menu.addAction(f"{tr.COPY_RECORDS}[Ctrl+C]") + cut_record_recursively = menu.addAction(f"{tr.CUT_RECORDS_RECURSIVE}[X]") + copy_record_recursively = menu.addAction(f"{tr.COPY_RECORDS_RECURSIVE}[C]") + paste_record_before = menu.addAction(f"{tr.PASTE_BEFORE}[Ctrl+V]") + paste_record_after = menu.addAction(f"{tr.PASTE_AFTER}[V]") + paste_record_inside = menu.addAction(f"{tr.PASTE_INSIDE}[I]") + delete_record = menu.addAction(f"{tr.DELETE_RECORDS}[Del]") menu.addSeparator() - what_writes = menu.addAction("Find out what writes to this address") - what_reads = menu.addAction("Find out what reads this address") - what_accesses = menu.addAction("Find out what accesses this address") + what_writes = menu.addAction(tr.WHAT_WRITES) + what_reads = menu.addAction(tr.WHAT_READS) + what_accesses = menu.addAction(tr.WHAT_ACCESSES) if current_row is None: deletion_list = [edit_menu.menuAction(), show_hex, show_dec, show_unsigned, show_signed, toggle_record, freeze_menu.menuAction(), browse_region, disassemble, what_writes, what_reads, @@ -880,7 +893,7 @@ def paste_records(self, insert_after=None, insert_inside=False): try: records = ast.literal_eval(app.clipboard().text()) except (SyntaxError, ValueError): - QMessageBox.information(self, "Error", "Invalid clipboard content") + QMessageBox.information(self, tr.ERROR, tr.INVALID_CLIPBOARD) return insert_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) @@ -1026,7 +1039,7 @@ def pushButton_NewFirstScan_clicked(self): self.reset_scan() else: self.scan_mode = type_defs.SCAN_MODE.ONGOING - self.pushButton_NewFirstScan.setText("New Scan") + self.pushButton_NewFirstScan.setText(tr.NEW_SCAN) self.comboBox_ValueType.setEnabled(False) self.pushButton_NextScan.setEnabled(True) self.pushButton_UndoScan.setEnabled(True) @@ -1055,6 +1068,19 @@ def comboBox_ScanType_current_index_changed(self): self.lineEdit_Scan2.setVisible(False) def comboBox_ScanType_init(self): + scan_type_text = { + type_defs.SCAN_TYPE.EXACT: tr.EXACT, + type_defs.SCAN_TYPE.INCREASED: tr.INCREASED, + type_defs.SCAN_TYPE.INCREASED_BY: tr.INCREASED_BY, + type_defs.SCAN_TYPE.DECREASED: tr.DECREASED, + type_defs.SCAN_TYPE.DECREASED_BY: tr.DECREASED_BY, + type_defs.SCAN_TYPE.LESS: tr.LESS_THAN, + type_defs.SCAN_TYPE.MORE: tr.MORE_THAN, + type_defs.SCAN_TYPE.BETWEEN: tr.BETWEEN, + type_defs.SCAN_TYPE.CHANGED: tr.CHANGED, + type_defs.SCAN_TYPE.UNCHANGED: tr.UNCHANGED, + type_defs.SCAN_TYPE.UNKNOWN: tr.UNKNOWN_VALUE + } current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() items = type_defs.SCAN_TYPE.get_list(self.scan_mode) @@ -1062,11 +1088,17 @@ def comboBox_ScanType_init(self): for index, type_index in enumerate(items): if current_type == type_index: old_index = index - self.comboBox_ScanType.addItem(type_defs.scan_type_to_text_dict[type_index], type_index) + self.comboBox_ScanType.addItem(scan_type_text[type_index], type_index) self.comboBox_ScanType.setCurrentIndex(old_index) def comboBox_ScanScope_init(self): - for scope, text in type_defs.scan_scope_to_text_dict.items(): + scan_scope_text = [ + (type_defs.SCAN_SCOPE.BASIC, tr.BASIC), + (type_defs.SCAN_SCOPE.NORMAL, tr.NORMAL), + (type_defs.SCAN_SCOPE.FULL_RW, tr.RW), + (type_defs.SCAN_SCOPE.FULL, tr.FULL) + ] + for scope, text in scan_scope_text: self.comboBox_ScanScope.addItem(text, scope) self.comboBox_ScanScope.setCurrentIndex(1) # type_defs.SCAN_SCOPE.NORMAL @@ -1132,9 +1164,9 @@ def pushButton_NextScan_clicked(self, search_for=None): progress_running = 0 match_count = self.backend.get_match_count() if match_count > 10000: - self.label_MatchCount.setText("Match count: {} (10000 shown)".format(match_count)) + self.label_MatchCount.setText(tr.MATCH_COUNT_LIMITED.format(match_count, 10000)) else: - self.label_MatchCount.setText("Match count: {}".format(match_count)) + self.label_MatchCount.setText(tr.MATCH_COUNT.format(match_count)) self.tableWidget_valuesearchtable.setRowCount(0) current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) length = self._scan_to_length(current_type) @@ -1168,7 +1200,7 @@ def _scan_to_length(self, type_index): def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) - self.add_entry_to_addresstable("No Description", current_item.text(), + self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), current_item.data(Qt.ItemDataRole.UserRole)[0], length) def comboBox_ValueType_current_index_changed(self): @@ -1207,39 +1239,36 @@ def pushButton_AttachProcess_clicked(self): def pushButton_Open_clicked(self): pct_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.CHEAT_TABLES_PATH) - file_paths = QFileDialog.getOpenFileNames(self, "Open PCT file(s)", pct_file_path, - "PINCE Cheat Table (*.pct);;All files (*)")[0] + file_paths = QFileDialog.getOpenFileNames(self, tr.OPEN_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_paths: return if self.treeWidget_AddressTable.topLevelItemCount() > 0: - if InputDialogForm(item_list=[("Clear existing address table?",)]).exec(): + if InputDialogForm(item_list=[(tr.CLEAR_TABLE,)]).exec(): self.treeWidget_AddressTable.clear() for file_path in file_paths: content = SysUtils.load_file(file_path) if content is None: - QMessageBox.information(self, "Error", "File " + file_path + " does not exist, " + - "is inaccessible or contains invalid content. Terminating...") + QMessageBox.information(self, tr.ERROR, tr.FILE_LOAD_ERROR.format(file_path)) break self.insert_records(content, self.treeWidget_AddressTable.invisibleRootItem(), self.treeWidget_AddressTable.topLevelItemCount()) def pushButton_Save_clicked(self): pct_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.CHEAT_TABLES_PATH) - file_path = QFileDialog.getSaveFileName(self, "Save PCT file", pct_file_path, - "PINCE Cheat Table (*.pct);;All files (*)")[0] + file_path = QFileDialog.getSaveFileName(self, tr.SAVE_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_path: return content = [self.read_address_table_recursively(self.treeWidget_AddressTable.topLevelItem(i)) for i in range(self.treeWidget_AddressTable.topLevelItemCount())] file_path = SysUtils.append_file_extension(file_path, "pct") if not SysUtils.save_file(content, file_path): - QMessageBox.information(self, "Error", "Cannot save to file") + QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) # Returns: a bool value indicates whether the operation succeeded. def attach_to_pid(self, pid): attach_result = GDB_Engine.attach(pid, gdb_path) - if attach_result[0] == type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL: + if attach_result == type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL: self.apply_after_init() self.backend.send_command("pid {}".format(pid)) self.on_new_process() @@ -1250,7 +1279,14 @@ def attach_to_pid(self, pid): GDB_Engine.continue_inferior() return True else: - QMessageBox.information(app.focusWidget(), "Error", attach_result[1]) + messages = { + type_defs.ATTACH_RESULT.ATTACH_SELF: tr.SMARTASS, # easter egg + type_defs.ATTACH_RESULT.PROCESS_NOT_VALID: tr.PROCESS_NOT_VALID, + type_defs.ATTACH_RESULT.ALREADY_DEBUGGING: tr.ALREADY_DEBUGGING, + type_defs.ATTACH_RESULT.ALREADY_TRACED: tr.ALREADY_TRACED.format(SysUtils.is_traced(pid)), + type_defs.ATTACH_RESULT.PERM_DENIED: tr.PERM_DENIED + } + QMessageBox.information(app.focusWidget(), tr.ERROR, messages[attach_result]) return False # Returns: a bool value indicates whether the operation succeeded. @@ -1260,7 +1296,7 @@ def create_new_process(self, file_path, args, ld_preload_path): self.on_new_process() return True else: - QMessageBox.information(app.focusWidget(), "Error", "An error occurred while trying to create process") + QMessageBox.information(app.focusWidget(), tr.ERROR, tr.CREATE_PROCESS_ERROR) self.on_inferior_exit() return False @@ -1270,7 +1306,7 @@ def on_new_process(self): self.label_SelectedProcess.setText(str(GDB_Engine.currentpid) + " - " + name) # enable scan GUI - self.lineEdit_Scan.setPlaceholderText("Scan for") + self.lineEdit_Scan.setPlaceholderText(tr.SCAN_FOR) self.QWidget_Toolbox.setEnabled(True) self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) @@ -1283,7 +1319,7 @@ def on_new_process(self): def delete_address_table_contents(self): if self.treeWidget_AddressTable.topLevelItemCount() == 0: return - confirm_dialog = InputDialogForm(item_list=[("This will clear the contents of address table\nProceed?",)]) + confirm_dialog = InputDialogForm(item_list=[(tr.CLEAR_TABLE,)]) if confirm_dialog.exec(): self.treeWidget_AddressTable.clear() @@ -1297,7 +1333,7 @@ def copy_to_address_table(self): def reset_scan(self): self.scan_mode = type_defs.SCAN_MODE.NEW - self.pushButton_NewFirstScan.setText("First Scan") + self.pushButton_NewFirstScan.setText(tr.FIRST_SCAN) self.backend.send_command("reset") self.tableWidget_valuesearchtable.setRowCount(0) self.comboBox_ValueType.setEnabled(True) @@ -1305,7 +1341,7 @@ def reset_scan(self): self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) self.progressBar.setValue(0) - self.label_MatchCount.setText("Match count: 0") + self.label_MatchCount.setText(tr.MATCH_COUNT.format(0)) def on_inferior_exit(self): self.pushButton_MemoryView.setEnabled(False) @@ -1318,17 +1354,17 @@ def on_inferior_exit(self): self.apply_after_init() self.flashAttachButton = True self.flashAttachButtonTimer.start(100) - self.label_SelectedProcess.setText("No Process Selected") + self.label_SelectedProcess.setText(tr.NO_PROCESS_SELECTED) def on_status_detached(self): self.label_SelectedProcess.setStyleSheet("color: blue") - self.label_InferiorStatus.setText("[detached]") + self.label_InferiorStatus.setText(tr.STATUS_DETACHED) self.label_InferiorStatus.setVisible(True) self.label_InferiorStatus.setStyleSheet("color: blue") def on_status_stopped(self): self.label_SelectedProcess.setStyleSheet("color: red") - self.label_InferiorStatus.setText("[stopped]") + self.label_InferiorStatus.setText(tr.STATUS_STOPPED) self.label_InferiorStatus.setVisible(True) self.label_InferiorStatus.setStyleSheet("color: red") self.update_address_table() @@ -1383,7 +1419,7 @@ def update_address_table_loop(self): try: self.update_address_table() except: - print("Update Address Table failed :(") + print("Update Address Table failed") def update_search_table_loop(self): while exiting == 0: @@ -1391,7 +1427,7 @@ def update_search_table_loop(self): try: self.update_search_table() except: - print("Update Search Table failed :(") + print("Update Search Table failed") def freeze_loop(self): while exiting == 0: @@ -1399,7 +1435,7 @@ def freeze_loop(self): try: self.freeze() except: - print("Freeze failed :(") + print("Freeze failed") # ---------------------------------------------------- @@ -1467,8 +1503,7 @@ def treeWidget_AddressTable_edit_value(self): return value = row.text(VALUE_COL) value_index = row.data(TYPE_COL, Qt.ItemDataRole.UserRole).value_index - label_text = "Enter the new value" - dialog = InputDialogForm(item_list=[(label_text, value)], parsed_index=0, value_index=value_index) + dialog = InputDialogForm(item_list=[(tr.ENTER_VALUE, value)], parsed_index=0, value_index=value_index) if dialog.exec(): new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): @@ -1490,7 +1525,7 @@ def treeWidget_AddressTable_edit_desc(self): if not row: return description = row.text(DESC_COL) - dialog = InputDialogForm(item_list=[("Enter the new description", description)]) + dialog = InputDialogForm(item_list=[(tr.ENTER_DESCRIPTION, description)]) if dialog.exec(): description_text = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): @@ -1504,7 +1539,7 @@ def treeWidget_AddressTable_edit_address(self): manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, index=value_type.value_index, length=value_type.length, zero_terminate=value_type.zero_terminate) - manual_address_dialog.setWindowTitle("Edit Address") + manual_address_dialog.setWindowTitle(tr.EDIT_ADDRESS) if manual_address_dialog.exec(): desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() value_type = type_defs.ValueType(value_index, length, zero_terminate, value_type.value_repr) @@ -1526,7 +1561,7 @@ def treeWidget_AddressTable_edit_type(self): self.update_address_table() # Changes the column values of the given row - def change_address_table_entries(self, row, description="No Description", address_expr="", value_type=None): + def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, address_expr="", value_type=None): if isinstance(address_expr, type_defs.PointerType): address = GDB_Engine.read_pointer(address_expr) address_text = f'P->{hex(address)}' if address != None else address_expr.get_base_address() @@ -1635,7 +1670,7 @@ def refresh_process_table(self, tablewidget, processlist): def pushButton_Open_clicked(self): current_item = self.tableWidget_ProcessTable.item(self.tableWidget_ProcessTable.currentIndex().row(), 0) if current_item is None: - QMessageBox.information(self, "Error", "Please select a process first") + QMessageBox.information(self, tr.ERROR, tr.SELECT_PROCESS) else: pid = int(current_item.text()) self.setCursor(QCursor(Qt.CursorShape.WaitCursor)) @@ -1644,9 +1679,9 @@ def pushButton_Open_clicked(self): self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) def pushButton_CreateProcess_clicked(self): - file_path = QFileDialog.getOpenFileName(self, "Select the target binary")[0] + file_path = QFileDialog.getOpenFileName(self, tr.SELECT_BINARY)[0] if file_path: - items = [("Enter the optional arguments", ""), ("LD_PRELOAD .so path (optional)", "")] + items = [(tr.ENTER_OPTIONAL_ARGS, ""), (tr.LD_PRELOAD_OPTIONAL, "")] arg_dialog = InputDialogForm(item_list=items) if arg_dialog.exec(): args, ld_preload_path = arg_dialog.get_values() @@ -1660,7 +1695,7 @@ def pushButton_CreateProcess_clicked(self): # Add Address Manually Dialog class ManualAddressDialogForm(QDialog, ManualAddressDialog): - def __init__(self, parent=None, description="No Description", address="0x", + def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True): super().__init__(parent=parent) self.setupUi(self) @@ -1717,7 +1752,7 @@ def __init__(self, parent=None, description="No Description", address="0x", def label_valueofaddress_context_menu_event(self, event): menu = QMenu() - refresh = menu.addAction("Refresh") + refresh = menu.addAction(tr.REFRESH) font_size = self.label_valueofaddress.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -1830,10 +1865,10 @@ def accept(self): try: length = int(length, 0) except: - QMessageBox.information(self, "Error", "Length is not valid") + QMessageBox.information(self, tr.ERROR, tr.LENGTH_NOT_VALID) return if not length > 0: - QMessageBox.information(self, "Error", "Length must be greater than 0") + QMessageBox.information(self, tr.ERROR, tr.LENGTH_GT) return super(ManualAddressDialogForm, self).accept() @@ -1941,10 +1976,10 @@ def accept(self): try: length = int(length, 0) except: - QMessageBox.information(self, "Error", "Length is not valid") + QMessageBox.information(self, tr.ERROR, tr.LENGTH_NOT_VALID) return if not length > 0: - QMessageBox.information(self, "Error", "Length must be greater than 0") + QMessageBox.information(self, tr.ERROR, tr.LENGTH_GT) return super(EditTypeDialogForm, self).accept() @@ -2098,7 +2133,7 @@ def accept(self): if self.parsed_index != -1: item = self.object_list[self.parsed_index] if SysUtils.parse_string(self.get_text(item), self.value_index) is None: - QMessageBox.information(self, "Error", "Can't parse the input") + QMessageBox.information(self, tr.ERROR, tr.PARSE_ERROR) return super(InputDialogForm, self).accept() @@ -2151,36 +2186,31 @@ def accept(self): try: current_table_update_interval = int(self.lineEdit_UpdateInterval.text()) except: - QMessageBox.information(self, "Error", "Update interval must be an int") + QMessageBox.information(self, tr.ERROR, tr.UPDATE_ASSERT_INT) return try: current_freeze_interval = int(self.lineEdit_FreezeInterval.text()) except: - QMessageBox.information(self, "Error", "Freeze interval must be an int") + QMessageBox.information(self, tr.ERROR, tr.FREEZE_ASSERT_INT) return try: current_instructions_shown = int(self.lineEdit_InstructionsPerScroll.text()) except: - QMessageBox.information(self, "Error", "Instruction count must be an integer") + QMessageBox.information(self, tr.ERROR, tr.INSTRUCTION_ASSERT_INT) return if current_instructions_shown < 1: - QMessageBox.information(self, "Error", "Instruction count cannot be lower than 1" + - "\nIt would be silly anyway, wouldn't it?") + QMessageBox.information(self, tr.ERROR, tr.INSTRUCTION_ASSERT_LT.format(1)) return if not self.checkBox_AutoUpdateAddressTable.isChecked(): pass elif current_table_update_interval < 0 or current_freeze_interval < 0: - QMessageBox.information(self, "Error", "Interval cannot be a negative number") + QMessageBox.information(self, tr.ERROR, tr.INTERVAL_ASSERT_NEGATIVE) return elif current_table_update_interval == 0 or current_freeze_interval == 0: - - # Easter egg #2 - if not InputDialogForm(item_list=[("You are asking for it, aren't you?",)]).exec(): + if not InputDialogForm(item_list=[(tr.ASKING_FOR_TROUBLE,)]).exec(): # Easter egg return elif current_table_update_interval < 100: - if not InputDialogForm(item_list=[("Update interval should be bigger than 100 ms" + - "\nSetting update interval less than 100 ms may cause slowdown" - "\nProceed?",)]).exec(): + if not InputDialogForm(item_list=[(tr.UPDATE_ASSERT_GT.format(100),)]).exec(): return self.settings.setValue("General/auto_update_address_table", self.checkBox_AutoUpdateAddressTable.isChecked()) @@ -2196,7 +2226,7 @@ def accept(self): try: re.compile(self.lineEdit_AutoAttachList.text()) except: - QMessageBox.information(self, "Error", self.lineEdit_AutoAttachList.text() + " isn't a valid regex") + QMessageBox.information(self, tr.ERROR, tr.IS_INVALID_REGEX.format(self.lineEdit_AutoAttachList.text())) return self.settings.setValue("General/auto_attach_list", self.lineEdit_AutoAttachList.text()) self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) @@ -2214,7 +2244,7 @@ def accept(self): selected_gdb_path = self.lineEdit_GDBPath.text() current_gdb_path = self.settings.value("Debug/gdb_path", type=str) if selected_gdb_path != current_gdb_path: - if InputDialogForm(item_list=[("You have changed the GDB path, reset GDB now?",)]).exec(): + if InputDialogForm(item_list=[(tr.GDB_RESET,)]).exec(): GDB_Engine.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) @@ -2278,7 +2308,7 @@ def pushButton_ClearHotkey_clicked(self): self.keySequenceEdit.clear() def pushButton_ResetSettings_clicked(self): - confirm_dialog = InputDialogForm(item_list=[("This will reset to the default settings\nProceed?",)]) + confirm_dialog = InputDialogForm(item_list=[(tr.RESET_DEFAULT_SETTINGS,)]) if confirm_dialog.exec(): self.set_default_settings() self.handle_signals_data = None @@ -2292,18 +2322,15 @@ def checkBox_AutoUpdateAddressTable_state_changed(self): def checkBox_AutoAttachRegex_state_changed(self): if self.checkBox_AutoAttachRegex.isChecked(): - self.lineEdit_AutoAttachList.setPlaceholderText("Mouse over on this text for examples") - self.lineEdit_AutoAttachList.setToolTip("asdf|qwer --> search for asdf or qwer\n" + - "[as]df --> search for both adf and sdf\n" + - "Use the char \\ to escape special chars such as [\n" + - "\[asdf\] --> search for opcodes that contain [asdf]") + self.lineEdit_AutoAttachList.setPlaceholderText(tr.MOUSE_OVER_EXAMPLES) + self.lineEdit_AutoAttachList.setToolTip(tr.AUTO_ATTACH_TOOLTIP) else: - self.lineEdit_AutoAttachList.setPlaceholderText("Separate processes with ;") + self.lineEdit_AutoAttachList.setPlaceholderText(tr.SEPARATE_PROCESSES_WITH.format(";")) self.lineEdit_AutoAttachList.setToolTip("") def pushButton_GDBPath_clicked(self): current_path = self.lineEdit_GDBPath.text() - file_path = QFileDialog.getOpenFileName(self, "Select the gdb binary", os.path.dirname(current_path))[0] + file_path = QFileDialog.getOpenFileName(self, tr.SELECT_GDB_BINARY, os.path.dirname(current_path))[0] if file_path: self.lineEdit_GDBPath.setText(file_path) @@ -2399,7 +2426,7 @@ def communicate(self, control=False): return self.lineEdit.clear() if console_input.strip().lower() in self.quit_commands: - console_output = "Quitting current session will crash PINCE" + console_output = tr.QUIT_SESSION_CRASH else: if not control: if self.radioButton_CLI.isChecked(): @@ -2408,7 +2435,7 @@ def communicate(self, control=False): console_output = GDB_Engine.send_command(console_input) if not console_output: if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - console_output = "Inferior is running" + console_output = tr.INFERIOR_RUNNING else: GDB_Engine.interrupt_inferior() console_output = "" @@ -2419,35 +2446,7 @@ def communicate(self, control=False): def reset_console_text(self): self.textBrowser.clear() - self.textBrowser.append("Hotkeys:") - self.textBrowser.append("----------------------------") - self.textBrowser.append("Send=Enter |") - self.textBrowser.append("Send ctrl+c=Ctrl+C |") - self.textBrowser.append("Multi-line mode=Ctrl+Enter |") - self.textBrowser.append("Complete command=Tab |") - self.textBrowser.append("----------------------------") - self.textBrowser.append("Commands:") - self.textBrowser.append("----------------------------------------------------------") - self.textBrowser.append("/clear: Clear the console |") - self.textBrowser.append("phase-out: Detach from the current process |") - self.textBrowser.append("phase-in: Attach back to the previously detached process |") - self.textBrowser.append( - "---------------------------------------------------------------------------------------------------") - self.textBrowser.append( - "pince-init-so-file so_file_path: Initializes 'lib' variable |") - self.textBrowser.append( - "pince-get-so-file-information: Get information about current lib |") - self.textBrowser.append( - "pince-execute-from-so-file lib.func(params): Execute a function from lib |") - self.textBrowser.append( - "# Check https://github.com/korcankaraokcu/PINCE/wiki#extending-pince-with-so-files for an example |") - self.textBrowser.append( - "# CLI output mode doesn't work very well with .so extensions, use MI output mode instead |") - self.textBrowser.append( - "---------------------------------------------------------------------------------------------------") - self.textBrowser.append("You can change the output mode from bottom right") - self.textBrowser.append("Note: Changing output mode only affects commands sent. Any other " + - "output coming from external sources(e.g async output) will be shown in MI format") + self.textBrowser.append(tr.GDB_CONSOLE_INIT) def scroll_to_bottom(self): cursor = self.textBrowser.textCursor() @@ -2513,6 +2512,8 @@ def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) GuiUtils.center(self) + + # This section has untranslated text since it's just a placeholder license_text = open("COPYING").read() authors_text = open("AUTHORS").read() thanks_text = open("THANKS").read() @@ -2535,9 +2536,9 @@ class MemoryViewWindowForm(QMainWindow, MemoryViewWindow): process_running = pyqtSignal() def set_dynamic_debug_hotkeys(self): - self.actionBreak.setText("Break[" + Hotkeys.break_hotkey.get_active_key() + "]") - self.actionRun.setText("Run[" + Hotkeys.continue_hotkey.get_active_key() + "]") - self.actionToggle_Attach.setText("Toggle Attach[" + Hotkeys.toggle_attach_hotkey.get_active_key() + "]") + self.actionBreak.setText(tr.BREAK.format(Hotkeys.break_hotkey.get_active_key())) + self.actionRun.setText(tr.RUN.format(Hotkeys.continue_hotkey.get_active_key())) + self.actionToggle_Attach.setText(tr.TOGGLE_ATTACH.format(Hotkeys.toggle_attach_hotkey.get_active_key())) def set_debug_menu_shortcuts(self): self.shortcut_step = QShortcut(QKeySequence("F7"), self) @@ -2775,7 +2776,7 @@ def toggle_breakpoint(self): GDB_Engine.delete_breakpoint(current_address) else: if not GDB_Engine.add_breakpoint(current_address): - QMessageBox.information(self, "Error", "Failed to set breakpoint at address " + current_address) + QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_FAILED.format(current_address)) self.refresh_disassemble_view() def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.BOTH): @@ -2784,18 +2785,18 @@ def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.B if GDB_Engine.check_address_in_breakpoints(address): GDB_Engine.delete_breakpoint(hex(address)) else: - watchpoint_dialog = InputDialogForm(item_list=[("Enter the watchpoint length in size of bytes", "")]) + watchpoint_dialog = InputDialogForm(item_list=[(tr.ENTER_WATCHPOINT_LENGTH, "")]) if watchpoint_dialog.exec(): user_input = watchpoint_dialog.get_values() user_input_int = SysUtils.parse_string(user_input, type_defs.VALUE_INDEX.INDEX_INT32) if user_input_int is None: - QMessageBox.information(self, "Error", user_input + " can't be parsed as an integer") + QMessageBox.information(self, tr.ERROR, tr.PARSE_ERROR_INT.format(user_input)) return if user_input_int < 1: - QMessageBox.information(self, "Error", "Breakpoint length can't be lower than 1") + QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_ASSERT_LT.format(1)) return if len(GDB_Engine.add_watchpoint(hex(address), user_input_int, watchpoint_type)) < 1: - QMessageBox.information(self, "Error", "Failed to set watchpoint at address " + hex(address)) + QMessageBox.information(self, tr.ERROR, tr.WATCHPOINT_FAILED.format(hex(address))) self.refresh_hex_view() def label_HexView_Information_context_menu_event(self, event): @@ -2806,7 +2807,7 @@ def copy_to_clipboard(): app.clipboard().setText(self.label_HexView_Information.text()) menu = QMenu() - copy_label = menu.addAction("Copy to Clipboard") + copy_label = menu.addAction(tr.COPY_CLIPBOARD) font_size = self.label_HexView_Information.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -2823,21 +2824,21 @@ def widget_HexView_context_menu_event(self, event): return selected_address = self.tableView_HexView_Hex.get_selected_address() menu = QMenu() - edit = menu.addAction("Edit") + edit = menu.addAction(tr.EDIT) menu.addSeparator() - go_to = menu.addAction("Go to expression[Ctrl+G]") - disassemble = menu.addAction("Disassemble this address[Ctrl+D]") + go_to = menu.addAction(f"{tr.GO_TO_EXPRESSION}[Ctrl+G]") + disassemble = menu.addAction(f"{tr.DISASSEMBLE_ADDRESS}[Ctrl+D]") menu.addSeparator() - add_address = menu.addAction("Add this address to address list[Ctrl+A]") + add_address = menu.addAction(f"{tr.ADD_TO_ADDRESS_LIST}[Ctrl+A]") menu.addSeparator() - refresh = menu.addAction("Refresh[R]") + refresh = menu.addAction(f"{tr.REFRESH}[R]") menu.addSeparator() - watchpoint_menu = menu.addMenu("Set Watchpoint") - watchpoint_write = watchpoint_menu.addAction("Write Only") - watchpoint_read = watchpoint_menu.addAction("Read Only") - watchpoint_both = watchpoint_menu.addAction("Both") - add_condition = menu.addAction("Add/Change condition for breakpoint") - delete_breakpoint = menu.addAction("Delete Breakpoint") + watchpoint_menu = menu.addMenu(tr.SET_WATCHPOINT) + watchpoint_write = watchpoint_menu.addAction(tr.WRITE_ONLY) + watchpoint_read = watchpoint_menu.addAction(tr.READ_ONLY) + watchpoint_both = watchpoint_menu.addAction(tr.BOTH) + add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) + delete_breakpoint = menu.addAction(tr.DELETE_BREAKPOINT) if not GDB_Engine.check_address_in_breakpoints(selected_address): GuiUtils.delete_menu_entries(menu, [add_condition, delete_breakpoint]) else: @@ -2873,12 +2874,12 @@ def exec_hex_view_go_to_dialog(self): if GDB_Engine.currentpid == -1: return current_address = hex(self.tableView_HexView_Hex.get_selected_address()) - go_to_dialog = InputDialogForm(item_list=[("Enter the expression", current_address)]) + go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, current_address)]) if go_to_dialog.exec(): expression = go_to_dialog.get_values() dest_address = GDB_Engine.examine_expression(expression).address if not dest_address: - QMessageBox.information(self, "Error", expression + " is invalid") + QMessageBox.information(self, tr.ERROR, tr.INVALID.format(expression)) return self.hex_dump_address(int(dest_address, 16)) @@ -2973,15 +2974,14 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL return int_address = SysUtils.modulo_address(int_address, GDB_Engine.inferior_arch) if not (self.hex_view_current_region.start <= int_address < self.hex_view_current_region.end): - information = SysUtils.get_region_info(GDB_Engine.currentpid, int_address) - if information: - self.hex_view_current_region = information - self.label_HexView_Information.setText("Protection:" + information.perms + " | Base:" + - hex(information.start) + "-" + hex(information.end) + - " | Module:" + information.file_name) + info = SysUtils.get_region_info(GDB_Engine.currentpid, int_address) + if info: + self.hex_view_current_region = info + self.label_HexView_Information.setText(tr.REGION_INFO.format( + info.perms, hex(info.start), hex(info.end), info.file_name)) else: self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) - self.label_HexView_Information.setText("This region is invalid") + self.label_HexView_Information.setText(tr.INVALID_REGION) self.tableWidget_HexView_Address.setRowCount(0) self.tableWidget_HexView_Address.setRowCount(HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT) for row, current_offset in enumerate(range(HEX_VIEW_ROW_COUNT)): @@ -3041,7 +3041,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his return disas_data = GDB_Engine.disassemble(expression, offset) if not disas_data: - QMessageBox.information(app.focusWidget(), "Error", "Cannot access memory at expression " + expression) + QMessageBox.information(app.focusWidget(), tr.ERROR, tr.EXPRESSION_ACCESS_ERROR.format(expression)) return False program_counter = GDB_Engine.examine_expression("$pc").address program_counter_int = int(program_counter, 16) @@ -3076,7 +3076,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his except KeyError: pass if jmp_ref_exists or call_ref_exists: - tooltip_text = "Referenced by:\n" + tooltip_text = f"{tr.REFERENCED_BY}\n" ref_count = 0 if jmp_ref_exists: for referrer in jmp_referrers: @@ -3092,7 +3092,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his ref_count += 1 if ref_count > 30: tooltip_text += "\n..." - tooltip_text += "\n\nPress 'Ctrl+E' to see a detailed list of referrers" + tooltip_text += f"\n\n{tr.SEE_REFERRERS}" try: row_colour[row].append(REF_COLOUR) except KeyError: @@ -3203,16 +3203,11 @@ def set_row_colour(self, row, colour): def on_process_stop(self): if GDB_Engine.stop_reason == type_defs.STOP_REASON.PAUSE: - self.setWindowTitle("Memory Viewer - Paused") + self.setWindowTitle(tr.MV_PAUSED) return self.updating_memoryview = True time0 = time() - thread_info = GDB_Engine.get_thread_info() - if thread_info: - self.setWindowTitle("Memory Viewer - Currently debugging " + thread_info) - else: - self.setWindowTitle("Error while getting thread information: " + - "Please invoke 'info threads' command in GDB Console and open an issue with the output") + self.setWindowTitle(tr.MV_DEBUGGING.format(GDB_Engine.get_thread_info())) self.disassemble_expression("$pc") self.update_registers() if self.stackedWidget_StackScreens.currentWidget() == self.StackTrace: @@ -3239,28 +3234,23 @@ def on_process_stop(self): self.updating_memoryview = False def on_process_running(self): - self.setWindowTitle("Memory Viewer - Running") + self.setWindowTitle(tr.MV_RUNNING) def add_breakpoint_condition(self, int_address): if GDB_Engine.currentpid == -1: return - condition_text = "Enter the expression for condition, for instance:\n\n" + \ - "$eax==0x523\n" + \ - "$rax>0 && ($rbp<0 || $rsp==0)\n" + \ - "printf($r10)==3" breakpoint = GDB_Engine.check_address_in_breakpoints(int_address) if breakpoint: condition_line_edit_text = breakpoint.condition else: condition_line_edit_text = "" condition_dialog = InputDialogForm( - item_list=[(condition_text, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) + item_list=[(tr.ENTER_BP_CONDITION, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) if condition_dialog.exec(): condition = condition_dialog.get_values() if not GDB_Engine.modify_breakpoint(hex(int_address), type_defs.BREAKPOINT_MODIFY.CONDITION, condition=condition): - QMessageBox.information(app.focusWidget(), "Error", "Failed to set condition for address " + - hex(int_address) + "\nCheck terminal for details") + QMessageBox.information(app.focusWidget(), tr.ERROR, tr.BP_CONDITION_FAILED.format(hex(int_address))) def update_registers(self): if GDB_Engine.currentpid == -1: @@ -3341,14 +3331,14 @@ def copy_to_clipboard(row, column): selected_row = GuiUtils.get_current_row(self.tableWidget_StackTrace) menu = QMenu() - switch_to_stack = menu.addAction("Full Stack") + switch_to_stack = menu.addAction(tr.FULL_STACK) menu.addSeparator() - clipboard_menu = menu.addMenu("Copy to Clipboard") - copy_return = clipboard_menu.addAction("Copy Return Address") - copy_frame = clipboard_menu.addAction("Copy Frame Address") + clipboard_menu = menu.addMenu(tr.COPY_CLIPBOARD) + copy_return = clipboard_menu.addAction(tr.COPY_RETURN_ADDRESS) + copy_frame = clipboard_menu.addAction(tr.COPY_FRAME_ADDRESS) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [clipboard_menu.menuAction()]) - refresh = menu.addAction("Refresh[R]") + refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.tableWidget_StackTrace.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -3410,16 +3400,16 @@ def copy_to_clipboard(row, column): current_address = SysUtils.extract_address(current_address_text) menu = QMenu() - switch_to_stacktrace = menu.addAction("Stacktrace") + switch_to_stacktrace = menu.addAction(tr.STACKTRACE) menu.addSeparator() - clipboard_menu = menu.addMenu("Copy to Clipboard") - copy_address = clipboard_menu.addAction("Copy Address") - copy_value = clipboard_menu.addAction("Copy Value") - copy_points_to = clipboard_menu.addAction("Copy Points to") - refresh = menu.addAction("Refresh[R]") + clipboard_menu = menu.addMenu(tr.COPY_CLIPBOARD) + copy_address = clipboard_menu.addAction(tr.COPY_ADDRESS) + copy_value = clipboard_menu.addAction(tr.COPY_VALUE) + copy_points_to = clipboard_menu.addAction(tr.COPY_POINTS_TO) + refresh = menu.addAction(f"{tr.REFRESH}[R]") menu.addSeparator() - show_in_disas = menu.addAction("Disassemble 'value' pointer address[Ctrl+D]") - show_in_hex = menu.addAction("Show 'value' pointer in HexView[Ctrl+H]") + show_in_disas = menu.addAction(f"{tr.DISASSEMBLE_VALUE_POINTER}[Ctrl+D]") + show_in_hex = menu.addAction(f"{tr.HEXVIEW_VALUE_POINTER}[Ctrl+H]") if selected_row == -1: GuiUtils.delete_menu_entries(menu, [clipboard_menu.menuAction(), show_in_disas, show_in_hex]) font_size = self.tableWidget_Stack.font().pointSize() @@ -3645,52 +3635,52 @@ def copy_all_columns(row): current_address_int = int(current_address, 16) menu = QMenu() - go_to = menu.addAction("Go to expression[Ctrl+G]") - back = menu.addAction("Back") - show_in_hex_view = menu.addAction("Show this address in HexView[Ctrl+H]") + go_to = menu.addAction(f"{tr.GO_TO_EXPRESSION}[Ctrl+G]") + back = menu.addAction(tr.BACK) + show_in_hex_view = menu.addAction(f"{tr.HEXVIEW_ADDRESS}[Ctrl+H]") menu.addSeparator() followable = SysUtils.instruction_follow_address( self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text()) - follow = menu.addAction("Follow[Space]") + follow = menu.addAction(f"{tr.FOLLOW}[Space]") if not followable: GuiUtils.delete_menu_entries(menu, [follow]) - examine_referrers = menu.addAction("Examine Referrers[Ctrl+E]") + examine_referrers = menu.addAction(f"{tr.EXAMINE_REFERRERS}[Ctrl+E]") if not GuiUtils.contains_reference_mark(current_address_text): GuiUtils.delete_menu_entries(menu, [examine_referrers]) - bookmark = menu.addAction("Bookmark this address[Ctrl+B]") - delete_bookmark = menu.addAction("Delete this bookmark") - change_comment = menu.addAction("Change comment") + bookmark = menu.addAction(f"{tr.BOOKMARK_ADDRESS}[Ctrl+B]") + delete_bookmark = menu.addAction(tr.DELETE_BOOKMARK) + change_comment = menu.addAction(tr.CHANGE_COMMENT) is_bookmarked = current_address_int in self.tableWidget_Disassemble.bookmarks if not is_bookmarked: GuiUtils.delete_menu_entries(menu, [delete_bookmark, change_comment]) else: GuiUtils.delete_menu_entries(menu, [bookmark]) - go_to_bookmark = menu.addMenu("Go to bookmarked address") + go_to_bookmark = menu.addMenu(tr.GO_TO_BOOKMARK_ADDRESS) address_list = [hex(address) for address in self.tableWidget_Disassemble.bookmarks.keys()] bookmark_actions = [go_to_bookmark.addAction(item.all) for item in GDB_Engine.examine_expressions(address_list)] menu.addSeparator() - toggle_breakpoint = menu.addAction("Toggle Breakpoint[F5]") - add_condition = menu.addAction("Add/Change condition for breakpoint") + toggle_breakpoint = menu.addAction(f"{tr.TOGGLE_BREAKPOINT}[F5]") + add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) if not GDB_Engine.check_address_in_breakpoints(current_address_int): GuiUtils.delete_menu_entries(menu, [add_condition]) menu.addSeparator() - edit_instruction = menu.addAction("Edit instruction") - nop_instruction = menu.addAction("Replace instruction with NOPs") + edit_instruction = menu.addAction(tr.EDIT_INSTRUCTION) + nop_instruction = menu.addAction(tr.REPLACE_WITH_NOPS) if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() == '90': GuiUtils.delete_menu_entries(menu, [nop_instruction]) menu.addSeparator() - track_breakpoint = menu.addAction("Find out which addresses this instruction accesses") - trace_instructions = menu.addAction("Break and trace instructions[Ctrl+T]") - dissect_region = menu.addAction("Dissect this region[Ctrl+D]") + track_breakpoint = menu.addAction(tr.WHAT_ACCESSES_INSTRUCTION) + trace_instructions = menu.addAction(f"{tr.TRACE_INSTRUCTION}[Ctrl+T]") + dissect_region = menu.addAction(f"{tr.DISSECT_REGION}[Ctrl+D]") menu.addSeparator() - refresh = menu.addAction("Refresh[R]") + refresh = menu.addAction(f"{tr.REFRESH}[R]") menu.addSeparator() - clipboard_menu = menu.addMenu("Copy to Clipboard") - copy_address = clipboard_menu.addAction("Copy Address") - copy_bytes = clipboard_menu.addAction("Copy Bytes") - copy_opcode = clipboard_menu.addAction("Copy Opcode") - copy_comment = clipboard_menu.addAction("Copy Comment") - copy_all = clipboard_menu.addAction("Copy All") + clipboard_menu = menu.addMenu(tr.COPY_CLIPBOARD) + copy_address = clipboard_menu.addAction(tr.COPY_ADDRESS) + copy_bytes = clipboard_menu.addAction(tr.COPY_BYTES) + copy_opcode = clipboard_menu.addAction(tr.COPY_OPCODE) + copy_comment = clipboard_menu.addAction(tr.COPY_COMMENT) + copy_all = clipboard_menu.addAction(tr.COPY_ALL) font_size = self.tableWidget_Disassemble.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -3764,17 +3754,7 @@ def exec_track_breakpoint_dialog(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_instruction = self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() - label_text = "Enter the register expression(s) you want to track" \ - "\nRegister names must start with $" \ - "\nEach expression must be separated with a comma" \ - "\n\nFor instance:" \ - "\nLet's say the instruction is mov [rax+rbx],30" \ - "\nThen you should enter $rax+$rbx" \ - "\nSo PINCE can track address [rax+rbx]" \ - "\n\nAnother example:" \ - "\nIf you enter $rax,$rbx*$rcx+4,$rbp" \ - "\nPINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]" - register_expression_dialog = InputDialogForm(item_list=[(label_text, "")]) + register_expression_dialog = InputDialogForm(item_list=[(tr.ENTER_TRACK_BP_EXPRESSION, "")]) if register_expression_dialog.exec(): exp = register_expression_dialog.get_values() track_breakpoint_widget = TrackBreakpointWidgetForm(current_address, current_instruction, exp, self) @@ -3789,7 +3769,7 @@ def exec_disassemble_go_to_dialog(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) - go_to_dialog = InputDialogForm(item_list=[("Enter the expression", current_address)]) + go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, current_address)]) if go_to_dialog.exec(): traveled_exp = go_to_dialog.get_values() self.disassemble_expression(traveled_exp, append_to_travel_history=True) @@ -3798,9 +3778,9 @@ def bookmark_address(self, int_address): if GDB_Engine.currentpid == -1: return if int_address in self.tableWidget_Disassemble.bookmarks: - QMessageBox.information(app.focusWidget(), "Error", "This address has already been bookmarked") + QMessageBox.information(app.focusWidget(), tr.ERROR, tr.ALREADY_BOOKMARKED) return - comment_dialog = InputDialogForm(item_list=[("Enter the comment for bookmarked address", "")]) + comment_dialog = InputDialogForm(item_list=[(tr.ENTER_BOOKMARK_COMMENT, "")]) if comment_dialog.exec(): comment = comment_dialog.get_values() else: @@ -3812,7 +3792,7 @@ def change_bookmark_comment(self, int_address): if GDB_Engine.currentpid == -1: return current_comment = self.tableWidget_Disassemble.bookmarks[int_address] - comment_dialog = InputDialogForm(item_list=[("Enter the comment for bookmarked address", current_comment)]) + comment_dialog = InputDialogForm(item_list=[(tr.ENTER_BOOKMARK_COMMENT, current_comment)]) if comment_dialog.exec(): new_comment = comment_dialog.get_values() else: @@ -3886,32 +3866,23 @@ def actionReferenced_Calls_triggered(self): def actionInject_so_file_triggered(self): if GDB_Engine.currentpid == -1: return - file_path = QFileDialog.getOpenFileName(self, "Select the .so file", "", "Shared object library (*.so)")[0] + file_path = QFileDialog.getOpenFileName(self, tr.SELECT_SO_FILE, "", tr.SHARED_OBJECT_TYPE)[0] if file_path: if GDB_Engine.inject_with_dlopen_call(file_path): - QMessageBox.information(self, "Success!", "The file has been injected") + QMessageBox.information(self, tr.SUCCESS, tr.FILE_INJECTED) else: - QMessageBox.information(self, "Error", "Failed to inject the .so file") + QMessageBox.information(self, tr.ERROR, tr.FILE_INJECT_FAILED) def actionCall_Function_triggered(self): if GDB_Engine.currentpid == -1: return - label_text = "Enter the expression for the function that'll be called from the inferior" \ - "\nYou can view functions list from View->Functions" \ - "\n\nFor instance:" \ - '\nCalling printf("1234") will yield something like this' \ - '\n↓' \ - '\n$28 = 4' \ - '\n\n$28 is the assigned convenience variable' \ - '\n4 is the result' \ - '\nYou can use the assigned variable from the GDB Console' - call_dialog = InputDialogForm(item_list=[(label_text, "")]) + call_dialog = InputDialogForm(item_list=[(tr.ENTER_CALL_EXPRESSION, "")]) if call_dialog.exec(): result = GDB_Engine.call_function_from_inferior(call_dialog.get_values()) if result[0]: - QMessageBox.information(self, "Success!", result[0] + " = " + result[1]) + QMessageBox.information(self, tr.SUCCESS, result[0] + " = " + result[1]) else: - QMessageBox.information(self, "Failed", "Failed to call the expression " + call_dialog.get_values()) + QMessageBox.information(self, tr.ERROR, tr.CALL_EXPRESSION_FAILED.format(call_dialog.get_values())) def actionSearch_Opcode_triggered(self): if GDB_Engine.currentpid == -1: @@ -3974,12 +3945,12 @@ def listWidget_item_double_clicked(self, item): self.parent().disassemble_expression(SysUtils.extract_address(item.text()), append_to_travel_history=True) def exec_add_entry_dialog(self): - entry_dialog = InputDialogForm(item_list=[("Enter the expression", "")]) + entry_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, "")]) if entry_dialog.exec(): text = entry_dialog.get_values() address = GDB_Engine.examine_expression(text).address if not address: - QMessageBox.information(self, "Error", "Invalid expression or address") + QMessageBox.information(self, tr.ERROR, tr.INVALID_EXPRESSION) return self.parent().bookmark_address(int(address, 16)) self.refresh_table() @@ -3993,19 +3964,19 @@ def listWidget_context_menu_event(self, event): if current_item: current_address = int(SysUtils.extract_address(current_item.text()), 16) if current_address not in self.parent().tableWidget_Disassemble.bookmarks: - QMessageBox.information(self, "Error", "Invalid entries detected, refreshing the page") + QMessageBox.information(self, tr.ERROR, tr.INVALID_ENTRY) self.refresh_table() return else: current_address = None menu = QMenu() - add_entry = menu.addAction("Add new entry") - change_comment = menu.addAction("Change comment of this record") - delete_record = menu.addAction("Delete this record[Del]") + add_entry = menu.addAction(tr.ADD_ENTRY) + change_comment = menu.addAction(tr.CHANGE_COMMENT) + delete_record = menu.addAction(f"{tr.DELETE}[Del]") if current_item is None: GuiUtils.delete_menu_entries(menu, [change_comment, delete_record]) menu.addSeparator() - refresh = menu.addAction("Refresh[R]") + refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.listWidget.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -4064,7 +4035,7 @@ def set_register(self, index): raise Exception("Current widget is invalid: " + str(self.currentWidget().objectName())) current_register = current_table_widget.item(current_row, FLOAT_REGISTERS_NAME_COL).text() current_value = current_table_widget.item(current_row, FLOAT_REGISTERS_VALUE_COL).text() - label_text = "Enter the new value of register " + current_register.upper() + label_text = tr.ENTER_REGISTER_VALUE.format(current_register.upper()) register_dialog = InputDialogForm(item_list=[(label_text, current_value)]) if register_dialog.exec(): if self.currentWidget() == self.XMM: @@ -4112,7 +4083,7 @@ def __init__(self, parent=None): def tableWidget_Instructions_context_menu_event(self, event): selected_row = GuiUtils.get_current_row(self.tableWidget_Instructions) menu = QMenu() - restore_instruction = menu.addAction("Restore this instruction") + restore_instruction = menu.addAction(tr.RESTORE_INSTRUCTION) if selected_row != -1: selected_address_text = self.tableWidget_Instructions.item(selected_row, INSTR_ADDR_COL).text() selected_address = SysUtils.extract_address(selected_address_text) @@ -4121,7 +4092,7 @@ def tableWidget_Instructions_context_menu_event(self, event): GuiUtils.delete_menu_entries(menu, [restore_instruction]) selected_address_int = None menu.addSeparator() - refresh = menu.addAction("Refresh[R]") + refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.tableWidget_Instructions.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -4235,16 +4206,16 @@ def tableWidget_BreakpointInfo_key_press_event(self, event): self.tableWidget_BreakpointInfo.keyPressEvent_original(event) def exec_enable_count_dialog(self, current_address): - hit_count_dialog = InputDialogForm(item_list=[("Enter the hit count(1 or higher)", "")]) + hit_count_dialog = InputDialogForm(item_list=[(tr.ENTER_HIT_COUNT.format(1), "")]) if hit_count_dialog.exec(): count = hit_count_dialog.get_values() try: count = int(count) except ValueError: - QMessageBox.information(self, "Error", "Hit count must be an integer") + QMessageBox.information(self, tr.ERROR, tr.HIT_COUNT_ASSERT_INT) else: if count < 1: - QMessageBox.information(self, "Error", "Hit count can't be lower than 1") + QMessageBox.information(self, tr.ERROR, tr.HIT_COUNT_ASSERT_LT.format(1)) else: GDB_Engine.modify_breakpoint(current_address, type_defs.BREAKPOINT_MODIFY.ENABLE_COUNT, count=count) @@ -4260,20 +4231,20 @@ def tableWidget_BreakpointInfo_context_menu_event(self, event): current_address_int = None menu = QMenu() - change_condition = menu.addAction("Change condition of this breakpoint") - enable = menu.addAction("Enable this breakpoint") - disable = menu.addAction("Disable this breakpoint") - enable_once = menu.addAction("Disable this breakpoint after hit") - enable_count = menu.addAction("Disable this breakpoint after X hits") - enable_delete = menu.addAction("Delete this breakpoint after hit") + change_condition = menu.addAction(tr.CHANGE_CONDITION) + enable = menu.addAction(tr.ENABLE) + disable = menu.addAction(tr.DISABLE) + enable_once = menu.addAction(tr.DISABLE_AFTER_HIT) + enable_count = menu.addAction(tr.DISABLE_AFTER_COUNT) + enable_delete = menu.addAction(tr.DELETE_AFTER_HIT) menu.addSeparator() - delete_breakpoint = menu.addAction("Delete this breakpoint[Del]") + delete_breakpoint = menu.addAction(f"{tr.DELETE}[Del]") menu.addSeparator() if current_address is None: deletion_list = [change_condition, enable, disable, enable_once, enable_count, enable_delete, delete_breakpoint] GuiUtils.delete_menu_entries(menu, deletion_list) - refresh = menu.addAction("Refresh[R]") + refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.tableWidget_BreakpointInfo.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -4330,17 +4301,17 @@ def __init__(self, address, length, watchpoint_type, parent=None): GuiUtils.center(self) self.setWindowFlags(Qt.WindowType.Window) if watchpoint_type == type_defs.WATCHPOINT_TYPE.WRITE_ONLY: - string = "writing to" + string = tr.OPCODE_WRITING_TO.format(address) elif watchpoint_type == type_defs.WATCHPOINT_TYPE.READ_ONLY: - string = "reading from" + string = tr.OPCODE_READING_FROM.format(address) elif watchpoint_type == type_defs.WATCHPOINT_TYPE.BOTH: - string = "accessing to" + string = tr.OPCODE_ACCESSING_TO.format(address) else: raise Exception("Watchpoint type is invalid: " + str(watchpoint_type)) - self.setWindowTitle("Opcodes " + string + " the address " + address) + self.setWindowTitle(string) breakpoints = GDB_Engine.track_watchpoint(address, length, watchpoint_type) if not breakpoints: - QMessageBox.information(self, "Error", "Unable to track watchpoint at expression " + address) + QMessageBox.information(self, tr.ERROR, tr.TRACK_WATCHPOINT_FAILED.format(address)) return self.address = address self.breakpoints = breakpoints @@ -4397,10 +4368,10 @@ def pushButton_Stop_clicked(self): if self.stopped: self.close() if not GDB_Engine.execute_func_temporary_interruption(GDB_Engine.delete_breakpoint, self.address): - QMessageBox.information(self, "Error", "Unable to delete watchpoint at expression " + self.address) + QMessageBox.information(self, tr.ERROR, tr.DELETE_WATCHPOINT_FAILED.format(self.address)) return self.stopped = True - self.pushButton_Stop.setText("Close") + self.pushButton_Stop.setText(tr.CLOSE) @GDB_Engine.execute_with_temporary_interruption def closeEvent(self, QCloseEvent): @@ -4420,11 +4391,12 @@ def __init__(self, address, instruction, register_expressions, parent=None): instances.append(self) self.setWindowFlags(Qt.WindowType.Window) GuiUtils.center_to_parent(self) - self.setWindowTitle("Addresses accessed by instruction '" + instruction + "'") + self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) breakpoint = GDB_Engine.track_breakpoint(address, register_expressions) if not breakpoint: - QMessageBox.information(self, "Error", "Unable to track breakpoint at expression " + address) + QMessageBox.information(self, tr.ERROR, tr.TRACK_BREAKPOINT_FAILED.format(address)) return + # This part will be deleted after non-pause patch, not translating self.label_Info.setText("Pause the process to refresh 'Value' part of the table(" + Hotkeys.pause_hotkey.get_active_key() + " or " + Hotkeys.break_hotkey.get_active_key() + ")") @@ -4438,7 +4410,6 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.tableWidget_TrackInfo.itemDoubleClicked.connect(self.tableWidget_TrackInfo_item_double_clicked) self.tableWidget_TrackInfo.selectionModel().currentChanged.connect(self.tableWidget_TrackInfo_current_changed) self.comboBox_ValueType.currentIndexChanged.connect(self.update_values) - self.comboBox_ValueType.setToolTip("Allan please add details") # planned easter egg self.update_timer = QTimer() self.update_timer.setInterval(100) self.update_timer.timeout.connect(self.update_list) @@ -4483,7 +4454,7 @@ def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() - self.parent().parent().add_entry_to_addresstable("Accessed by " + self.address, address, + self.parent().parent().add_entry_to_addresstable(tr.ACCESSED_BY.format(self.address), address, self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole), 10, True) @@ -4491,10 +4462,10 @@ def pushButton_Stop_clicked(self): if self.stopped: self.close() if not GDB_Engine.delete_breakpoint(self.address): - QMessageBox.information(self, "Error", "Unable to delete breakpoint at expression " + self.address) + QMessageBox.information(self, tr.ERROR, tr.DELETE_BREAKPOINT_FAILED.format(self.address)) return self.stopped = True - self.pushButton_Stop.setText("Close") + self.pushButton_Stop.setText(tr.CLOSE) self.parent().refresh_disassemble_view() def closeEvent(self, QCloseEvent): @@ -4536,7 +4507,7 @@ def accept(self): if int(self.lineEdit_MaxTraceCount.text()) >= 1: super(TraceInstructionsPromptDialogForm, self).accept() else: - QMessageBox.information(self, "Error", "Max trace count must be greater than or equal to 1") + QMessageBox.information(self, tr.ERROR, tr.MAX_TRACE_COUNT_ASSERT_GT.format(1)) class TraceInstructionsWaitWidgetForm(QWidget, TraceInstructionsWaitWidget): @@ -4545,6 +4516,12 @@ class TraceInstructionsWaitWidgetForm(QWidget, TraceInstructionsWaitWidget): def __init__(self, address, breakpoint, parent=None): super().__init__(parent=parent) self.setupUi(self) + self.status_to_text = { + type_defs.TRACE_STATUS.STATUS_IDLE: tr.WAITING_FOR_BREAKPOINT, + type_defs.TRACE_STATUS.STATUS_CANCELED: tr.TRACING_CANCELED, + type_defs.TRACE_STATUS.STATUS_PROCESSING: tr.PROCESSING_DATA, + type_defs.TRACE_STATUS.STATUS_FINISHED: tr.TRACING_COMPLETED + } self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) GuiUtils.center(self) self.address = address @@ -4569,12 +4546,15 @@ def change_status(self): status_info[0] == type_defs.TRACE_STATUS.STATUS_PROCESSING: self.close() return - self.label_StatusText.setText(status_info[1]) + if status_info[0] == type_defs.TRACE_STATUS.STATUS_TRACING: + self.label_StatusText.setText(status_info[1]) + else: + self.label_StatusText.setText(self.status_to_text[status_info[0]]) app.processEvents() def closeEvent(self, QCloseEvent): self.status_timer.stop() - self.label_StatusText.setText("Processing the collected data") + self.label_StatusText.setText(tr.PROCESSING_DATA) self.pushButton_Cancel.setVisible(False) self.adjustSize() app.processEvents() @@ -4616,7 +4596,7 @@ def __init__(self, address="", prompt_dialog=True, parent=None): params = (address,) + prompt_dialog.get_values() breakpoint = GDB_Engine.trace_instructions(*params) if not breakpoint: - QMessageBox.information(self, "Error", "Failed to set breakpoint at address " + address) + QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_FAILED.format(address)) self.close() return self.showMaximized() @@ -4668,30 +4648,27 @@ def show_trace_info(self, trace_data=None): def save_file(self): trace_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) - file_path = QFileDialog.getSaveFileName(self, "Save trace file", trace_file_path, - "Trace File (*.trace);;All Files (*)")[0] + file_path = QFileDialog.getSaveFileName(self, tr.SAVE_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] if file_path: file_path = SysUtils.append_file_extension(file_path, "trace") if not SysUtils.save_file(self.trace_data, file_path): - QMessageBox.information(self, "Error", "Cannot save to file") + QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) def load_file(self): trace_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) - file_path = QFileDialog.getOpenFileName(self, "Open trace file", trace_file_path, - "Trace File (*.trace);;All Files (*)")[0] + file_path = QFileDialog.getOpenFileName(self, tr.OPEN_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] if file_path: content = SysUtils.load_file(file_path) if content is None: - QMessageBox.information(self, "Error", "File " + file_path + " does not exist, " + - "is inaccessible or contains invalid content. Terminating...") + QMessageBox.information(self, tr.ERROR, tr.FILE_LOAD_ERROR.format(file_path)) return self.treeWidget_InstructionInfo.clear() self.show_trace_info(content) def treeWidget_InstructionInfo_context_menu_event(self, event): menu = QMenu() - expand_all = menu.addAction("Expand All") - collapse_all = menu.addAction("Collapse All") + expand_all = menu.addAction(tr.EXPAND_ALL) + collapse_all = menu.addAction(tr.COLLAPSE_ALL) font_size = self.treeWidget_InstructionInfo.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -4760,7 +4737,7 @@ def apply_data(self, output): if address: address_item = QTableWidgetItem(address) else: - address_item = QTableWidgetItem("DEFINED") + address_item = QTableWidgetItem(tr.DEFINED) address_item.setBackground(QColorConstants.Green) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_ADDR_COL, address_item) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_SYMBOL_COL, QTableWidgetItem(item[1])) @@ -4776,9 +4753,7 @@ def tableWidget_SymbolInfo_current_changed(self, QModelIndex_current): info = GDB_Engine.get_symbol_info(item) self.textBrowser_AddressInfo.append(info) else: - text = "This symbol is defined. You can use its body as a gdb expression. For instance:\n\n" \ - "void func(param) can be used as 'func' as a gdb expression" - self.textBrowser_AddressInfo.append(text) + self.textBrowser_AddressInfo.append(tr.DEFINED_SYMBOL) def tableWidget_SymbolInfo_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -4787,8 +4762,8 @@ def copy_to_clipboard(row, column): selected_row = GuiUtils.get_current_row(self.tableWidget_SymbolInfo) menu = QMenu() - copy_address = menu.addAction("Copy Address") - copy_symbol = menu.addAction("Copy Symbol") + copy_address = menu.addAction(tr.COPY_ADDRESS) + copy_symbol = menu.addAction(tr.COPY_SYMBOL) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_address, copy_symbol]) font_size = self.tableWidget_SymbolInfo.font().pointSize() @@ -4805,22 +4780,12 @@ def copy_to_clipboard(row, column): def tableWidget_SymbolInfo_item_double_clicked(self, index): address = self.tableWidget_SymbolInfo.item(index.row(), FUNCTIONS_INFO_ADDR_COL).text() - if address == "DEFINED": + if address == tr.DEFINED: return self.parent().disassemble_expression(address, append_to_travel_history=True) def pushButton_Help_clicked(self): - text = "\tHere's some useful regex tips:" \ - "\n^quaso --> search for everything that starts with quaso" \ - "\n[ab]cd --> search for both acd and bcd" \ - "\n\n\tHow to interpret symbols:" \ - "\nA symbol that looks like 'func(param)@plt' consists of 3 pieces" \ - "\nfunc, func(param), func(param)@plt" \ - "\nThese 3 functions will have different addresses" \ - "\n@plt means this function is a subroutine for the original one" \ - "\nThere can be more than one of the same function" \ - "\nIt means that the function is overloaded" - InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], + InputDialogForm(item_list=[(tr.FUNCTIONS_INFO_HELPER, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() def closeEvent(self, QCloseEvent): @@ -4885,9 +4850,7 @@ def accept(self): if new_length < old_length: bytes_aob += " 90"*(old_length-new_length) # Append NOPs if we are short on bytes elif new_length > old_length: - if not InputDialogForm( - item_list=[("New opcode is " + str(new_length) + " bytes long but old opcode is only " + - str(old_length) + " bytes long\nThis will cause an overflow, proceed?",)]).exec(): + if not InputDialogForm(item_list=[(tr.NEW_OPCODE.format(new_length, old_length),)]).exec(): return GDB_Engine.modify_instruction(address, bytes_aob) self.parent().refresh_hex_view() @@ -4968,13 +4931,14 @@ def accept(self): expression = self.lineEdit_Address.text() address = GDB_Engine.examine_expression(expression).address if not address: - QMessageBox.information(self, "Error", expression + " isn't a valid expression") + QMessageBox.information(self, tr.ERROR, tr.IS_INVALID_EXPRESSION.format(expression)) return value = self.lineEdit_HexView.text() GDB_Engine.write_memory(address, type_defs.VALUE_INDEX.INDEX_AOB, value) super(HexEditDialogForm, self).accept() +# This widget will be replaced with auto-generated documentation in the future, no need to translate class LibpinceReferenceWidgetForm(QWidget, LibpinceReferenceWidget): def convert_to_modules(self, module_strings): return [eval(item) for item in module_strings] @@ -5243,17 +5207,17 @@ def __init__(self, parent=None): def refresh_contents(self): log_path = SysUtils.get_logging_file(GDB_Engine.currentpid) - self.setWindowTitle("Log File of PID " + str(GDB_Engine.currentpid)) - self.label_FilePath.setText("Contents of " + log_path + " (only last 20000 bytes are shown)") - logging_status = "ON" if gdb_logging else "OFF" - self.label_LoggingStatus.setText("LOGGING: " + logging_status + "") + self.setWindowTitle(tr.LOG_FILE.format(GDB_Engine.currentpid)) + self.label_FilePath.setText(tr.LOG_CONTENTS.format(log_path, 20000)) + logging_status = f"{tr.ON}" if gdb_logging else f"{tr.OFF}" + self.label_LoggingStatus.setText(f"{tr.LOG_STATUS.format(logging_status)}") try: log_file = open(log_path) except OSError: self.textBrowser_LogContent.clear() - error_message = "Unable to read log file at " + log_path + "\n" + error_message = tr.LOG_READ_ERROR.format(log_path) + "\n" if not gdb_logging: - error_message += "Go to Settings->Debug to enable logging" + error_message += tr.SETTINGS_ENABLE_LOG self.textBrowser_LogContent.setText(error_message) return log_file.seek(0, io.SEEK_END) @@ -5322,7 +5286,7 @@ def process_data(self, regex, start_address, end_address, case_sensitive, enable def apply_data(self, disas_data): if disas_data is None: - QMessageBox.information(self, "Error", "Given regex isn't valid, check terminal to see the error") + QMessageBox.information(self, tr.ERROR, tr.INVALID_REGEX) return self.tableWidget_Opcodes.setSortingEnabled(False) self.tableWidget_Opcodes.setRowCount(0) @@ -5333,12 +5297,7 @@ def apply_data(self, disas_data): self.tableWidget_Opcodes.setSortingEnabled(True) def pushButton_Help_clicked(self): - text = "\tHere's some useful regex examples:" \ - "\ncall|rax --> search for opcodes that contain call or rax" \ - "\n[re]cx --> search for both rcx and ecx" \ - "\nUse the char \\ to escape special chars such as [" \ - "\n\[rsp\] --> search for opcodes that contain [rsp]" - InputDialogForm(item_list=[(text, None, Qt.AlignmentFlag.AlignLeft)], + InputDialogForm(item_list=[(tr.SEARCH_OPCODE_HELPER, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() def tableWidget_Opcodes_item_double_clicked(self, index): @@ -5353,8 +5312,8 @@ def copy_to_clipboard(row, column): selected_row = GuiUtils.get_current_row(self.tableWidget_Opcodes) menu = QMenu() - copy_address = menu.addAction("Copy Address") - copy_opcode = menu.addAction("Copy Opcode") + copy_address = menu.addAction(tr.COPY_ADDRESS) + copy_opcode = menu.addAction(tr.COPY_OPCODE) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_address, copy_opcode]) font_size = self.tableWidget_Opcodes.font().pointSize() @@ -5408,11 +5367,11 @@ def copy_to_clipboard(row, column): selected_row = GuiUtils.get_current_row(self.tableWidget_MemoryRegions) menu = QMenu() - refresh = menu.addAction("Refresh[R]") + refresh = menu.addAction(f"{tr.REFRESH}[R]") menu.addSeparator() - copy_addresses = menu.addAction("Copy Addresses") - copy_offset = menu.addAction("Copy Offset") - copy_path = menu.addAction("Copy Path") + copy_addresses = menu.addAction(tr.COPY_ADDRESSES) + copy_offset = menu.addAction(tr.COPY_OFFSET) + copy_path = menu.addAction(tr.COPY_PATH) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_addresses, copy_offset, copy_path]) font_size = self.tableWidget_MemoryRegions.font().pointSize() @@ -5464,7 +5423,7 @@ def __init__(self, parent=None, int_address=-1): self.pushButton_StartCancel_clicked() break else: - QMessageBox.information(self, "Error", hex(int_address) + " isn't in a valid region range") + QMessageBox.information(self, tr.ERROR, tr.INVALID_REGION) else: if self.tableWidget_ExecutableMemoryRegions.rowCount() > 0: self.tableWidget_ExecutableMemoryRegions.selectRow(0) @@ -5486,12 +5445,12 @@ def run(self): def init_pre_scan_gui(self): self.is_scanning = False self.is_canceled = False - self.pushButton_StartCancel.setText("Start") + self.pushButton_StartCancel.setText(tr.START) def init_after_scan_gui(self): self.is_scanning = True - self.label_ScanInfo.setText("Currently scanning region:") - self.pushButton_StartCancel.setText("Cancel") + self.label_ScanInfo.setText(tr.CURRENT_SCAN_REGION) + self.pushButton_StartCancel.setText(tr.CANCEL) def refresh_dissect_status(self): region, region_count, range, string_count, jump_count, call_count = GDB_Engine.get_dissect_code_status() @@ -5528,7 +5487,7 @@ def show_memory_regions(self): def scan_finished(self): self.init_pre_scan_gui() if not self.is_canceled: - self.label_ScanInfo.setText("Scan finished") + self.label_ScanInfo.setText(tr.SCAN_FINISHED) self.is_canceled = False self.refresh_timer.stop() self.refresh_dissect_status() @@ -5542,15 +5501,15 @@ def pushButton_StartCancel_clicked(self): GDB_Engine.cancel_dissect_code() self.refresh_timer.stop() self.update_dissect_results() - self.label_ScanInfo.setText("Scan was canceled") + self.label_ScanInfo.setText(tr.SCAN_CANCELED) self.init_pre_scan_gui() else: if not GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: - QMessageBox.information(self, "Error", "Please stop the process first") + QMessageBox.information(self, tr.ERROR, tr.STOP_PROCESS) return selected_rows = self.tableWidget_ExecutableMemoryRegions.selectionModel().selectedRows() if not selected_rows: - QMessageBox.information(self, "Error", "Select at least one region") + QMessageBox.information(self, tr.ERROR, tr.SELECT_ONE_REGION) return selected_indexes = [selected_row.row() for selected_row in selected_rows] selected_regions = [self.region_list[selected_index] for selected_index in selected_indexes] @@ -5587,7 +5546,7 @@ def __init__(self, parent=None): jmp_dict.close() call_dict.close() if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: - confirm_dialog = InputDialogForm(item_list=[("You need to dissect code first\nProceed?",)]) + confirm_dialog = InputDialogForm(item_list=[(tr.DISSECT_CODE,)]) if confirm_dialog.exec(): dissect_code_dialog = DissectCodeDialogForm() dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) @@ -5618,8 +5577,7 @@ def refresh_table(self): self.checkBox_CaseSensitive.isChecked(), self.checkBox_Regex.isChecked()) if item_list is None: - QMessageBox.information(self, "Error", - "An exception occurred while trying to compile the given regex\n") + QMessageBox.information(self, tr.ERROR, tr.INVALID_REGEX) return self.tableWidget_References.setSortingEnabled(False) self.tableWidget_References.setRowCount(0) @@ -5661,8 +5619,8 @@ def copy_to_clipboard(row, column): selected_row = GuiUtils.get_current_row(self.tableWidget_References) menu = QMenu() - copy_address = menu.addAction("Copy Address") - copy_value = menu.addAction("Copy Value") + copy_address = menu.addAction(tr.COPY_ADDRESS) + copy_value = menu.addAction(tr.COPY_VALUE) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_address, copy_value]) font_size = self.tableWidget_References.font().pointSize() @@ -5684,7 +5642,7 @@ def copy_to_clipboard(row): selected_row = GuiUtils.get_current_row(self.listWidget_Referrers) menu = QMenu() - copy_address = menu.addAction("Copy Address") + copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() @@ -5722,7 +5680,7 @@ def __init__(self, parent=None): jmp_dict.close() call_dict.close() if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: - confirm_dialog = InputDialogForm(item_list=[("You need to dissect code first\nProceed?",)]) + confirm_dialog = InputDialogForm(item_list=[(tr.DISSECT_CODE,)]) if confirm_dialog.exec(): dissect_code_dialog = DissectCodeDialogForm() dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) @@ -5751,8 +5709,7 @@ def refresh_table(self): self.checkBox_CaseSensitive.isChecked(), self.checkBox_Regex.isChecked()) if item_list is None: - QMessageBox.information(self, "Error", - "An exception occurred while trying to compile the given regex\n") + QMessageBox.information(self, tr.ERROR, tr.INVALID_REGEX) return self.tableWidget_References.setSortingEnabled(False) self.tableWidget_References.setRowCount(0) @@ -5791,7 +5748,7 @@ def copy_to_clipboard(row, column): selected_row = GuiUtils.get_current_row(self.tableWidget_References) menu = QMenu() - copy_address = menu.addAction("Copy Address") + copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.tableWidget_References.font().pointSize() @@ -5812,7 +5769,7 @@ def copy_to_clipboard(row): selected_row = GuiUtils.get_current_row(self.listWidget_Referrers) menu = QMenu() - copy_address = menu.addAction("Copy Address") + copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() @@ -5893,8 +5850,7 @@ def refresh_table(self): else: regex = re.compile(searched_str, re.IGNORECASE) except: - QMessageBox.information(self, "Error", - "An exception occurred while trying to compile the given regex\n") + QMessageBox.information(self, tr.ERROR, tr.INVALID_REGEX) return self.listWidget_Referrers.setSortingEnabled(False) self.listWidget_Referrers.clear() @@ -5936,7 +5892,7 @@ def copy_to_clipboard(row): selected_row = GuiUtils.get_current_row(self.listWidget_Referrers) menu = QMenu() - copy_address = menu.addAction("Copy Address") + copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: GuiUtils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() @@ -5961,7 +5917,6 @@ def handle_exit(): if __name__ == "__main__": - app = QApplication(sys.argv) app.aboutToQuit.connect(handle_exit) window = MainForm() window.show() diff --git a/README.md b/README.md index 69c43093..ddae959e 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - - Provide an option to cut BOM bytes when writing to memory with the types UTF-16 and UTF-32 - - Put a warning for users about replacement bytes for non UTF-8 types - - Extend string types with LE and BE variants of UTF-16 and UTF-32 -- - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others Array of Bytes +- - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others - - Implement a custom combobox class for comboBox_ValueType and create a context menu for String_Others item - Having to stop the process to resolve symbols sucks, we already resolve base addresses of libs by ourselves, try to replace this gdb functionality with something else, like parsing from the memory - Implement "Investigate Registers" button to gather information about the addresses registers point to(independent from other steps) diff --git a/compile_ts.sh b/compile_ts.sh new file mode 100755 index 00000000..c8a1dfe2 --- /dev/null +++ b/compile_ts.sh @@ -0,0 +1 @@ +pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts i18n/ts/it_IT.ts diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts new file mode 100644 index 00000000..ffd332b6 --- /dev/null +++ b/i18n/ts/it_IT.ts @@ -0,0 +1,2760 @@ + + + + + Dialog + + + Add Address Manually + + + + + Base Address: + + + + + Add Offset + + + + + Remove Offset + + + + + + Pointer + + + + + Type: + + + + + + Zero-Terminated + + + + + + Length + + + + + + 10 + + + + + + + Address: + + + + + = + + + + + Description: + + + + + Dissect Code + + + + + Regions + + + + + Path + + + + + Selected regions will be scanned + + + + + + + - + + + + + Currently scanning range: + + + + + String references found: + + + + + Jumps found: + + + + + Calls found: + + + + + Entries that can't be decoded as utf-8 won't be included in referenced strings +Unchecking it makes ReferencedStringsWidget load slower but allows you to examine non-string pointers on it + + + + + Discard invalid strings + + + + + Edit Instruction + + + + + Instruction: + + + + + Multiple entries are separated with ; + + + + + Type + + + + + Select the new type + + + + + + Handle Signals + + + + + Signal + + + + + Ignore + + + + + Hex Edit + + + + + Length: + + + + + Refresh + + + + + + Dialog + + + + + Processing + + + + + Cancel + + + + + Settings + + + + + General + + + + + Hotkeys + + + + + Code Injection + + + + + Disassemble + + + + + Debug + + + + + Auto-update address table + + + + + Update Interval + + + + + 500 + + + + + + ms + + + + + Freeze Interval + + + + + 100 + + + + + Show a MessageBox on InferiorRunning and GDBInitialize exceptions + + + + + GDB output: + + + + + Async + + + + + Command + + + + + Command info + + + + + On start, automatically attach to processes with name matching one of the entries +Patterns at former positions have higher priority if regex is off + + + + + Auto-attach on start + + + + + Regex + + + + + Logo + + + + + Functions + + + + + Hotkey + + + + + Clear + + + + + Code injection method: + + + + + Simp&le dlopen call + + + + + Advanced In&jection + + + + + Bring disassemble screen to front when the inferior is stopped + + + + + Instructions shown per scroll + + + + + GDB Path + + + + + GDB Logging + + + + + Reset Settings + + + + + Hit Esc to cancel and Ctrl+Enter to accept + + + + + Parameters for tracing + + + + + Number of the instructions that'll be traced + + + + + Max trace count(1 or greater): + + + + + 1000 + + + + + Tracing will start if this condition is met + + + + + Trigger condition(Optional, gdb expression): + + + + + Tracing will stop whenever this condition is met + + + + + Stop condition(Optional, gdb expression): + + + + + Step over instead of single step + + + + + Stop when tracing ends + + + + + Collect general registers + + + + + Collect flag registers + + + + + Collect segment registers + + + + + Collect float registers + + + + + Select an address to track + + + + + Pointed Address + + + + + Form + + + Bookmarks + + + + + Bookmarked Addresses + + + + + + Info + + + + + Comment + + + + + GDB Console + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Monospace'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + Send + + + + + Send ctrl+c + + + + + CLI + + + + + MI + + + + + Examine Referrers + + + + + + + + + Enter a string or a python regex + + + + + + + + + Ignore case if checked + + + + + + + + + Case sensitive + + + + + + + + Your string will be treated as a regex if checked + + + + + + + + + Regex + + + + + + + + + Search(Enter) + + + + + Functions + + + + + + + + + + + Address + + + + + Symbol + + + + + Enter the regex. Leave blank to see all functions + + + + + libpince Reference + + + + + + Search + + + + + type_defs(Type Definitions) + + + + + 0/0 + + + + + + + + Value + + + + + Item Name + + + + + Source File + + + + + Resources(Mouse-over items to see docstrings) + + + + + Hide type_defs + + + + + + + + Form + + + + + + TextLabel + + + + + Memory Regions + + + + + Regions + + + + + Perms + + + + + Offset + + + + + Path + + + + + Referenced Calls + + + + + + Refcount + + + + + Referenced Strings and Values + + + + + Restore Instructions + + + + + Original OpCode + + + + + Original Instruction + + + + + Search for Opcodes + + + + + Start + + + + + End + + + + + Opcodes + + + + + StackTrace Information + + + + + Return Address + + + + + Cancel + + + + + + Stop + + + + + + Count + + + + + Source + + + + + Try changing combobox index if the 'Value' part of table still isn't updated + + + + + Refresh + + + + + MainWindow + + + PINCE + + + + + Freeze + + + + + Freeze the value + + + + + Description + + + + + + Address + + + + + Type + + + + + + Value + + + + + Memory View + + + + + Copy selected items to the address table + + + + + Erase all the table contents + + + + + Refresh the address table[R] + + + + + Add Address Manually + + + + + Create or attach to a process + + + + + Open a cheat table + + + + + Save current table to a file + + + + + Wiki + + + + + About + + + + + No Process Selected + + + + + Open a gdb console + + + + + Configure options + + + + + Match count: 0 + + + + + Previous + + + + + First Scan + + + + + Next Scan + + + + + Undo Scan + + + + + B&its + + + + + &Decimal + + + + + Hex + + + + + <-> + + + + + Scan Type: + + + + + Value Type: + + + + + Scan Scope: + + + + + Please select a Process + + + + + Name of the Process: + + + + + PID + + + + + Username + + + + + Process Name + + + + + Attach to the selected process + + + + + + Open + + + + + Cancel + + + + + Open an executable + + + + + Create Process[F1] + + + + + Tracer + + + + + File + + + + + Save + + + + + Save as a text file + + + + + MainWindow_MemoryView + + + Memory Viewer + + + + + + + Address + + + + + Bytes + + + + + Opcodes + + + + + Comment + + + + + Registers + + + + + RAX= + + + + + RBX= + + + + + RCX= + + + + + RDX= + + + + + RSI= + + + + + RDI= + + + + + RBP= + + + + + RSP= + + + + + R8= + + + + + R9= + + + + + R10= + + + + + R11= + + + + + R12= + + + + + R13= + + + + + R14= + + + + + R15= + + + + + RIP= + + + + + EAX= + + + + + EBX= + + + + + ECX= + + + + + EDX= + + + + + ESI= + + + + + EDI= + + + + + EBP= + + + + + ESP= + + + + + EIP= + + + + + Flags + + + + + CF + + + + + + + + + + + + + 0 + + + + + PF + + + + + AF + + + + + ZF + + + + + SF + + + + + TF + + + + + IF + + + + + DF + + + + + OF + + + + + Segment Registers + + + + + CS= + + + + + ES= + + + + + SS= + + + + + GS= + + + + + DS= + + + + + FS= + + + + + Show Float Registers + + + + + Return Address + + + + + Frame Address + + + + + Value + + + + + Points to + + + + + V&iew + + + + + &Debug + + + + + &Tools + + + + + Fi&le + + + + + Help + + + + + &Bookmarks + + + + + &StackTrace Info + + + + + &Inject .so file + + + + + &Break + + + + + &Run + + + + + &Step[F7] + + + + + Step &Over[F8] + + + + + &Execute Till Return[Shift+F8] + + + + + &Toggle Breakpoint[F5] + + + + + B&reakpoints + + + + + &Functions + + + + + Set Address[Shift+F4] + + + + + &Call Function + + + + + &Load Trace + + + + + &libpince + + + + + &GDB Log File + + + + + &Search Opcode + + + + + &Memory Regions + + + + + &Dissect Code + + + + + R&eferenced Strings + + + + + Referenced &Calls + + + + + To&ggle Attach + + + + + Restore Instructions + + + + + TabWidget + + + About PINCE + + + + + Contributors + + + + + License + + + + + Breakpoints + + + + + Interactive + + + + + No + + + + + Type + + + + + Disp + + + + + Enabled + + + + + Address + + + + + Size + + + + + On Hit + + + + + Hit Count + + + + + Condition + + + + + Raw + + + + + Floating Point Registers + + + + + FPU + + + + + + Register + + + + + + Value + + + + + XMM + + + + + TranslationConstants + + + Pause the process + + + + + Break the process + + + + + Continue the process + + + + + Toggle attach/detach + + + + + Next Scan - Exact + + + + + Next Scan - Increased + + + + + Next Scan - Decreased + + + + + Next Scan - Changed + + + + + Next Scan - Unchanged + + + + + Error + + + + + GDB isn't initialized yet + + + + + Process is running +Press {} to stop process + +Go to Settings->General to disable this dialog + + + + + Unable to initialize GDB +You might want to reinstall GDB or use the system GDB +To change the current GDB path, check Settings->Debug + + + + + Edit + + + + + Show as hexadecimal + + + + + Show as decimal + + + + + Show as unsigned + + + + + Show as signed + + + + + Toggle selected records + + + + + Freeze + + + + + Default + + + + + Incremental + + + + + Decremental + + + + + Browse this memory region + + + + + Disassemble this address + + + + + Cut selected records + + + + + Copy selected records + + + + + Cut selected records (recursive) + + + + + Copy selected records (recursive) + + + + + Paste selected records before + + + + + Paste selected records after + + + + + Paste selected records inside + + + + + Delete selected records + + + + + Find out what writes to this address + + + + + Find out what reads this address + + + + + Find out what accesses this address + + + + + Invalid clipboard content + + + + + New Scan + + + + + Match count: {} ({} shown) + + + + + Match count: {} + + + + + No Description + + + + + Open PCT file(s) + + + + + PINCE Cheat Table (*.pct);;All files (*) + + + + + Clear address table? + + + + + File {} is inaccessible or contains invalid content + + + + + Save PCT file + + + + + Cannot save to file + + + + + Nice try, smartass + + + + + Selected process is not valid + + + + + You're debugging this process already + + + + + That process is already being traced by {}, could not attach to the process + + + + + Permission denied, could not attach to the process + + + + + An error occurred while trying to create process + + + + + Scan for + + + + + First Scan + + + + + No Process Selected + + + + + [detached] + + + + + [stopped] + + + + + Enter the new value + + + + + Enter the new description + + + + + Edit Address + + + + + Please select a process first + + + + + Select the target binary + + + + + Enter the optional arguments + + + + + LD_PRELOAD .so path (optional) + + + + + Refresh + + + + + Length is not valid + + + + + Length must be greater than 0 + + + + + Can't parse the input + + + + + Update interval must be an int + + + + + Freeze interval must be an int + + + + + Instruction count must be an int + + + + + Instruction count cannot be lower than {} + + + + + Interval cannot be a negative number + + + + + You are asking for it, aren't you? + + + + + Update interval should be bigger than {} ms +Setting update interval less than {} ms may cause slowdown +Proceed? + + + + + {} isn't a valid regex + + + + + You have changed the GDB path, reset GDB now? + + + + + This will reset to the default settings +Proceed? + + + + + Mouse over on this text for examples + + + + + asdf|qwer --> search for asdf or qwer +[as]df --> search for both adf and sdf +Use the char \ to escape special chars such as [ +\[asdf\] --> search for opcodes that contain [asdf] + + + + + Separate processes with {} + + + + + Select the gdb binary + + + + + Quitting current session will crash PINCE + + + + + Inferior is running + + + + + Hotkeys: +---------------------------- +Send=Enter | +Send ctrl+c=Ctrl+C | +Multi-line mode=Ctrl+Enter | +Complete command=Tab | +---------------------------- +Commands: +---------------------------------------------------------- +/clear: Clear the console | +phase-out: Detach from the current process | +phase-in: Attach back to the previously detached process | +--------------------------------------------------------------------------------------------------- +pince-init-so-file so_file_path: Initializes 'lib' variable | +pince-get-so-file-information: Get information about current lib | +pince-execute-from-so-file lib.func(params): Execute a function from lib | +# Check https://github.com/korcankaraokcu/PINCE/wiki#extending-pince-with-so-files for an example | +# CLI output mode doesn't work very well with .so extensions, use MI output mode instead | +--------------------------------------------------------------------------------------------------- +You can change the output mode from bottom right +Note: Changing output mode only affects commands sent. Any other output coming from external sources(e.g async output) will be shown in MI format + + + + + Break[{}] + + + + + Run[{}] + + + + + Toggle Attach[{}] + + + + + Failed to set breakpoint at address {} + + + + + Enter the watchpoint length in size of bytes + + + + + {} can't be parsed as an integer + + + + + Breakpoint length can't be lower than {} + + + + + Failed to set watchpoint at address {} + + + + + Copy to Clipboard + + + + + Go to expression + + + + + Add this address to address list + + + + + Set Watchpoint + + + + + Write Only + + + + + Read Only + + + + + Both + + + + + Add/Change condition for breakpoint + + + + + Delete Breakpoint + + + + + Enter the expression + + + + + {} is invalid + + + + + Protection:{} | Base:{}-{} | Module:{} + + + + + Invalid Region + + + + + Cannot access memory at expression {} + + + + + Referenced by: + + + + + Press 'Ctrl+E' to see a detailed list of referrers + + + + + Memory Viewer - Paused + + + + + Memory Viewer - Currently debugging {} + + + + + Memory Viewer - Running + + + + + Enter the expression for condition, for instance: + +$eax==0x523 +$rax>0 && ($rbp<0 || $rsp==0) +printf($r10)==3 + + + + + Failed to set condition for address {} +Check terminal for details + + + + + Full Stack + + + + + Copy Return Address + + + + + Copy Frame Address + + + + + Stacktrace + + + + + Copy Address + + + + + Copy Value + + + + + Copy Points to + + + + + Disassemble 'value' pointer address + + + + + Show 'value' pointer in HexView + + + + + Back + + + + + Show this address in HexView + + + + + Follow + + + + + Examine Referrers + + + + + Bookmark this address + + + + + Delete this bookmark + + + + + Change comment + + + + + Go to bookmarked address + + + + + Toggle Breakpoint + + + + + Edit instruction + + + + + Replace instruction with NOPs + + + + + Find out which addresses this instruction accesses + + + + + Break and trace instructions + + + + + Dissect this region + + + + + Copy Bytes + + + + + Copy Opcode + + + + + Copy Comment + + + + + Copy All + + + + + Enter the register expression(s) you want to track +Register names must start with $ +Each expression must be separated with a comma + +For instance: +Let's say the instruction is mov [rax+rbx],30 +Then you should enter $rax+$rbx +So PINCE can track address [rax+rbx] + +Another example: +If you enter $rax,$rbx*$rcx+4,$rbp +PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] + + + + + This address has already been bookmarked + + + + + Enter the comment for bookmarked address + + + + + Select the .so file + + + + + Shared object library (*.so) + + + + + Success + + + + + The file has been injected + + + + + Failed to inject the .so file + + + + + Enter the expression for the function that'll be called from the inferior +You can view functions list from View->Functions + +For instance: +Calling printf("1234") will yield something like this +↓ +$28 = 4 + +$28 is the assigned convenience variable +4 is the result +You can use the assigned variable from the GDB Console + + + + + Failed to call the expression {} + + + + + Invalid expression or address + + + + + Invalid entries detected, refreshing the page + + + + + Add new entry + + + + + Delete + + + + + Enter the new value of register {} + + + + + Restore this instruction + + + + + Enter the hit count({} or higher) + + + + + Hit count must be an integer + + + + + Hit count can't be lower than {} + + + + + Change condition + + + + + Enable + + + + + Disable + + + + + Disable after hit + + + + + Disable after X hits + + + + + Delete after hit + + + + + Opcodes writing to the address {} + + + + + Opcodes reading from the address {} + + + + + Opcodes accessing to the address {} + + + + + Unable to track watchpoint at expression {} + + + + + Unable to delete watchpoint at expression {} + + + + + Close + + + + + Addresses accessed by instruction {} + + + + + Unable to track breakpoint at expression {} + + + + + Accessed by {} + + + + + Unable to delete breakpoint at expression {} + + + + + Max trace count must be greater than or equal to {} + + + + + Processing the collected data + + + + + Save trace file + + + + + Trace File (*.trace);;All Files (*) + + + + + Open trace file + + + + + Expand All + + + + + Collapse All + + + + + DEFINED + + + + + This symbol is defined. You can use its body as a gdb expression. For instance: + +void func(param) can be used as 'func' as a gdb expression + + + + + Copy Symbol + + + + + Here's some useful regex tips: +^quaso --> search for everything that starts with quaso +[ab]cd --> search for both acd and bcd + + How to interpret symbols: +A symbol that looks like 'func(param)@plt' consists of 3 pieces +func, func(param), func(param)@plt +These 3 functions will have different addresses +@plt means this function is a subroutine for the original one +There can be more than one of the same function +It means that the function is overloaded + + + + + New opcode is {} bytes long but old opcode is only {} bytes long +This will cause an overflow, proceed? + + + + + {} isn't a valid expression + + + + + Log File of PID {} + + + + + Contents of {} (only last {} bytes are shown) + + + + + ON + + + + + OFF + + + + + LOGGING: {} + + + + + Unable to read log file at {} + + + + + Go to Settings->Debug to enable logging + + + + + Invalid Regex + + + + + Here's some useful regex examples: +call|rax --> search for opcodes that contain call or rax +[re]cx --> search for both rcx and ecx +Use the char \ to escape special chars such as [ +\[rsp\] --> search for opcodes that contain [rsp] + + + + + Copy Addresses + + + + + Copy Offset + + + + + Copy Path + + + + + Start + + + + + Currently scanning region: + + + + + Cancel + + + + + Scan finished + + + + + Scan was canceled + + + + + Please stop the process first + + + + + Select at least one region + + + + + You need to dissect code first +Proceed? + + + + + Waiting for breakpoint to trigger + + + + + Tracing has been canceled + + + + + Tracing has been completed + + + + + Exact + + + + + Increased + + + + + Increased by + + + + + Decreased + + + + + Decreased by + + + + + Less Than + + + + + More Than + + + + + Between + + + + + Changed + + + + + Unchanged + + + + + Unknown Value + + + + + Basic + + + + + Normal + + + + + Read+Write + + + + + Full + + + + diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index e62e009e..98082b69 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -554,7 +554,7 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): gdb_path (str): Path of the gdb binary Returns: - tuple: (A member of type_defs.ATTACH_RESULT, result_message) + int: A member of type_defs.ATTACH_RESULT Note: If gdb is already initialized, gdb_path will be ignored @@ -564,19 +564,15 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): traced_by = SysUtils.is_traced(pid) pid_control_list = [ # Attaching PINCE to itself makes PINCE freeze immediately because gdb freezes the target on attach - (lambda: pid == self_pid, type_defs.ATTACH_RESULT.ATTACH_SELF, "Nice try, smartass"), # planned easter egg - (lambda: not SysUtils.is_process_valid(pid), type_defs.ATTACH_RESULT.PROCESS_NOT_VALID, - "Selected process is not valid"), - (lambda: pid == currentpid, type_defs.ATTACH_RESULT.ALREADY_DEBUGGING, "You're debugging this process already"), - (lambda: traced_by is not False, type_defs.ATTACH_RESULT.ALREADY_TRACED, - "That process is already being traced by " + str(traced_by) + ", could not attach to the process"), - (lambda: not can_attach(pid), type_defs.ATTACH_RESULT.PERM_DENIED, - "Permission denied, could not attach to the process") + (lambda: pid == self_pid, type_defs.ATTACH_RESULT.ATTACH_SELF), + (lambda: not SysUtils.is_process_valid(pid), type_defs.ATTACH_RESULT.PROCESS_NOT_VALID), + (lambda: pid == currentpid, type_defs.ATTACH_RESULT.ALREADY_DEBUGGING), + (lambda: traced_by is not None, type_defs.ATTACH_RESULT.ALREADY_TRACED), + (lambda: not can_attach(pid), type_defs.ATTACH_RESULT.PERM_DENIED) ] - for control_func, attach_result, error_message in pid_control_list: + for control_func, attach_result in pid_control_list: if control_func(): - print(error_message) - return attach_result, error_message + return attach_result if currentpid != -1 or not gdb_initialized: init_gdb(gdb_path) global inferior_arch @@ -591,10 +587,8 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): await_exit_thread = Thread(target=await_process_exit) await_exit_thread.daemon = True await_exit_thread.start() - result_message = "Successfully attached to the process with PID " + str(currentpid) - print(result_message) SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_AA_PATH)) - return type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL, result_message + return type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL #:tag:Debug @@ -1816,7 +1810,7 @@ def trace_instructions(expression, max_trace_count=1000, trigger_condition="", s if not breakpoint: return modify_breakpoint(expression, type_defs.BREAKPOINT_MODIFY.CONDITION, condition=trigger_condition) - contents_send = (type_defs.TRACE_STATUS.STATUS_IDLE, "Waiting for breakpoint to trigger") + contents_send = (type_defs.TRACE_STATUS.STATUS_IDLE, "") trace_status_file = SysUtils.get_trace_instructions_status_file(currentpid, breakpoint) pickle.dump(contents_send, open(trace_status_file, "wb")) param_str = ( @@ -1865,15 +1859,15 @@ def get_trace_instructions_status(breakpoint): tuple:(status_id, status_str) status_id-->(int) A member of type_defs.TRACE_STATUS - status_str-->(str) Status string + status_str-->(str) Status string, only used with type_defs.TRACE_STATUS.STATUS_TRACING - Returns a tuple of (False, "") if fails to gather info + Returns a tuple of (None, "") if fails to gather info """ trace_status_file = SysUtils.get_trace_instructions_status_file(currentpid, breakpoint) try: output = pickle.load(open(trace_status_file, "rb")) except: - output = False, "" + output = None, "" return output @@ -1884,7 +1878,7 @@ def cancel_trace_instructions(breakpoint): Args: breakpoint (str): breakpoint number, must be returned from trace_instructions() """ - status_info = (type_defs.TRACE_STATUS.STATUS_CANCELED, "Tracing has been canceled") + status_info = (type_defs.TRACE_STATUS.STATUS_CANCELED, "") trace_status_file = SysUtils.get_trace_instructions_status_file(currentpid, breakpoint) pickle.dump(status_info, open(trace_status_file, "wb")) diff --git a/libpince/SysUtils.py b/libpince/SysUtils.py index c634096b..9dd017ff 100644 --- a/libpince/SysUtils.py +++ b/libpince/SysUtils.py @@ -178,18 +178,16 @@ def is_traced(pid): Returns: str: Name of the tracer if the specified process is being traced - bool: False, if the specified process is not being traced or the process doesn't exist anymore + None: if the specified process is not being traced or the process doesn't exist anymore """ try: status_file = open("/proc/%d/status" % pid) except FileNotFoundError: - return False + return for line in status_file.readlines(): if line.startswith("TracerPid:"): tracer_pid = line.split(":", 1)[1].strip() - if tracer_pid == "0": - return False - else: + if tracer_pid != "0": return get_process_name(tracer_pid) diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 916a5267..40abc20b 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -140,7 +140,7 @@ def invoke(self, arg, from_tty): if return_address: return_address_with_info = ScriptUtils.examine_expression(return_address.group(1)).all else: - return_address_with_info = "" + return_address_with_info = "<>" stacktrace_info_list.append([return_address_with_info, frame_address_with_difference]) send_to_pince(stacktrace_info_list) @@ -209,7 +209,7 @@ def invoke(self, arg, from_tty): if return_address: return_address_with_info = ScriptUtils.examine_expression(return_address.group(1)).all else: - return_address_with_info = "" + return_address_with_info = "<>" return_address_list.append(return_address_with_info) send_to_pince(return_address_list) @@ -375,11 +375,11 @@ def invoke(self, arg, from_tty): gdb.execute("stepi", to_string=True) elif step_mode == type_defs.STEP_MODE.STEP_OVER: gdb.execute("nexti", to_string=True) - status_info = (type_defs.TRACE_STATUS.STATUS_PROCESSING, "Processing the collected data") + status_info = (type_defs.TRACE_STATUS.STATUS_PROCESSING, "") pickle.dump(status_info, open(trace_status_file, "wb")) trace_instructions_file = SysUtils.get_trace_instructions_file(pid, breakpoint) json.dump((tree, root_index), open(trace_instructions_file, "w")) - status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "Tracing has been completed") + status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "") pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: gdb.execute("c") @@ -462,7 +462,7 @@ def invoke(self, arg, from_tty): ref_jmp_count = len(referenced_jumps_dict) ref_call_count = len(referenced_calls_dict) for region_index, (start_addr, end_addr) in enumerate(region_list): - region_info = start_addr+"-"+end_addr, "Region " + str(region_index + 1) + " of " + str(region_count) + region_info = start_addr+"-"+end_addr, str(region_index + 1) + " / " + str(region_count) start_addr = int(start_addr, 16) # Becomes address of the last disassembled instruction later on end_addr = int(end_addr, 16) region_finished = False diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 4f2e0c49..42ca4c1c 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -202,6 +202,7 @@ class SCAN_INDEX: INDEX_AOB = 10 # Array of Bytes +# GDB already provides breakpoint info in english, no need to make these translatable on_hit_to_text_dict = { BREAKPOINT_ON_HIT.BREAK: "Break", BREAKPOINT_ON_HIT.FIND_CODE: "Find Code", @@ -210,6 +211,7 @@ class SCAN_INDEX: } # Represents the texts at indexes in the address table +# TODO: This class is mostly an UI helper, maybe integrate it into the the UI completely in the future? index_to_text_dict = collections.OrderedDict([ (VALUE_INDEX.INDEX_INT8, "Int8"), (VALUE_INDEX.INDEX_INT16, "Int16"), @@ -221,7 +223,7 @@ class SCAN_INDEX: (VALUE_INDEX.INDEX_STRING_UTF8, "String_UTF8"), (VALUE_INDEX.INDEX_STRING_UTF16, "String_UTF16"), (VALUE_INDEX.INDEX_STRING_UTF32, "String_UTF32"), - (VALUE_INDEX.INDEX_AOB, "Array of Bytes") + (VALUE_INDEX.INDEX_AOB, "ByteArray") ]) text_to_index_dict = collections.OrderedDict() @@ -248,6 +250,7 @@ class SCAN_INDEX: ]) # Represents the texts at indexes in scan combobox +# TODO: Same as index_to_text_dict, consider integrating into UI completely scan_index_to_text_dict = collections.OrderedDict([ (SCAN_INDEX.INDEX_INT_ANY, "Int(any)"), (SCAN_INDEX.INDEX_INT8, "Int8"), @@ -259,7 +262,7 @@ class SCAN_INDEX: (SCAN_INDEX.INDEX_FLOAT64, "Float64"), (SCAN_INDEX.INDEX_ANY, "Any(int, float)"), (SCAN_INDEX.INDEX_STRING, "String"), - (VALUE_INDEX.INDEX_AOB, "Array of Bytes") + (VALUE_INDEX.INDEX_AOB, "ByteArray") ]) # Used in scan_data_type option of scanmem @@ -278,6 +281,7 @@ class SCAN_INDEX: ]) +# TODO: Same as index_to_text_dict, consider integrating into UI completely class SCAN_TYPE: EXACT = 0 INCREASED = 1 @@ -301,22 +305,6 @@ def get_list(scan_mode): SCAN_TYPE.CHANGED, SCAN_TYPE.UNCHANGED] -# Represents the texts at indexes in combobox -scan_type_to_text_dict = collections.OrderedDict([ - (SCAN_TYPE.EXACT, "Exact"), - (SCAN_TYPE.INCREASED, "Increased"), - (SCAN_TYPE.INCREASED_BY, "Increased by"), - (SCAN_TYPE.DECREASED, "Decreased"), - (SCAN_TYPE.DECREASED_BY, "Decreased by"), - (SCAN_TYPE.LESS, "Less Than"), - (SCAN_TYPE.MORE, "More Than"), - (SCAN_TYPE.BETWEEN, "Between"), - (SCAN_TYPE.CHANGED, "Changed"), - (SCAN_TYPE.UNCHANGED, "Unchanged"), - (SCAN_TYPE.UNKNOWN, "Unknown Value") -]) - - class SCAN_MODE: NEW = 0 ONGOING = 1 @@ -329,13 +317,6 @@ class SCAN_SCOPE: FULL = 4 -scan_scope_to_text_dict = collections.OrderedDict([ - (SCAN_SCOPE.BASIC, "Basic"), - (SCAN_SCOPE.NORMAL, "Normal"), - (SCAN_SCOPE.FULL_RW, "Read+Write"), - (SCAN_SCOPE.FULL, "Full") -]) - string_index_to_encoding_dict = { VALUE_INDEX.INDEX_STRING_UTF8: ["utf-8", "surrogateescape"], VALUE_INDEX.INDEX_STRING_UTF16: ["utf-16", "replace"], diff --git a/tr/tr.py b/tr/tr.py new file mode 100644 index 00000000..bdd05684 --- /dev/null +++ b/tr/tr.py @@ -0,0 +1,315 @@ +from PyQt6.QtCore import QObject, QT_TR_NOOP + + +class TranslationConstants(QObject): + @staticmethod + def translate(): + for key, value in vars(TranslationConstants).items(): + if not key.startswith("__") and isinstance(value, str): + setattr(TranslationConstants, key, TranslationConstants.tr(value)) + + PAUSE_HOTKEY = QT_TR_NOOP("Pause the process") + BREAK_HOTKEY = QT_TR_NOOP("Break the process") + CONTINUE_HOTKEY = QT_TR_NOOP("Continue the process") + TOGGLE_ATTACH_HOTKEY = QT_TR_NOOP("Toggle attach/detach") + EXACT_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Exact") + INC_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Increased") + DEC_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Decreased") + CHANGED_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Changed") + UNCHANGED_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Unchanged") + ERROR = QT_TR_NOOP("Error") + GDB_INIT = QT_TR_NOOP("GDB isn't initialized yet") + PROCESS_RUNNING = QT_TR_NOOP("Process is running\n" + "Press {} to stop process\n" + "\nGo to Settings->General to disable this dialog") + GDB_INIT_ERROR = QT_TR_NOOP("Unable to initialize GDB\n" + "You might want to reinstall GDB or use the system GDB\n" + "To change the current GDB path, check Settings->Debug") + EDIT = QT_TR_NOOP("Edit") + SHOW_HEX = QT_TR_NOOP("Show as hexadecimal") + SHOW_DEC = QT_TR_NOOP("Show as decimal") + SHOW_UNSIGNED = QT_TR_NOOP("Show as unsigned") + SHOW_SIGNED = QT_TR_NOOP("Show as signed") + TOGGLE_RECORDS = QT_TR_NOOP("Toggle selected records") + FREEZE = QT_TR_NOOP("Freeze") + DEFAULT = QT_TR_NOOP("Default") + INCREMENTAL = QT_TR_NOOP("Incremental") + DECREMENTAL = QT_TR_NOOP("Decremental") + BROWSE_MEMORY_REGION = QT_TR_NOOP("Browse this memory region") + DISASSEMBLE_ADDRESS = QT_TR_NOOP("Disassemble this address") + CUT_RECORDS = QT_TR_NOOP("Cut selected records") + COPY_RECORDS = QT_TR_NOOP("Copy selected records") + CUT_RECORDS_RECURSIVE = QT_TR_NOOP("Cut selected records (recursive)") + COPY_RECORDS_RECURSIVE = QT_TR_NOOP("Copy selected records (recursive)") + PASTE_BEFORE = QT_TR_NOOP("Paste selected records before") + PASTE_AFTER = QT_TR_NOOP("Paste selected records after") + PASTE_INSIDE = QT_TR_NOOP("Paste selected records inside") + DELETE_RECORDS = QT_TR_NOOP("Delete selected records") + WHAT_WRITES = QT_TR_NOOP("Find out what writes to this address") + WHAT_READS = QT_TR_NOOP("Find out what reads this address") + WHAT_ACCESSES = QT_TR_NOOP("Find out what accesses this address") + INVALID_CLIPBOARD = QT_TR_NOOP("Invalid clipboard content") + NEW_SCAN = QT_TR_NOOP("New Scan") + MATCH_COUNT_LIMITED = QT_TR_NOOP("Match count: {} ({} shown)") + MATCH_COUNT = QT_TR_NOOP("Match count: {}") + NO_DESCRIPTION = QT_TR_NOOP("No Description") + OPEN_PCT_FILE = QT_TR_NOOP("Open PCT file(s)") + + # Keep (*.pct) and (*) while translating, it doesn't matter where it stays within the sentence + # For instance, you can keep (*) in the beginning of the sentence for right-to-left languages like arabic + # All entries are separated by ;; Please try to respect the original order of the file types + FILE_TYPES_PCT = QT_TR_NOOP("PINCE Cheat Table (*.pct);;All files (*)") + CLEAR_TABLE = QT_TR_NOOP("Clear address table?") + FILE_LOAD_ERROR = QT_TR_NOOP("File {} is inaccessible or contains invalid content") + SAVE_PCT_FILE = QT_TR_NOOP("Save PCT file") + FILE_SAVE_ERROR = QT_TR_NOOP("Cannot save to file") + SMARTASS = QT_TR_NOOP("Nice try, smartass") + PROCESS_NOT_VALID = QT_TR_NOOP("Selected process is not valid") + ALREADY_DEBUGGING = QT_TR_NOOP("You're debugging this process already") + ALREADY_TRACED = QT_TR_NOOP("That process is already being traced by {}, could not attach to the process") + PERM_DENIED = QT_TR_NOOP("Permission denied, could not attach to the process") + CREATE_PROCESS_ERROR = QT_TR_NOOP("An error occurred while trying to create process") + SCAN_FOR = QT_TR_NOOP("Scan for") + FIRST_SCAN = QT_TR_NOOP("First Scan") + NO_PROCESS_SELECTED = QT_TR_NOOP("No Process Selected") + STATUS_DETACHED = QT_TR_NOOP("[detached]") + STATUS_STOPPED = QT_TR_NOOP("[stopped]") + ENTER_VALUE = QT_TR_NOOP("Enter the new value") + ENTER_DESCRIPTION = QT_TR_NOOP("Enter the new description") + EDIT_ADDRESS = QT_TR_NOOP("Edit Address") + SELECT_PROCESS = QT_TR_NOOP("Please select a process first") + SELECT_BINARY = QT_TR_NOOP("Select the target binary") + ENTER_OPTIONAL_ARGS = QT_TR_NOOP("Enter the optional arguments") + LD_PRELOAD_OPTIONAL = QT_TR_NOOP("LD_PRELOAD .so path (optional)") + REFRESH = QT_TR_NOOP("Refresh") + LENGTH_NOT_VALID = QT_TR_NOOP("Length is not valid") + LENGTH_GT = QT_TR_NOOP("Length must be greater than 0") + PARSE_ERROR = QT_TR_NOOP("Can't parse the input") + UPDATE_ASSERT_INT = QT_TR_NOOP("Update interval must be an int") + FREEZE_ASSERT_INT = QT_TR_NOOP("Freeze interval must be an int") + INSTRUCTION_ASSERT_INT = QT_TR_NOOP("Instruction count must be an int") + INSTRUCTION_ASSERT_LT = QT_TR_NOOP("Instruction count cannot be lower than {}") + INTERVAL_ASSERT_NEGATIVE = QT_TR_NOOP("Interval cannot be a negative number") + ASKING_FOR_TROUBLE = QT_TR_NOOP("You are asking for it, aren't you?") + UPDATE_ASSERT_GT = QT_TR_NOOP("Update interval should be bigger than {} ms\n" + "Setting update interval less than {} ms may cause slowdown\n" + "Proceed?") + IS_INVALID_REGEX = QT_TR_NOOP("{} isn't a valid regex") + GDB_RESET = QT_TR_NOOP("You have changed the GDB path, reset GDB now?") + RESET_DEFAULT_SETTINGS = QT_TR_NOOP("This will reset to the default settings\n" + "Proceed?") + MOUSE_OVER_EXAMPLES = QT_TR_NOOP("Mouse over on this text for examples") + AUTO_ATTACH_TOOLTIP = QT_TR_NOOP("asdf|qwer --> search for asdf or qwer\n" + "[as]df --> search for both adf and sdf\n" + "Use the char \\ to escape special chars such as [\n" + "\[asdf\] --> search for opcodes that contain [asdf]") + SEPARATE_PROCESSES_WITH = QT_TR_NOOP("Separate processes with {}") + SELECT_GDB_BINARY = QT_TR_NOOP("Select the gdb binary") + QUIT_SESSION_CRASH = QT_TR_NOOP("Quitting current session will crash PINCE") + INFERIOR_RUNNING = QT_TR_NOOP("Inferior is running") + GDB_CONSOLE_INIT = QT_TR_NOOP( + "Hotkeys:\n" + "----------------------------\n" + "Send=Enter |\n" + "Send ctrl+c=Ctrl+C |\n" + "Multi-line mode=Ctrl+Enter |\n" + "Complete command=Tab |\n" + "----------------------------\n" + "Commands:\n" + "----------------------------------------------------------\n" + "/clear: Clear the console |\n" + "phase-out: Detach from the current process |\n" + "phase-in: Attach back to the previously detached process |\n" + "---------------------------------------------------------------------------------------------------\n" + "pince-init-so-file so_file_path: Initializes 'lib' variable |\n" + "pince-get-so-file-information: Get information about current lib |\n" + "pince-execute-from-so-file lib.func(params): Execute a function from lib |\n" + "# Check https://github.com/korcankaraokcu/PINCE/wiki#extending-pince-with-so-files for an example |\n" + "# CLI output mode doesn't work very well with .so extensions, use MI output mode instead |\n" + "---------------------------------------------------------------------------------------------------\n" + "You can change the output mode from bottom right\n" + "Note: Changing output mode only affects commands sent. Any other output coming from " + "external sources(e.g async output) will be shown in MI format") + BREAK = QT_TR_NOOP("Break[{}]") + RUN = QT_TR_NOOP("Run[{}]") + TOGGLE_ATTACH = QT_TR_NOOP("Toggle Attach[{}]") + BREAKPOINT_FAILED = QT_TR_NOOP("Failed to set breakpoint at address {}") + ENTER_WATCHPOINT_LENGTH = QT_TR_NOOP("Enter the watchpoint length in size of bytes") + PARSE_ERROR_INT = QT_TR_NOOP("{} can't be parsed as an integer") + BREAKPOINT_ASSERT_LT = QT_TR_NOOP("Breakpoint length can't be lower than {}") + WATCHPOINT_FAILED = QT_TR_NOOP("Failed to set watchpoint at address {}") + COPY_CLIPBOARD = QT_TR_NOOP("Copy to Clipboard") + GO_TO_EXPRESSION = QT_TR_NOOP("Go to expression") + ADD_TO_ADDRESS_LIST = QT_TR_NOOP("Add this address to address list") + SET_WATCHPOINT = QT_TR_NOOP("Set Watchpoint") + WRITE_ONLY = QT_TR_NOOP("Write Only") + READ_ONLY = QT_TR_NOOP("Read Only") + BOTH = QT_TR_NOOP("Both") + CHANGE_BREAKPOINT_CONDITION = QT_TR_NOOP("Add/Change condition for breakpoint") + DELETE_BREAKPOINT = QT_TR_NOOP("Delete Breakpoint") + ENTER_EXPRESSION = QT_TR_NOOP("Enter the expression") + INVALID = QT_TR_NOOP("{} is invalid") + REGION_INFO = QT_TR_NOOP("Protection:{} | Base:{}-{} | Module:{}") + INVALID_REGION = QT_TR_NOOP("Invalid Region") + EXPRESSION_ACCESS_ERROR = QT_TR_NOOP("Cannot access memory at expression {}") + REFERENCED_BY = QT_TR_NOOP("Referenced by:") + SEE_REFERRERS = QT_TR_NOOP("Press 'Ctrl+E' to see a detailed list of referrers") + MV_PAUSED = QT_TR_NOOP("Memory Viewer - Paused") + MV_DEBUGGING = QT_TR_NOOP("Memory Viewer - Currently debugging {}") + MV_RUNNING = QT_TR_NOOP("Memory Viewer - Running") + ENTER_BP_CONDITION = QT_TR_NOOP("Enter the expression for condition, for instance:\n\n" + "$eax==0x523\n" + "$rax>0 && ($rbp<0 || $rsp==0)\n" + "printf($r10)==3") + BP_CONDITION_FAILED = QT_TR_NOOP("Failed to set condition for address {}\n" + "Check terminal for details") + FULL_STACK = QT_TR_NOOP("Full Stack") + COPY_RETURN_ADDRESS = QT_TR_NOOP("Copy Return Address") + COPY_FRAME_ADDRESS = QT_TR_NOOP("Copy Frame Address") + STACKTRACE = QT_TR_NOOP("Stacktrace") + COPY_ADDRESS = QT_TR_NOOP("Copy Address") + COPY_VALUE = QT_TR_NOOP("Copy Value") + COPY_POINTS_TO = QT_TR_NOOP("Copy Points to") + DISASSEMBLE_VALUE_POINTER = QT_TR_NOOP("Disassemble 'value' pointer address") + HEXVIEW_VALUE_POINTER = QT_TR_NOOP("Show 'value' pointer in HexView") + BACK = QT_TR_NOOP("Back") + HEXVIEW_ADDRESS = QT_TR_NOOP("Show this address in HexView") + FOLLOW = QT_TR_NOOP("Follow") + EXAMINE_REFERRERS = QT_TR_NOOP("Examine Referrers") + BOOKMARK_ADDRESS = QT_TR_NOOP("Bookmark this address") + DELETE_BOOKMARK = QT_TR_NOOP("Delete this bookmark") + CHANGE_COMMENT = QT_TR_NOOP("Change comment") + GO_TO_BOOKMARK_ADDRESS = QT_TR_NOOP("Go to bookmarked address") + TOGGLE_BREAKPOINT = QT_TR_NOOP("Toggle Breakpoint") + EDIT_INSTRUCTION = QT_TR_NOOP("Edit instruction") + REPLACE_WITH_NOPS = QT_TR_NOOP("Replace instruction with NOPs") + WHAT_ACCESSES_INSTRUCTION = QT_TR_NOOP("Find out which addresses this instruction accesses") + TRACE_INSTRUCTION = QT_TR_NOOP("Break and trace instructions") + DISSECT_REGION = QT_TR_NOOP("Dissect this region") + COPY_BYTES = QT_TR_NOOP("Copy Bytes") + COPY_OPCODE = QT_TR_NOOP("Copy Opcode") + COPY_COMMENT = QT_TR_NOOP("Copy Comment") + COPY_ALL = QT_TR_NOOP("Copy All") + ENTER_TRACK_BP_EXPRESSION = QT_TR_NOOP("Enter the register expression(s) you want to track\n" + "Register names must start with $\n" + "Each expression must be separated with a comma\n\n" + "For instance:\n" + "Let's say the instruction is mov [rax+rbx],30\n" + "Then you should enter $rax+$rbx\n" + "So PINCE can track address [rax+rbx]\n\n" + "Another example:\n" + "If you enter $rax,$rbx*$rcx+4,$rbp\n" + "PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]") + ALREADY_BOOKMARKED = QT_TR_NOOP("This address has already been bookmarked") + ENTER_BOOKMARK_COMMENT = QT_TR_NOOP("Enter the comment for bookmarked address") + SELECT_SO_FILE = QT_TR_NOOP("Select the .so file") + + # Same applies here, keep (*.so) + SHARED_OBJECT_TYPE = QT_TR_NOOP("Shared object library (*.so)") + SUCCESS = QT_TR_NOOP("Success") + FILE_INJECTED = QT_TR_NOOP("The file has been injected") + FILE_INJECT_FAILED = QT_TR_NOOP("Failed to inject the .so file") + ENTER_CALL_EXPRESSION = QT_TR_NOOP("Enter the expression for the function that'll be called from the inferior\n" + "You can view functions list from View->Functions\n\n" + "For instance:\n" + 'Calling printf("1234") will yield something like this\n' + '↓\n' + '$28 = 4\n\n' + '$28 is the assigned convenience variable\n' + '4 is the result\n' + 'You can use the assigned variable from the GDB Console') + CALL_EXPRESSION_FAILED = QT_TR_NOOP("Failed to call the expression {}") + INVALID_EXPRESSION = QT_TR_NOOP("Invalid expression or address") + INVALID_ENTRY = QT_TR_NOOP("Invalid entries detected, refreshing the page") + ADD_ENTRY = QT_TR_NOOP("Add new entry") + DELETE = QT_TR_NOOP("Delete") + ENTER_REGISTER_VALUE = QT_TR_NOOP("Enter the new value of register {}") + RESTORE_INSTRUCTION = QT_TR_NOOP("Restore this instruction") + ENTER_HIT_COUNT = QT_TR_NOOP("Enter the hit count({} or higher)") + HIT_COUNT_ASSERT_INT = QT_TR_NOOP("Hit count must be an integer") + HIT_COUNT_ASSERT_LT = QT_TR_NOOP("Hit count can't be lower than {}") + CHANGE_CONDITION = QT_TR_NOOP("Change condition") + ENABLE = QT_TR_NOOP("Enable") + DISABLE = QT_TR_NOOP("Disable") + DISABLE_AFTER_HIT = QT_TR_NOOP("Disable after hit") + DISABLE_AFTER_COUNT = QT_TR_NOOP("Disable after X hits") + DELETE_AFTER_HIT = QT_TR_NOOP("Delete after hit") + OPCODE_WRITING_TO = QT_TR_NOOP("Opcodes writing to the address {}") + OPCODE_READING_FROM = QT_TR_NOOP("Opcodes reading from the address {}") + OPCODE_ACCESSING_TO = QT_TR_NOOP("Opcodes accessing to the address {}") + TRACK_WATCHPOINT_FAILED = QT_TR_NOOP("Unable to track watchpoint at expression {}") + DELETE_WATCHPOINT_FAILED = QT_TR_NOOP("Unable to delete watchpoint at expression {}") + CLOSE = QT_TR_NOOP("Close") + ACCESSED_BY_INSTRUCTION = QT_TR_NOOP("Addresses accessed by instruction {}") + TRACK_BREAKPOINT_FAILED = QT_TR_NOOP("Unable to track breakpoint at expression {}") + ACCESSED_BY = QT_TR_NOOP("Accessed by {}") + DELETE_BREAKPOINT_FAILED = QT_TR_NOOP("Unable to delete breakpoint at expression {}") + MAX_TRACE_COUNT_ASSERT_GT = QT_TR_NOOP("Max trace count must be greater than or equal to {}") + PROCESSING_DATA = QT_TR_NOOP("Processing the collected data") + SAVE_TRACE_FILE = QT_TR_NOOP("Save trace file") + + # Same applies here, keep (*.trace) and (*) + FILE_TYPES_TRACE = QT_TR_NOOP("Trace File (*.trace);;All Files (*)") + OPEN_TRACE_FILE = QT_TR_NOOP("Open trace file") + EXPAND_ALL = QT_TR_NOOP("Expand All") + COLLAPSE_ALL = QT_TR_NOOP("Collapse All") + DEFINED = QT_TR_NOOP("DEFINED") + DEFINED_SYMBOL = QT_TR_NOOP("This symbol is defined. You can use its body as a gdb expression. For instance:\n\n" + "void func(param) can be used as 'func' as a gdb expression") + COPY_SYMBOL = QT_TR_NOOP("Copy Symbol") + FUNCTIONS_INFO_HELPER = QT_TR_NOOP("\tHere's some useful regex tips:\n" + "^quaso --> search for everything that starts with quaso\n" + "[ab]cd --> search for both acd and bcd\n\n" + "\tHow to interpret symbols:\n" + "A symbol that looks like 'func(param)@plt' consists of 3 pieces\n" + "func, func(param), func(param)@plt\n" + "These 3 functions will have different addresses\n" + "@plt means this function is a subroutine for the original one\n" + "There can be more than one of the same function\n" + "It means that the function is overloaded") + NEW_OPCODE = QT_TR_NOOP("New opcode is {} bytes long but old opcode is only {} bytes long\n" + "This will cause an overflow, proceed?") + IS_INVALID_EXPRESSION = QT_TR_NOOP("{} isn't a valid expression") + LOG_FILE = QT_TR_NOOP("Log File of PID {}") + LOG_CONTENTS = QT_TR_NOOP("Contents of {} (only last {} bytes are shown)") + ON = QT_TR_NOOP("ON") + OFF = QT_TR_NOOP("OFF") + LOG_STATUS = QT_TR_NOOP("LOGGING: {}") + LOG_READ_ERROR = QT_TR_NOOP("Unable to read log file at {}") + SETTINGS_ENABLE_LOG = QT_TR_NOOP("Go to Settings->Debug to enable logging") + INVALID_REGEX = QT_TR_NOOP("Invalid Regex") + SEARCH_OPCODE_HELPER = QT_TR_NOOP("\tHere's some useful regex examples:\n" + "call|rax --> search for opcodes that contain call or rax\n" + "[re]cx --> search for both rcx and ecx\n" + "Use the char \\ to escape special chars such as [\n" + "\[rsp\] --> search for opcodes that contain [rsp]") + COPY_ADDRESSES = QT_TR_NOOP("Copy Addresses") + COPY_OFFSET = QT_TR_NOOP("Copy Offset") + COPY_PATH = QT_TR_NOOP("Copy Path") + START = QT_TR_NOOP("Start") + CURRENT_SCAN_REGION = QT_TR_NOOP("Currently scanning region:") + CANCEL = QT_TR_NOOP("Cancel") + SCAN_FINISHED = QT_TR_NOOP("Scan finished") + SCAN_CANCELED = QT_TR_NOOP("Scan was canceled") + STOP_PROCESS = QT_TR_NOOP("Please stop the process first") + SELECT_ONE_REGION = QT_TR_NOOP("Select at least one region") + DISSECT_CODE = QT_TR_NOOP("You need to dissect code first\n" + "Proceed?") + WAITING_FOR_BREAKPOINT = QT_TR_NOOP("Waiting for breakpoint to trigger") + TRACING_CANCELED = QT_TR_NOOP("Tracing has been canceled") + TRACING_COMPLETED = QT_TR_NOOP("Tracing has been completed") + EXACT = QT_TR_NOOP("Exact") + INCREASED = QT_TR_NOOP("Increased") + INCREASED_BY = QT_TR_NOOP("Increased by") + DECREASED = QT_TR_NOOP("Decreased") + DECREASED_BY = QT_TR_NOOP("Decreased by") + LESS_THAN = QT_TR_NOOP("Less Than") + MORE_THAN = QT_TR_NOOP("More Than") + BETWEEN = QT_TR_NOOP("Between") + CHANGED = QT_TR_NOOP("Changed") + UNCHANGED = QT_TR_NOOP("Unchanged") + UNKNOWN_VALUE = QT_TR_NOOP("Unknown Value") + BASIC = QT_TR_NOOP("Basic") + NORMAL = QT_TR_NOOP("Normal") + RW = QT_TR_NOOP("Read+Write") + FULL = QT_TR_NOOP("Full") From 846e5c66370883f37bdef81dc2ae8f36c533546a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 10 Jul 2023 22:07:13 +0300 Subject: [PATCH 202/487] Fix search_functions for invalid regexes --- libpince/gdb_python_scripts/GDBCommandExtensions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 40abc20b..4e8887b9 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -595,9 +595,13 @@ def invoke(self, arg, from_tty): gdb.execute("set case-sensitive on") else: gdb.execute("set case-sensitive off") - output = gdb.execute("info functions " + expression, to_string=True).splitlines() + try: + output = gdb.execute("info functions " + expression, to_string=True) + except Exception as e: + print("An exception occurred while trying to search functions:\n", e) + output = "" gdb.execute("set case-sensitive auto") - for line in output: + for line in output.splitlines(): non_debugging = common_regexes.info_functions_non_debugging.search(line) if non_debugging: function_list.append((non_debugging.group(1), non_debugging.group(2))) From 29d466cb6f4daffa8eea7c246345c9c194eaa98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 11 Jul 2023 02:26:35 +0300 Subject: [PATCH 203/487] Fix tableWidget_TrackInfo_item_double_clicked --- PINCE.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 0ef4af38..997fb471 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4455,8 +4455,7 @@ def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() self.parent().parent().add_entry_to_addresstable(tr.ACCESSED_BY.format(self.address), address, - self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole), - 10, True) + self.comboBox_ValueType.currentIndex(), 10, True) def pushButton_Stop_clicked(self): if self.stopped: From e31ea7ce68f9cce5c3afbdecd7ae39d17baf1a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 11 Jul 2023 13:49:06 +0300 Subject: [PATCH 204/487] Use nx to ignore other gdb plugins --- libpince/GDB_Engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 98082b69..cddcce7d 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -491,8 +491,8 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): last_gdb_command = "" libpince_dir = SysUtils.get_libpince_directory() - child = pexpect.spawn('sudo -E --preserve-env=PATH LC_NUMERIC=C ' + gdb_path + ' --interpreter=mi', cwd=libpince_dir, - encoding="utf-8") + child = pexpect.spawn(f'sudo -E --preserve-env=PATH LC_NUMERIC=C {gdb_path} --nx --interpreter=mi', + cwd=libpince_dir, encoding="utf-8") child.setecho(False) child.delaybeforesend = 0 child.timeout = None From 7eb58024b61a4224de2b9951f5d9a12eb23dc9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 15 Jul 2023 22:43:14 +0300 Subject: [PATCH 205/487] Add alpha to background colors --- GUI/CustomAbstractTableModels/AsciiModel.py | 6 +++-- GUI/CustomAbstractTableModels/HexModel.py | 6 +++-- PINCE.py | 28 +++++++++++---------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/GUI/CustomAbstractTableModels/AsciiModel.py b/GUI/CustomAbstractTableModels/AsciiModel.py index 820e2176..9dde25bd 100644 --- a/GUI/CustomAbstractTableModels/AsciiModel.py +++ b/GUI/CustomAbstractTableModels/AsciiModel.py @@ -15,11 +15,13 @@ along with this program. If not, see . """ from PyQt6.QtCore import QVariant, Qt -from PyQt6.QtGui import QColorConstants +from PyQt6.QtGui import QColor, QColorConstants from GUI.CustomAbstractTableModels.HexModel import QHexModel from libpince import SysUtils, GDB_Engine +breakpoint_red = QColor(QColorConstants.Red) +breakpoint_red.setAlpha(96) class QAsciiModel(QHexModel): def __init__(self, row_count, column_count, parent=None): @@ -30,7 +32,7 @@ def data(self, QModelIndex, int_role=None): if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: - return QVariant(QColorConstants.Red) + return QVariant(breakpoint_red) elif int_role == Qt.ItemDataRole.DisplayRole: return QVariant(SysUtils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()])) return QVariant() diff --git a/GUI/CustomAbstractTableModels/HexModel.py b/GUI/CustomAbstractTableModels/HexModel.py index a68ea628..02a0ccba 100644 --- a/GUI/CustomAbstractTableModels/HexModel.py +++ b/GUI/CustomAbstractTableModels/HexModel.py @@ -15,10 +15,12 @@ along with this program. If not, see . """ from PyQt6.QtCore import QAbstractTableModel, QVariant, Qt -from PyQt6.QtGui import QColorConstants +from PyQt6.QtGui import QColor, QColorConstants from libpince import SysUtils, GDB_Engine +breakpoint_red = QColor(QColorConstants.Red) +breakpoint_red.setAlpha(96) class QHexModel(QAbstractTableModel): def __init__(self, row_count, column_count, parent=None): @@ -40,7 +42,7 @@ def data(self, QModelIndex, int_role=None): if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: - return QVariant(QColorConstants.Red) + return QVariant(breakpoint_red) elif int_role == Qt.ItemDataRole.DisplayRole: return QVariant(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]) diff --git a/PINCE.py b/PINCE.py index 997fb471..93955fe3 100755 --- a/PINCE.py +++ b/PINCE.py @@ -195,7 +195,6 @@ def get_hotkeys(): # row colours for disassemble qtablewidget PC_COLOUR = QColorConstants.Blue BOOKMARK_COLOUR = QColorConstants.Cyan -DEFAULT_COLOUR = QColorConstants.White BREAKPOINT_COLOUR = QColorConstants.Red REF_COLOUR = QColorConstants.LightGray @@ -800,7 +799,7 @@ def change_freeze_type(self, freeze_type): # TODO: Create a QWidget subclass with signals so freeze type can be changed by clicking on the cell if freeze_type == type_defs.FREEZE_TYPE.DEFAULT: row.setText(FROZEN_COL, "") - row.setForeground(FROZEN_COL, QBrush(QColor(0, 0, 0))) + row.setForeground(FROZEN_COL, QBrush()) elif freeze_type == type_defs.FREEZE_TYPE.INCREMENT: row.setText(FROZEN_COL, "▲") row.setForeground(FROZEN_COL, QBrush(QColor(0, 255, 0))) @@ -1487,7 +1486,7 @@ def treeWidget_AddressTable_item_clicked(self, row, column): frozen.value = row.text(VALUE_COL) else: row.setText(FROZEN_COL, "") - row.setForeground(FROZEN_COL, QBrush(QColor(0, 0, 0))) + row.setForeground(FROZEN_COL, QBrush()) def treeWidget_AddressTable_change_repr(self, new_repr): value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) @@ -3199,6 +3198,8 @@ def set_row_colour(self, row, colour): if GDB_Engine.currentpid == -1: return for col in range(self.tableWidget_Disassemble.columnCount()): + colour = QColor(colour) + colour.setAlpha(96) self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, colour) def on_process_stop(self): @@ -4731,13 +4732,15 @@ def apply_data(self, output): self.tableWidget_SymbolInfo.setSortingEnabled(False) self.tableWidget_SymbolInfo.setRowCount(0) self.tableWidget_SymbolInfo.setRowCount(len(output)) + defined_color = QColor(QColorConstants.Green) + defined_color.setAlpha(96) for row, item in enumerate(output): address = item[0] if address: address_item = QTableWidgetItem(address) else: address_item = QTableWidgetItem(tr.DEFINED) - address_item.setBackground(QColorConstants.Green) + address_item.setBackground(defined_color) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_ADDR_COL, address_item) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_SYMBOL_COL, QTableWidgetItem(item[1])) self.tableWidget_SymbolInfo.setSortingEnabled(True) @@ -4892,14 +4895,14 @@ def lineEdit_HexView_selection_changed(self): def lineEdit_HexView_text_edited(self): aob_string = self.lineEdit_HexView.text() if not SysUtils.parse_string(aob_string, type_defs.VALUE_INDEX.INDEX_AOB): - self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: red;}") + self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") return aob_array = aob_string.split() try: self.lineEdit_AsciiView.setText(SysUtils.aob_to_str(aob_array, "utf-8")) self.lineEdit_HexView.setStyleSheet("") # This should set background color back to QT default except ValueError: - self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: red;}") + self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") def lineEdit_AsciiView_text_edited(self): ascii_str = self.lineEdit_AsciiView.text() @@ -4907,7 +4910,7 @@ def lineEdit_AsciiView_text_edited(self): self.lineEdit_HexView.setText(SysUtils.str_to_aob(ascii_str, "utf-8")) self.lineEdit_AsciiView.setStyleSheet("") except ValueError: - self.lineEdit_AsciiView.setStyleSheet("QLineEdit {background-color: red;}") + self.lineEdit_AsciiView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") def refresh_view(self): self.lineEdit_AsciiView.clear() @@ -5139,15 +5142,14 @@ def pushButton_TextUp_clicked(self): self.label_FoundCount.setText(str(self.current_found) + "/" + str(self.found_count)) def highlight_text(self): - self.textBrowser_TypeDefs.selectAll() - self.textBrowser_TypeDefs.setTextBackgroundColor(QColorConstants.White) cursor = self.textBrowser_TypeDefs.textCursor() cursor.clearSelection() cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_TypeDefs.setTextCursor(cursor) - highlight_format = QTextCharFormat() - highlight_format.setBackground(QColorConstants.LightGray) + color = QColor(QColorConstants.LightGray) + color.setAlpha(96) + highlight_format.setBackground(color) pattern = self.lineEdit_SearchText.text() found_count = 0 while True: @@ -5159,14 +5161,14 @@ def highlight_text(self): self.found_count = found_count if found_count == 0: self.label_FoundCount.setText("0/0") - return + else: + self.label_FoundCount.setText("1/" + str(found_count)) cursor = self.textBrowser_TypeDefs.textCursor() cursor.clearSelection() cursor.movePosition(QTextCursor.MoveOperation.Start) self.textBrowser_TypeDefs.setTextCursor(cursor) self.textBrowser_TypeDefs.find(pattern) self.current_found = 1 - self.label_FoundCount.setText("1/" + str(found_count)) def toggle_type_defs(self): if self.type_defs_shown: From 3a1a91cbb952996f3233abcb9ef873fa98149611 Mon Sep 17 00:00:00 2001 From: Domenico <50798132+Domefemia@users.noreply.github.com> Date: Wed, 19 Jul 2023 18:03:05 +0200 Subject: [PATCH 206/487] Translation work (#195) * Removed strings that don't need to translated * Updated py files with new ui * Update italian translation * Updated ts file with pylupdate6 * Added missing tr.py --- GUI/AddAddressManuallyDialog.py | 42 ++-- GUI/AddAddressManuallyDialog.ui | 4 +- GUI/ConsoleWidget.py | 33 ++- GUI/ConsoleWidget.ui | 33 ++- GUI/DissectCodeDialog.py | 44 ++-- GUI/DissectCodeDialog.ui | 6 +- GUI/EditTypeDialog.py | 16 +- GUI/EditTypeDialog.ui | 2 +- GUI/FloatRegisterWidget.py | 12 +- GUI/FloatRegisterWidget.ui | 4 +- GUI/LibpinceReferenceWidget.py | 54 ++--- GUI/LibpinceReferenceWidget.ui | 2 +- GUI/MainWindow.py | 6 +- GUI/MainWindow.ui | 4 +- GUI/MemoryViewerWindow.py | 324 ++++++++++++------------- GUI/MemoryViewerWindow.ui | 100 ++++---- GUI/SettingsDialog.py | 86 +++---- GUI/SettingsDialog.ui | 8 +- GUI/TraceInstructionsPromptDialog.py | 30 +-- GUI/TraceInstructionsPromptDialog.ui | 2 +- i18n/ts/it_IT.ts | 347 +++------------------------ 21 files changed, 446 insertions(+), 713 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index bc16ab90..44874441 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -22,7 +22,7 @@ def setupUi(self, Dialog): Dialog.setMaximumSize(QtCore.QSize(224, 16777215)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") - self.widget_Pointer = QtWidgets.QWidget(Dialog) + self.widget_Pointer = QtWidgets.QWidget(parent=Dialog) self.widget_Pointer.setEnabled(True) self.widget_Pointer.setMinimumSize(QtCore.QSize(0, 0)) self.widget_Pointer.setObjectName("widget_Pointer") @@ -32,12 +32,12 @@ def setupUi(self, Dialog): self.verticalLayout_4.setObjectName("verticalLayout_4") self.verticalLayout_Pointers = QtWidgets.QVBoxLayout() self.verticalLayout_Pointers.setObjectName("verticalLayout_Pointers") - self.label_BaseAddress = QtWidgets.QLabel(self.widget_Pointer) + self.label_BaseAddress = QtWidgets.QLabel(parent=self.widget_Pointer) self.label_BaseAddress.setObjectName("label_BaseAddress") self.verticalLayout_Pointers.addWidget(self.label_BaseAddress) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.lineEdit_PtrStartAddress = QtWidgets.QLineEdit(self.widget_Pointer) + self.lineEdit_PtrStartAddress = QtWidgets.QLineEdit(parent=self.widget_Pointer) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -50,16 +50,16 @@ def setupUi(self, Dialog): self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") - self.addOffsetButton = QtWidgets.QPushButton(self.widget_Pointer) + self.addOffsetButton = QtWidgets.QPushButton(parent=self.widget_Pointer) self.addOffsetButton.setObjectName("addOffsetButton") self.horizontalLayout_5.addWidget(self.addOffsetButton) - self.removeOffsetButton = QtWidgets.QPushButton(self.widget_Pointer) + self.removeOffsetButton = QtWidgets.QPushButton(parent=self.widget_Pointer) self.removeOffsetButton.setObjectName("removeOffsetButton") self.horizontalLayout_5.addWidget(self.removeOffsetButton) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_5) self.verticalLayout_4.addLayout(self.verticalLayout_Pointers) self.gridLayout.addWidget(self.widget_Pointer, 7, 0, 1, 1) - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -70,7 +70,7 @@ def setupUi(self, Dialog): self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) - self.checkBox_IsPointer = QtWidgets.QCheckBox(Dialog) + self.checkBox_IsPointer = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) @@ -79,19 +79,19 @@ def setupUi(self, Dialog): self.verticalLayout_3.setObjectName("verticalLayout_3") self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.label_5 = QtWidgets.QLabel(Dialog) + self.label_5 = QtWidgets.QLabel(parent=Dialog) self.label_5.setObjectName("label_5") self.horizontalLayout_3.addWidget(self.label_5) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem2) - self.checkBox_zeroterminate = QtWidgets.QCheckBox(Dialog) + self.checkBox_zeroterminate = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_zeroterminate.setChecked(True) self.checkBox_zeroterminate.setObjectName("checkBox_zeroterminate") self.horizontalLayout_3.addWidget(self.checkBox_zeroterminate) self.verticalLayout_3.addLayout(self.horizontalLayout_3) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.comboBox_ValueType = QtWidgets.QComboBox(Dialog) + self.comboBox_ValueType = QtWidgets.QComboBox(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -102,10 +102,10 @@ def setupUi(self, Dialog): self.horizontalLayout_2.addWidget(self.comboBox_ValueType) spacerItem3 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem3) - self.label_length = QtWidgets.QLabel(Dialog) + self.label_length = QtWidgets.QLabel(parent=Dialog) self.label_length.setObjectName("label_length") self.horizontalLayout_2.addWidget(self.label_length) - self.lineEdit_length = QtWidgets.QLineEdit(Dialog) + self.lineEdit_length = QtWidgets.QLineEdit(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -113,18 +113,19 @@ def setupUi(self, Dialog): self.lineEdit_length.setSizePolicy(sizePolicy) self.lineEdit_length.setMaximumSize(QtCore.QSize(60, 16777215)) self.lineEdit_length.setInputMask("") + self.lineEdit_length.setText("10") self.lineEdit_length.setObjectName("lineEdit_length") self.horizontalLayout_2.addWidget(self.lineEdit_length) self.verticalLayout_3.addLayout(self.horizontalLayout_2) self.gridLayout.addLayout(self.verticalLayout_3, 2, 0, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") - self.label = QtWidgets.QLabel(Dialog) + self.label = QtWidgets.QLabel(parent=Dialog) self.label.setObjectName("label") self.verticalLayout_2.addWidget(self.label) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.lineEdit_address = QtWidgets.QLineEdit(Dialog) + self.lineEdit_address = QtWidgets.QLineEdit(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -134,10 +135,11 @@ def setupUi(self, Dialog): self.lineEdit_address.setText("") self.lineEdit_address.setObjectName("lineEdit_address") self.horizontalLayout.addWidget(self.lineEdit_address) - self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2 = QtWidgets.QLabel(parent=Dialog) + self.label_2.setText("=") self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) - self.label_valueofaddress = QtWidgets.QLabel(Dialog) + self.label_valueofaddress = QtWidgets.QLabel(parent=Dialog) self.label_valueofaddress.setText("") self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_valueofaddress.setObjectName("label_valueofaddress") @@ -148,10 +150,10 @@ def setupUi(self, Dialog): self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.label_4 = QtWidgets.QLabel(Dialog) + self.label_4 = QtWidgets.QLabel(parent=Dialog) self.label_4.setObjectName("label_4") self.verticalLayout.addWidget(self.label_4) - self.lineEdit_description = QtWidgets.QLineEdit(Dialog) + self.lineEdit_description = QtWidgets.QLineEdit(parent=Dialog) self.lineEdit_description.setText("") self.lineEdit_description.setObjectName("lineEdit_description") self.verticalLayout.addWidget(self.lineEdit_description) @@ -173,7 +175,5 @@ def retranslateUi(self, Dialog): self.label_5.setText(_translate("Dialog", "Type:")) self.checkBox_zeroterminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_length.setText(_translate("Dialog", "Length")) - self.lineEdit_length.setText(_translate("Dialog", "10")) self.label.setText(_translate("Dialog", "Address:")) - self.label_2.setText(_translate("Dialog", "=")) self.label_4.setText(_translate("Dialog", "Description:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 39465163..005f42f1 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -255,7 +255,7 @@ - 10 + 10 @@ -296,7 +296,7 @@ - = + = diff --git a/GUI/ConsoleWidget.py b/GUI/ConsoleWidget.py index 62ca270e..03eb8d80 100644 --- a/GUI/ConsoleWidget.py +++ b/GUI/ConsoleWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ConsoleWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -23,7 +23,7 @@ def setupUi(self, Form): self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.textBrowser = QtWidgets.QTextBrowser(Form) + self.textBrowser = QtWidgets.QTextBrowser(parent=Form) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 255, 0)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -31,18 +31,27 @@ def setupUi(self, Form): brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 255, 0, 128)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.PlaceholderText, brush) brush = QtGui.QBrush(QtGui.QColor(0, 255, 0)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 255, 0, 128)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.PlaceholderText, brush) brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 255, 0, 128)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.PlaceholderText, brush) self.textBrowser.setPalette(palette) font = QtGui.QFont() font.setFamily("Monospace") @@ -50,23 +59,28 @@ def setupUi(self, Form): font.setItalic(False) font.setWeight(50) self.textBrowser.setFont(font) + self.textBrowser.setHtml("\n" +"\n" +"


") self.textBrowser.setObjectName("textBrowser") self.verticalLayout.addWidget(self.textBrowser) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.lineEdit = QtWidgets.QLineEdit(Form) + self.lineEdit = QtWidgets.QLineEdit(parent=Form) self.lineEdit.setObjectName("lineEdit") self.horizontalLayout.addWidget(self.lineEdit) - self.pushButton_Send = QtWidgets.QPushButton(Form) + self.pushButton_Send = QtWidgets.QPushButton(parent=Form) self.pushButton_Send.setObjectName("pushButton_Send") self.horizontalLayout.addWidget(self.pushButton_Send) - self.pushButton_SendCtrl = QtWidgets.QPushButton(Form) + self.pushButton_SendCtrl = QtWidgets.QPushButton(parent=Form) self.pushButton_SendCtrl.setObjectName("pushButton_SendCtrl") self.horizontalLayout.addWidget(self.pushButton_SendCtrl) - self.radioButton_CLI = QtWidgets.QRadioButton(Form) + self.radioButton_CLI = QtWidgets.QRadioButton(parent=Form) self.radioButton_CLI.setObjectName("radioButton_CLI") self.horizontalLayout.addWidget(self.radioButton_CLI) - self.radioButton_MI = QtWidgets.QRadioButton(Form) + self.radioButton_MI = QtWidgets.QRadioButton(parent=Form) self.radioButton_MI.setChecked(True) self.radioButton_MI.setObjectName("radioButton_MI") self.horizontalLayout.addWidget(self.radioButton_MI) @@ -79,11 +93,6 @@ def setupUi(self, Form): def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "GDB Console")) - self.textBrowser.setHtml(_translate("Form", "\n" -"\n" -"


")) self.pushButton_Send.setText(_translate("Form", "Send")) self.pushButton_SendCtrl.setText(_translate("Form", "Send ctrl+c")) self.radioButton_CLI.setText(_translate("Form", "CLI")) diff --git a/GUI/ConsoleWidget.ui b/GUI/ConsoleWidget.ui index 51b3eba2..501534e8 100644 --- a/GUI/ConsoleWidget.ui +++ b/GUI/ConsoleWidget.ui @@ -51,6 +51,15 @@ + + + + 0 + 255 + 0 + + + @@ -71,6 +80,15 @@ + + + + 0 + 255 + 0 + + + @@ -91,6 +109,15 @@ + + + + 0 + 255 + 0 + + + @@ -103,11 +130,11 @@ - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Monospace'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> +</style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;"><br /></p></body></html> diff --git a/GUI/DissectCodeDialog.py b/GUI/DissectCodeDialog.py index 85dd3922..efcd7932 100644 --- a/GUI/DissectCodeDialog.py +++ b/GUI/DissectCodeDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'DissectCodeDialog.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -15,10 +15,10 @@ def setupUi(self, Dialog): Dialog.resize(799, 412) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") - self.splitter = QtWidgets.QSplitter(Dialog) + self.splitter = QtWidgets.QSplitter(parent=Dialog) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") - self.tableWidget_ExecutableMemoryRegions = QtWidgets.QTableWidget(self.splitter) + self.tableWidget_ExecutableMemoryRegions = QtWidgets.QTableWidget(parent=self.splitter) self.tableWidget_ExecutableMemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_ExecutableMemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_ExecutableMemoryRegions.setWordWrap(False) @@ -33,77 +33,80 @@ def setupUi(self, Dialog): self.tableWidget_ExecutableMemoryRegions.verticalHeader().setVisible(False) self.tableWidget_ExecutableMemoryRegions.verticalHeader().setDefaultSectionSize(16) self.tableWidget_ExecutableMemoryRegions.verticalHeader().setMinimumSectionSize(16) - self.layoutWidget = QtWidgets.QWidget(self.splitter) + self.layoutWidget = QtWidgets.QWidget(parent=self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.label_ScanInfo = QtWidgets.QLabel(self.layoutWidget) + self.label_ScanInfo = QtWidgets.QLabel(parent=self.layoutWidget) self.label_ScanInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_ScanInfo.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_ScanInfo.setObjectName("label_ScanInfo") self.verticalLayout.addWidget(self.label_ScanInfo) - self.label_RegionInfo = QtWidgets.QLabel(self.layoutWidget) + self.label_RegionInfo = QtWidgets.QLabel(parent=self.layoutWidget) + self.label_RegionInfo.setText("-") self.label_RegionInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_RegionInfo.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_RegionInfo.setObjectName("label_RegionInfo") self.verticalLayout.addWidget(self.label_RegionInfo) - self.label_RegionCountInfo = QtWidgets.QLabel(self.layoutWidget) + self.label_RegionCountInfo = QtWidgets.QLabel(parent=self.layoutWidget) + self.label_RegionCountInfo.setText("-") self.label_RegionCountInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_RegionCountInfo.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_RegionCountInfo.setObjectName("label_RegionCountInfo") self.verticalLayout.addWidget(self.label_RegionCountInfo) - self.label_4 = QtWidgets.QLabel(self.layoutWidget) + self.label_4 = QtWidgets.QLabel(parent=self.layoutWidget) self.label_4.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_4.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_4.setObjectName("label_4") self.verticalLayout.addWidget(self.label_4) - self.label_CurrentRange = QtWidgets.QLabel(self.layoutWidget) + self.label_CurrentRange = QtWidgets.QLabel(parent=self.layoutWidget) + self.label_CurrentRange.setText("-") self.label_CurrentRange.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.label_CurrentRange.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_CurrentRange.setObjectName("label_CurrentRange") self.verticalLayout.addWidget(self.label_CurrentRange) self.verticalLayout_2.addLayout(self.verticalLayout) - self.line = QtWidgets.QFrame(self.layoutWidget) + self.line = QtWidgets.QFrame(parent=self.layoutWidget) self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line.setObjectName("line") self.verticalLayout_2.addWidget(self.line) - self.label = QtWidgets.QLabel(self.layoutWidget) + self.label = QtWidgets.QLabel(parent=self.layoutWidget) self.label.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label.setObjectName("label") self.verticalLayout_2.addWidget(self.label) - self.label_StringReferenceCount = QtWidgets.QLabel(self.layoutWidget) + self.label_StringReferenceCount = QtWidgets.QLabel(parent=self.layoutWidget) self.label_StringReferenceCount.setText("") self.label_StringReferenceCount.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_StringReferenceCount.setObjectName("label_StringReferenceCount") self.verticalLayout_2.addWidget(self.label_StringReferenceCount) - self.label_2 = QtWidgets.QLabel(self.layoutWidget) + self.label_2 = QtWidgets.QLabel(parent=self.layoutWidget) self.label_2.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_2.setObjectName("label_2") self.verticalLayout_2.addWidget(self.label_2) - self.label_JumpReferenceCount = QtWidgets.QLabel(self.layoutWidget) + self.label_JumpReferenceCount = QtWidgets.QLabel(parent=self.layoutWidget) self.label_JumpReferenceCount.setText("") self.label_JumpReferenceCount.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_JumpReferenceCount.setObjectName("label_JumpReferenceCount") self.verticalLayout_2.addWidget(self.label_JumpReferenceCount) - self.label_3 = QtWidgets.QLabel(self.layoutWidget) + self.label_3 = QtWidgets.QLabel(parent=self.layoutWidget) self.label_3.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_3.setObjectName("label_3") self.verticalLayout_2.addWidget(self.label_3) - self.label_CallReferenceCount = QtWidgets.QLabel(self.layoutWidget) + self.label_CallReferenceCount = QtWidgets.QLabel(parent=self.layoutWidget) self.label_CallReferenceCount.setText("") self.label_CallReferenceCount.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_CallReferenceCount.setObjectName("label_CallReferenceCount") self.verticalLayout_2.addWidget(self.label_CallReferenceCount) - self.line_2 = QtWidgets.QFrame(self.layoutWidget) + self.line_2 = QtWidgets.QFrame(parent=self.layoutWidget) self.line_2.setFrameShape(QtWidgets.QFrame.Shape.HLine) self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_2.setObjectName("line_2") self.verticalLayout_2.addWidget(self.line_2) - self.checkBox_DiscardInvalidStrings = QtWidgets.QCheckBox(self.layoutWidget) + self.checkBox_DiscardInvalidStrings = QtWidgets.QCheckBox(parent=self.layoutWidget) self.checkBox_DiscardInvalidStrings.setChecked(True) self.checkBox_DiscardInvalidStrings.setObjectName("checkBox_DiscardInvalidStrings") self.verticalLayout_2.addWidget(self.checkBox_DiscardInvalidStrings) @@ -111,7 +114,7 @@ def setupUi(self, Dialog): self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) - self.pushButton_StartCancel = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_StartCancel = QtWidgets.QPushButton(parent=self.layoutWidget) self.pushButton_StartCancel.setText("") self.pushButton_StartCancel.setObjectName("pushButton_StartCancel") self.horizontalLayout.addWidget(self.pushButton_StartCancel) @@ -133,10 +136,7 @@ def retranslateUi(self, Dialog): item = self.tableWidget_ExecutableMemoryRegions.horizontalHeaderItem(1) item.setText(_translate("Dialog", "Path")) self.label_ScanInfo.setText(_translate("Dialog", "Selected regions will be scanned")) - self.label_RegionInfo.setText(_translate("Dialog", "-")) - self.label_RegionCountInfo.setText(_translate("Dialog", "-")) self.label_4.setText(_translate("Dialog", "Currently scanning range:")) - self.label_CurrentRange.setText(_translate("Dialog", "-")) self.label.setText(_translate("Dialog", "String references found:")) self.label_2.setText(_translate("Dialog", "Jumps found:")) self.label_3.setText(_translate("Dialog", "Calls found:")) diff --git a/GUI/DissectCodeDialog.ui b/GUI/DissectCodeDialog.ui index e68e14db..bcbbe7d6 100644 --- a/GUI/DissectCodeDialog.ui +++ b/GUI/DissectCodeDialog.ui @@ -72,7 +72,7 @@ - - + - Qt::AlignCenter @@ -85,7 +85,7 @@ - - + - Qt::AlignCenter @@ -111,7 +111,7 @@ - - + - Qt::AlignCenter diff --git a/GUI/EditTypeDialog.py b/GUI/EditTypeDialog.py index 1254888c..747f1971 100644 --- a/GUI/EditTypeDialog.py +++ b/GUI/EditTypeDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'EditTypeDialog.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -20,21 +20,22 @@ def setupUi(self, Dialog): self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.label = QtWidgets.QLabel(Dialog) + self.label = QtWidgets.QLabel(parent=Dialog) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) - self.comboBox_ValueType = QtWidgets.QComboBox(Dialog) + self.comboBox_ValueType = QtWidgets.QComboBox(parent=Dialog) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.verticalLayout.addWidget(self.comboBox_ValueType) self.horizontalLayout_3.addLayout(self.verticalLayout) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") - self.label_Length = QtWidgets.QLabel(Dialog) + self.label_Length = QtWidgets.QLabel(parent=Dialog) self.label_Length.setObjectName("label_Length") self.verticalLayout_3.addWidget(self.label_Length) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lineEdit_Length = QtWidgets.QLineEdit(Dialog) + self.lineEdit_Length = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Length.setText("10") self.lineEdit_Length.setObjectName("lineEdit_Length") self.horizontalLayout_2.addWidget(self.lineEdit_Length) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -45,7 +46,7 @@ def setupUi(self, Dialog): self.verticalLayout_2.setObjectName("verticalLayout_2") spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_2.addItem(spacerItem1) - self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(Dialog) + self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_ZeroTerminate.setChecked(True) self.checkBox_ZeroTerminate.setObjectName("checkBox_ZeroTerminate") self.verticalLayout_2.addWidget(self.checkBox_ZeroTerminate) @@ -53,7 +54,7 @@ def setupUi(self, Dialog): self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") @@ -72,5 +73,4 @@ def retranslateUi(self, Dialog): Dialog.setWindowTitle(_translate("Dialog", "Type")) self.label.setText(_translate("Dialog", "Select the new type")) self.label_Length.setText(_translate("Dialog", "Length")) - self.lineEdit_Length.setText(_translate("Dialog", "10")) self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) diff --git a/GUI/EditTypeDialog.ui b/GUI/EditTypeDialog.ui index 42b68050..226d9d46 100644 --- a/GUI/EditTypeDialog.ui +++ b/GUI/EditTypeDialog.ui @@ -50,7 +50,7 @@ - 10 + 10 diff --git a/GUI/FloatRegisterWidget.py b/GUI/FloatRegisterWidget.py index 3b5c8510..551e17b1 100644 --- a/GUI/FloatRegisterWidget.py +++ b/GUI/FloatRegisterWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'FloatRegisterWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -17,7 +17,7 @@ def setupUi(self, TabWidget): self.FPU.setObjectName("FPU") self.gridLayout = QtWidgets.QGridLayout(self.FPU) self.gridLayout.setObjectName("gridLayout") - self.tableWidget_FPU = QtWidgets.QTableWidget(self.FPU) + self.tableWidget_FPU = QtWidgets.QTableWidget(parent=self.FPU) self.tableWidget_FPU.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_FPU.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_FPU.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -32,12 +32,12 @@ def setupUi(self, TabWidget): self.tableWidget_FPU.horizontalHeader().setStretchLastSection(True) self.tableWidget_FPU.verticalHeader().setVisible(False) self.gridLayout.addWidget(self.tableWidget_FPU, 0, 0, 1, 1) - TabWidget.addTab(self.FPU, "") + TabWidget.addTab(self.FPU, "FPU") self.XMM = QtWidgets.QWidget() self.XMM.setObjectName("XMM") self.gridLayout_2 = QtWidgets.QGridLayout(self.XMM) self.gridLayout_2.setObjectName("gridLayout_2") - self.tableWidget_XMM = QtWidgets.QTableWidget(self.XMM) + self.tableWidget_XMM = QtWidgets.QTableWidget(parent=self.XMM) self.tableWidget_XMM.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_XMM.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_XMM.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -51,7 +51,7 @@ def setupUi(self, TabWidget): self.tableWidget_XMM.horizontalHeader().setStretchLastSection(True) self.tableWidget_XMM.verticalHeader().setVisible(False) self.gridLayout_2.addWidget(self.tableWidget_XMM, 0, 0, 1, 1) - TabWidget.addTab(self.XMM, "") + TabWidget.addTab(self.XMM, "XMM") self.retranslateUi(TabWidget) TabWidget.setCurrentIndex(0) @@ -64,9 +64,7 @@ def retranslateUi(self, TabWidget): item.setText(_translate("TabWidget", "Register")) item = self.tableWidget_FPU.horizontalHeaderItem(1) item.setText(_translate("TabWidget", "Value")) - TabWidget.setTabText(TabWidget.indexOf(self.FPU), _translate("TabWidget", "FPU")) item = self.tableWidget_XMM.horizontalHeaderItem(0) item.setText(_translate("TabWidget", "Register")) item = self.tableWidget_XMM.horizontalHeaderItem(1) item.setText(_translate("TabWidget", "Value")) - TabWidget.setTabText(TabWidget.indexOf(self.XMM), _translate("TabWidget", "XMM")) diff --git a/GUI/FloatRegisterWidget.ui b/GUI/FloatRegisterWidget.ui index f67723d0..eee44c35 100644 --- a/GUI/FloatRegisterWidget.ui +++ b/GUI/FloatRegisterWidget.ui @@ -18,7 +18,7 @@ - FPU + FPU @@ -57,7 +57,7 @@ - XMM + XMM diff --git a/GUI/LibpinceReferenceWidget.py b/GUI/LibpinceReferenceWidget.py index d9604239..0a777d0c 100644 --- a/GUI/LibpinceReferenceWidget.py +++ b/GUI/LibpinceReferenceWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'LibpinceReferenceWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -17,26 +17,26 @@ def setupUi(self, Form): self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setSpacing(0) self.gridLayout_2.setObjectName("gridLayout_2") - self.splitter = QtWidgets.QSplitter(Form) + self.splitter = QtWidgets.QSplitter(parent=Form) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setHandleWidth(10) self.splitter.setObjectName("splitter") - self.widget_TypeDefs = QtWidgets.QWidget(self.splitter) + self.widget_TypeDefs = QtWidgets.QWidget(parent=self.splitter) self.widget_TypeDefs.setObjectName("widget_TypeDefs") self.gridLayout = QtWidgets.QGridLayout(self.widget_TypeDefs) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.label_5 = QtWidgets.QLabel(self.widget_TypeDefs) + self.label_5 = QtWidgets.QLabel(parent=self.widget_TypeDefs) self.label_5.setObjectName("label_5") self.horizontalLayout_4.addWidget(self.label_5) - self.line = QtWidgets.QFrame(self.widget_TypeDefs) + self.line = QtWidgets.QFrame(parent=self.widget_TypeDefs) self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine) self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line.setObjectName("line") self.horizontalLayout_4.addWidget(self.line) - self.label_3 = QtWidgets.QLabel(self.widget_TypeDefs) + self.label_3 = QtWidgets.QLabel(parent=self.widget_TypeDefs) self.label_3.setObjectName("label_3") self.horizontalLayout_4.addWidget(self.label_3) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -44,30 +44,31 @@ def setupUi(self, Form): self.gridLayout.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lineEdit_SearchText = QtWidgets.QLineEdit(self.widget_TypeDefs) + self.lineEdit_SearchText = QtWidgets.QLineEdit(parent=self.widget_TypeDefs) self.lineEdit_SearchText.setObjectName("lineEdit_SearchText") self.horizontalLayout_2.addWidget(self.lineEdit_SearchText) - self.pushButton_TextUp = QtWidgets.QPushButton(self.widget_TypeDefs) + self.pushButton_TextUp = QtWidgets.QPushButton(parent=self.widget_TypeDefs) self.pushButton_TextUp.setText("") self.pushButton_TextUp.setObjectName("pushButton_TextUp") self.horizontalLayout_2.addWidget(self.pushButton_TextUp) - self.pushButton_TextDown = QtWidgets.QPushButton(self.widget_TypeDefs) + self.pushButton_TextDown = QtWidgets.QPushButton(parent=self.widget_TypeDefs) self.pushButton_TextDown.setText("") self.pushButton_TextDown.setObjectName("pushButton_TextDown") self.horizontalLayout_2.addWidget(self.pushButton_TextDown) - self.label_FoundCount = QtWidgets.QLabel(self.widget_TypeDefs) + self.label_FoundCount = QtWidgets.QLabel(parent=self.widget_TypeDefs) + self.label_FoundCount.setText("0/0") self.label_FoundCount.setObjectName("label_FoundCount") self.horizontalLayout_2.addWidget(self.label_FoundCount) self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1) - self.textBrowser_TypeDefs = QtWidgets.QTextBrowser(self.widget_TypeDefs) + self.textBrowser_TypeDefs = QtWidgets.QTextBrowser(parent=self.widget_TypeDefs) self.textBrowser_TypeDefs.setObjectName("textBrowser_TypeDefs") self.gridLayout.addWidget(self.textBrowser_TypeDefs, 2, 0, 1, 1) - self.widget_Resources = QtWidgets.QWidget(self.splitter) + self.widget_Resources = QtWidgets.QWidget(parent=self.splitter) self.widget_Resources.setObjectName("widget_Resources") self.gridLayout_3 = QtWidgets.QGridLayout(self.widget_Resources) self.gridLayout_3.setContentsMargins(0, 0, 0, 0) self.gridLayout_3.setObjectName("gridLayout_3") - self.stackedWidget_Resources = QtWidgets.QStackedWidget(self.widget_Resources) + self.stackedWidget_Resources = QtWidgets.QStackedWidget(parent=self.widget_Resources) self.stackedWidget_Resources.setObjectName("stackedWidget_Resources") self.page = QtWidgets.QWidget() self.page.setObjectName("page") @@ -75,7 +76,7 @@ def setupUi(self, Form): self.gridLayout_4.setContentsMargins(0, 0, 0, 0) self.gridLayout_4.setSpacing(0) self.gridLayout_4.setObjectName("gridLayout_4") - self.treeWidget_ResourceTree = QtWidgets.QTreeWidget(self.page) + self.treeWidget_ResourceTree = QtWidgets.QTreeWidget(parent=self.page) self.treeWidget_ResourceTree.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.treeWidget_ResourceTree.setObjectName("treeWidget_ResourceTree") self.treeWidget_ResourceTree.headerItem().setText(0, "Item Name") @@ -87,7 +88,7 @@ def setupUi(self, Form): self.gridLayout_5.setContentsMargins(0, 0, 0, 0) self.gridLayout_5.setSpacing(0) self.gridLayout_5.setObjectName("gridLayout_5") - self.tableWidget_ResourceTable = QtWidgets.QTableWidget(self.page_2) + self.tableWidget_ResourceTable = QtWidgets.QTableWidget(parent=self.page_2) self.tableWidget_ResourceTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_ResourceTable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_ResourceTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -109,31 +110,31 @@ def setupUi(self, Form): self.horizontalLayout.setObjectName("horizontalLayout") self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") - self.label_4 = QtWidgets.QLabel(self.widget_Resources) + self.label_4 = QtWidgets.QLabel(parent=self.widget_Resources) self.label_4.setObjectName("label_4") self.verticalLayout_2.addWidget(self.label_4) - self.lineEdit_Search = QtWidgets.QLineEdit(self.widget_Resources) + self.lineEdit_Search = QtWidgets.QLineEdit(parent=self.widget_Resources) self.lineEdit_Search.setObjectName("lineEdit_Search") self.verticalLayout_2.addWidget(self.lineEdit_Search) self.horizontalLayout.addLayout(self.verticalLayout_2) self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.label = QtWidgets.QLabel(self.widget_Resources) + self.label = QtWidgets.QLabel(parent=self.widget_Resources) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) - self.comboBox_SourceFile = QtWidgets.QComboBox(self.widget_Resources) + self.comboBox_SourceFile = QtWidgets.QComboBox(parent=self.widget_Resources) self.comboBox_SourceFile.setObjectName("comboBox_SourceFile") self.verticalLayout.addWidget(self.comboBox_SourceFile) self.horizontalLayout.addLayout(self.verticalLayout) self.gridLayout_3.addLayout(self.horizontalLayout, 0, 0, 1, 1) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.label_2 = QtWidgets.QLabel(self.widget_Resources) + self.label_2 = QtWidgets.QLabel(parent=self.widget_Resources) self.label_2.setObjectName("label_2") self.horizontalLayout_3.addWidget(self.label_2) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem1) - self.pushButton_ShowTypeDefs = QtWidgets.QPushButton(self.widget_Resources) + self.pushButton_ShowTypeDefs = QtWidgets.QPushButton(parent=self.widget_Resources) self.pushButton_ShowTypeDefs.setObjectName("pushButton_ShowTypeDefs") self.horizontalLayout_3.addWidget(self.pushButton_ShowTypeDefs) self.gridLayout_3.addLayout(self.horizontalLayout_3, 1, 0, 1, 1) @@ -148,7 +149,6 @@ def retranslateUi(self, Form): Form.setWindowTitle(_translate("Form", "libpince Reference")) self.label_5.setText(_translate("Form", "Search")) self.label_3.setText(_translate("Form", "type_defs(Type Definitions)")) - self.label_FoundCount.setText(_translate("Form", "0/0")) self.treeWidget_ResourceTree.headerItem().setText(1, _translate("Form", "Value")) self.tableWidget_ResourceTable.setSortingEnabled(True) item = self.tableWidget_ResourceTable.horizontalHeaderItem(0) @@ -159,13 +159,3 @@ def retranslateUi(self, Form): self.label.setText(_translate("Form", "Source File")) self.label_2.setText(_translate("Form", "Resources(Mouse-over items to see docstrings)")) self.pushButton_ShowTypeDefs.setText(_translate("Form", "Hide type_defs")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - Form = QtWidgets.QWidget() - ui = Ui_Form() - ui.setupUi(Form) - Form.show() - sys.exit(app.exec()) diff --git a/GUI/LibpinceReferenceWidget.ui b/GUI/LibpinceReferenceWidget.ui index 5c97b3dd..5838b5a0 100644 --- a/GUI/LibpinceReferenceWidget.ui +++ b/GUI/LibpinceReferenceWidget.ui @@ -102,7 +102,7 @@ - 0/0 + 0/0 diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 711e0889..c919d3de 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MainWindow.ui' # -# Created by: PyQt6 UI code generator 6.5.0 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -13,6 +13,7 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(678, 636) + MainWindow.setWindowTitle("PINCE") self.centralwidget = QtWidgets.QWidget(parent=MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) @@ -202,6 +203,7 @@ def setupUi(self, MainWindow): self.lineEdit_Scan.setObjectName("lineEdit_Scan") self.horizontalLayout_7.addWidget(self.lineEdit_Scan) self.label_Between = QtWidgets.QLabel(parent=self.widget_Scan) + self.label_Between.setText("<->") self.label_Between.setObjectName("label_Between") self.horizontalLayout_7.addWidget(self.label_Between) self.lineEdit_Scan2 = QtWidgets.QLineEdit(parent=self.widget_Scan) @@ -270,7 +272,6 @@ def setupUi(self, MainWindow): def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "PINCE")) self.treeWidget_AddressTable.headerItem().setText(0, _translate("MainWindow", "Freeze")) self.treeWidget_AddressTable.headerItem().setToolTip(0, _translate("MainWindow", "Freeze the value")) self.treeWidget_AddressTable.headerItem().setText(1, _translate("MainWindow", "Description")) @@ -303,7 +304,6 @@ def retranslateUi(self, MainWindow): self.radioButton_Bits.setText(_translate("MainWindow", "B&its")) self.radioButton_Decimal.setText(_translate("MainWindow", "&Decimal")) self.checkBox_Hex.setText(_translate("MainWindow", "Hex")) - self.label_Between.setText(_translate("MainWindow", "<->")) self.label.setText(_translate("MainWindow", "Scan Type:")) self.label_2.setText(_translate("MainWindow", "Value Type:")) self.label_ScanScope.setText(_translate("MainWindow", "Scan Scope:")) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 06f46c82..c9349a06 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -11,7 +11,7 @@ - PINCE + PINCE @@ -476,7 +476,7 @@ - <-> + <-> diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 24d9398d..410db446 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MemoryViewerWindow.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -13,30 +13,30 @@ class Ui_MainWindow_MemoryView(object): def setupUi(self, MainWindow_MemoryView): MainWindow_MemoryView.setObjectName("MainWindow_MemoryView") MainWindow_MemoryView.resize(800, 600) - self.centralwidget = QtWidgets.QWidget(MainWindow_MemoryView) + self.centralwidget = QtWidgets.QWidget(parent=MainWindow_MemoryView) self.centralwidget.setObjectName("centralwidget") self.gridLayout_5 = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout_5.setContentsMargins(0, 0, 0, 0) self.gridLayout_5.setSpacing(0) self.gridLayout_5.setObjectName("gridLayout_5") - self.splitter_MainMiddle = QtWidgets.QSplitter(self.centralwidget) + self.splitter_MainMiddle = QtWidgets.QSplitter(parent=self.centralwidget) self.splitter_MainMiddle.setLineWidth(1) self.splitter_MainMiddle.setOrientation(QtCore.Qt.Orientation.Vertical) self.splitter_MainMiddle.setOpaqueResize(True) self.splitter_MainMiddle.setHandleWidth(10) self.splitter_MainMiddle.setChildrenCollapsible(True) self.splitter_MainMiddle.setObjectName("splitter_MainMiddle") - self.splitter_Disassemble_Registers = QtWidgets.QSplitter(self.splitter_MainMiddle) + self.splitter_Disassemble_Registers = QtWidgets.QSplitter(parent=self.splitter_MainMiddle) self.splitter_Disassemble_Registers.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter_Disassemble_Registers.setHandleWidth(10) self.splitter_Disassemble_Registers.setObjectName("splitter_Disassemble_Registers") - self.widget_Disassemble = QtWidgets.QWidget(self.splitter_Disassemble_Registers) + self.widget_Disassemble = QtWidgets.QWidget(parent=self.splitter_Disassemble_Registers) self.widget_Disassemble.setObjectName("widget_Disassemble") self.gridLayout_2 = QtWidgets.QGridLayout(self.widget_Disassemble) self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setSpacing(0) self.gridLayout_2.setObjectName("gridLayout_2") - self.tableWidget_Disassemble = QtWidgets.QTableWidget(self.widget_Disassemble) + self.tableWidget_Disassemble = QtWidgets.QTableWidget(parent=self.widget_Disassemble) font = QtGui.QFont() font.setPointSize(9) self.tableWidget_Disassemble.setFont(font) @@ -66,18 +66,18 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_Disassemble.verticalHeader().setMinimumSectionSize(16) self.tableWidget_Disassemble.verticalHeader().setStretchLastSection(False) self.gridLayout_2.addWidget(self.tableWidget_Disassemble, 0, 0, 1, 1) - self.verticalScrollBar_Disassemble = QtWidgets.QScrollBar(self.widget_Disassemble) + self.verticalScrollBar_Disassemble = QtWidgets.QScrollBar(parent=self.widget_Disassemble) self.verticalScrollBar_Disassemble.setOrientation(QtCore.Qt.Orientation.Vertical) self.verticalScrollBar_Disassemble.setObjectName("verticalScrollBar_Disassemble") self.gridLayout_2.addWidget(self.verticalScrollBar_Disassemble, 0, 1, 1, 1) - self.widget_Registers = QtWidgets.QWidget(self.splitter_Disassemble_Registers) + self.widget_Registers = QtWidgets.QWidget(parent=self.splitter_Disassemble_Registers) self.widget_Registers.setMinimumSize(QtCore.QSize(0, 0)) self.widget_Registers.setObjectName("widget_Registers") self.gridLayout_4 = QtWidgets.QGridLayout(self.widget_Registers) self.gridLayout_4.setContentsMargins(0, 0, 0, 0) self.gridLayout_4.setSpacing(0) self.gridLayout_4.setObjectName("gridLayout_4") - self.scrollArea_Registers = QtWidgets.QScrollArea(self.widget_Registers) + self.scrollArea_Registers = QtWidgets.QScrollArea(parent=self.widget_Registers) self.scrollArea_Registers.setWidgetResizable(True) self.scrollArea_Registers.setObjectName("scrollArea_Registers") self.scrollAreaWidgetContents_Registers = QtWidgets.QWidget() @@ -93,18 +93,18 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_19 = QtWidgets.QVBoxLayout() self.verticalLayout_19.setSpacing(0) self.verticalLayout_19.setObjectName("verticalLayout_19") - self.label_3 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_3 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_3.setFont(font) self.label_3.setObjectName("label_3") self.verticalLayout_19.addWidget(self.label_3) - self.line = QtWidgets.QFrame(self.scrollAreaWidgetContents_Registers) + self.line = QtWidgets.QFrame(parent=self.scrollAreaWidgetContents_Registers) self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line.setObjectName("line") self.verticalLayout_19.addWidget(self.line) - self.stackedWidget = QtWidgets.QStackedWidget(self.scrollAreaWidgetContents_Registers) + self.stackedWidget = QtWidgets.QStackedWidget(parent=self.scrollAreaWidgetContents_Registers) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -128,52 +128,60 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16 = QtWidgets.QVBoxLayout() self.verticalLayout_16.setSpacing(0) self.verticalLayout_16.setObjectName("verticalLayout_16") - self.RAX = QRegisterLabel(self.registers_64) + self.RAX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RAX.setFont(font) + self.RAX.setText("RAX=") self.RAX.setObjectName("RAX") self.verticalLayout_16.addWidget(self.RAX) - self.RBX = QRegisterLabel(self.registers_64) + self.RBX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RBX.setFont(font) + self.RBX.setText("RBX=") self.RBX.setObjectName("RBX") self.verticalLayout_16.addWidget(self.RBX) - self.RCX = QRegisterLabel(self.registers_64) + self.RCX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RCX.setFont(font) + self.RCX.setText("RCX=") self.RCX.setObjectName("RCX") self.verticalLayout_16.addWidget(self.RCX) - self.RDX = QRegisterLabel(self.registers_64) + self.RDX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RDX.setFont(font) + self.RDX.setText("RDX=") self.RDX.setObjectName("RDX") self.verticalLayout_16.addWidget(self.RDX) - self.RSI = QRegisterLabel(self.registers_64) + self.RSI = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RSI.setFont(font) + self.RSI.setText("RSI=") self.RSI.setObjectName("RSI") self.verticalLayout_16.addWidget(self.RSI) - self.RDI = QRegisterLabel(self.registers_64) + self.RDI = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RDI.setFont(font) + self.RDI.setText("RDI=") self.RDI.setObjectName("RDI") self.verticalLayout_16.addWidget(self.RDI) - self.RBP = QRegisterLabel(self.registers_64) + self.RBP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RBP.setFont(font) + self.RBP.setText("RBP=") self.RBP.setObjectName("RBP") self.verticalLayout_16.addWidget(self.RBP) - self.RSP = QRegisterLabel(self.registers_64) + self.RSP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RSP.setFont(font) + self.RSP.setText("RSP=") self.RSP.setObjectName("RSP") self.verticalLayout_16.addWidget(self.RSP) self.horizontalLayout.addLayout(self.verticalLayout_16) @@ -182,52 +190,60 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setSpacing(0) self.verticalLayout_3.setObjectName("verticalLayout_3") - self.R8 = QRegisterLabel(self.registers_64) + self.R8 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R8.setFont(font) + self.R8.setText("R8=") self.R8.setObjectName("R8") self.verticalLayout_3.addWidget(self.R8) - self.R9 = QRegisterLabel(self.registers_64) + self.R9 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R9.setFont(font) + self.R9.setText("R9=") self.R9.setObjectName("R9") self.verticalLayout_3.addWidget(self.R9) - self.R10 = QRegisterLabel(self.registers_64) + self.R10 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R10.setFont(font) + self.R10.setText("R10=") self.R10.setObjectName("R10") self.verticalLayout_3.addWidget(self.R10) - self.R11 = QRegisterLabel(self.registers_64) + self.R11 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R11.setFont(font) + self.R11.setText("R11=") self.R11.setObjectName("R11") self.verticalLayout_3.addWidget(self.R11) - self.R12 = QRegisterLabel(self.registers_64) + self.R12 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R12.setFont(font) + self.R12.setText("R12=") self.R12.setObjectName("R12") self.verticalLayout_3.addWidget(self.R12) - self.R13 = QRegisterLabel(self.registers_64) + self.R13 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R13.setFont(font) + self.R13.setText("R13=") self.R13.setObjectName("R13") self.verticalLayout_3.addWidget(self.R13) - self.R14 = QRegisterLabel(self.registers_64) + self.R14 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R14.setFont(font) + self.R14.setText("R14=") self.R14.setObjectName("R14") self.verticalLayout_3.addWidget(self.R14) - self.R15 = QRegisterLabel(self.registers_64) + self.R15 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.R15.setFont(font) + self.R15.setText("R15=") self.R15.setObjectName("R15") self.verticalLayout_3.addWidget(self.R15) self.horizontalLayout.addLayout(self.verticalLayout_3) @@ -235,10 +251,11 @@ def setupUi(self, MainWindow_MemoryView): self.horizontalLayout_18 = QtWidgets.QHBoxLayout() self.horizontalLayout_18.setSpacing(0) self.horizontalLayout_18.setObjectName("horizontalLayout_18") - self.RIP = QRegisterLabel(self.registers_64) + self.RIP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setPointSize(9) self.RIP.setFont(font) + self.RIP.setText("RIP=") self.RIP.setObjectName("RIP") self.horizontalLayout_18.addWidget(self.RIP) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -263,58 +280,67 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setSpacing(0) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.EAX = QRegisterLabel(self.registers_32) + self.EAX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.EAX.setFont(font) + self.EAX.setText("EAX=") self.EAX.setObjectName("EAX") self.verticalLayout_2.addWidget(self.EAX) - self.EBX = QRegisterLabel(self.registers_32) + self.EBX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.EBX.setFont(font) + self.EBX.setText("EBX=") self.EBX.setObjectName("EBX") self.verticalLayout_2.addWidget(self.EBX) - self.ECX = QRegisterLabel(self.registers_32) + self.ECX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.ECX.setFont(font) + self.ECX.setText("ECX=") self.ECX.setObjectName("ECX") self.verticalLayout_2.addWidget(self.ECX) - self.EDX = QRegisterLabel(self.registers_32) + self.EDX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.EDX.setFont(font) + self.EDX.setText("EDX=") self.EDX.setObjectName("EDX") self.verticalLayout_2.addWidget(self.EDX) - self.ESI = QRegisterLabel(self.registers_32) + self.ESI = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.ESI.setFont(font) + self.ESI.setText("ESI=") self.ESI.setObjectName("ESI") self.verticalLayout_2.addWidget(self.ESI) - self.EDI = QRegisterLabel(self.registers_32) + self.EDI = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.EDI.setFont(font) + self.EDI.setText("EDI=") self.EDI.setObjectName("EDI") self.verticalLayout_2.addWidget(self.EDI) - self.EBP = QRegisterLabel(self.registers_32) + self.EBP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.EBP.setFont(font) + self.EBP.setText("EBP=") self.EBP.setObjectName("EBP") self.verticalLayout_2.addWidget(self.EBP) - self.ESP = QRegisterLabel(self.registers_32) + self.ESP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.ESP.setFont(font) + self.ESP.setText("ESP=") self.ESP.setObjectName("ESP") self.verticalLayout_2.addWidget(self.ESP) - self.EIP = QRegisterLabel(self.registers_32) + self.EIP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setPointSize(9) self.EIP.setFont(font) + self.EIP.setText("EIP=") self.EIP.setObjectName("EIP") self.verticalLayout_2.addWidget(self.EIP) self.horizontalLayout_3.addLayout(self.verticalLayout_2) @@ -324,13 +350,13 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_6.addLayout(self.verticalLayout_14, 0, 0, 1, 1) self.stackedWidget.addWidget(self.registers_32) self.verticalLayout_19.addWidget(self.stackedWidget) - self.label_29 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_29 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_29.setFont(font) self.label_29.setObjectName("label_29") self.verticalLayout_19.addWidget(self.label_29) - self.line_2 = QtWidgets.QFrame(self.scrollAreaWidgetContents_Registers) + self.line_2 = QtWidgets.QFrame(parent=self.scrollAreaWidgetContents_Registers) self.line_2.setFrameShape(QtWidgets.QFrame.Shape.HLine) self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_2.setObjectName("line_2") @@ -341,157 +367,175 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_5 = QtWidgets.QVBoxLayout() self.verticalLayout_5.setSpacing(0) self.verticalLayout_5.setObjectName("verticalLayout_5") - self.label_31 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_31 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_31.setFont(font) + self.label_31.setText("CF") self.label_31.setObjectName("label_31") self.verticalLayout_5.addWidget(self.label_31) - self.CF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.CF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.CF.setFont(font) + self.CF.setText("0") self.CF.setObjectName("CF") self.verticalLayout_5.addWidget(self.CF) self.horizontalLayout_21.addLayout(self.verticalLayout_5) self.verticalLayout_6 = QtWidgets.QVBoxLayout() self.verticalLayout_6.setSpacing(0) self.verticalLayout_6.setObjectName("verticalLayout_6") - self.label_35 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_35 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_35.setFont(font) + self.label_35.setText("PF") self.label_35.setObjectName("label_35") self.verticalLayout_6.addWidget(self.label_35) - self.PF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.PF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.PF.setFont(font) + self.PF.setText("0") self.PF.setObjectName("PF") self.verticalLayout_6.addWidget(self.PF) self.horizontalLayout_21.addLayout(self.verticalLayout_6) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setSpacing(0) self.verticalLayout_7.setObjectName("verticalLayout_7") - self.label_37 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_37 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_37.setFont(font) + self.label_37.setText("AF") self.label_37.setObjectName("label_37") self.verticalLayout_7.addWidget(self.label_37) - self.AF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.AF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.AF.setFont(font) + self.AF.setText("0") self.AF.setObjectName("AF") self.verticalLayout_7.addWidget(self.AF) self.horizontalLayout_21.addLayout(self.verticalLayout_7) self.verticalLayout_8 = QtWidgets.QVBoxLayout() self.verticalLayout_8.setSpacing(0) self.verticalLayout_8.setObjectName("verticalLayout_8") - self.label_39 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_39 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_39.setFont(font) + self.label_39.setText("ZF") self.label_39.setObjectName("label_39") self.verticalLayout_8.addWidget(self.label_39) - self.ZF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.ZF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.ZF.setFont(font) + self.ZF.setText("0") self.ZF.setObjectName("ZF") self.verticalLayout_8.addWidget(self.ZF) self.horizontalLayout_21.addLayout(self.verticalLayout_8) self.verticalLayout_9 = QtWidgets.QVBoxLayout() self.verticalLayout_9.setSpacing(0) self.verticalLayout_9.setObjectName("verticalLayout_9") - self.label_41 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_41 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_41.setFont(font) + self.label_41.setText("SF") self.label_41.setObjectName("label_41") self.verticalLayout_9.addWidget(self.label_41) - self.SF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.SF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.SF.setFont(font) + self.SF.setText("0") self.SF.setObjectName("SF") self.verticalLayout_9.addWidget(self.SF) self.horizontalLayout_21.addLayout(self.verticalLayout_9) self.verticalLayout_10 = QtWidgets.QVBoxLayout() self.verticalLayout_10.setSpacing(0) self.verticalLayout_10.setObjectName("verticalLayout_10") - self.label_43 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_43 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_43.setFont(font) + self.label_43.setText("TF") self.label_43.setObjectName("label_43") self.verticalLayout_10.addWidget(self.label_43) - self.TF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.TF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.TF.setFont(font) + self.TF.setText("0") self.TF.setObjectName("TF") self.verticalLayout_10.addWidget(self.TF) self.horizontalLayout_21.addLayout(self.verticalLayout_10) self.verticalLayout_11 = QtWidgets.QVBoxLayout() self.verticalLayout_11.setSpacing(0) self.verticalLayout_11.setObjectName("verticalLayout_11") - self.label_45 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_45 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_45.setFont(font) + self.label_45.setText("IF") self.label_45.setObjectName("label_45") self.verticalLayout_11.addWidget(self.label_45) - self.IF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.IF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.IF.setFont(font) + self.IF.setText("0") self.IF.setObjectName("IF") self.verticalLayout_11.addWidget(self.IF) self.horizontalLayout_21.addLayout(self.verticalLayout_11) self.verticalLayout_12 = QtWidgets.QVBoxLayout() self.verticalLayout_12.setSpacing(0) self.verticalLayout_12.setObjectName("verticalLayout_12") - self.label_47 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_47 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_47.setFont(font) + self.label_47.setText("DF") self.label_47.setObjectName("label_47") self.verticalLayout_12.addWidget(self.label_47) - self.DF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.DF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.DF.setFont(font) + self.DF.setText("0") self.DF.setObjectName("DF") self.verticalLayout_12.addWidget(self.DF) self.horizontalLayout_21.addLayout(self.verticalLayout_12) self.verticalLayout_13 = QtWidgets.QVBoxLayout() self.verticalLayout_13.setSpacing(0) self.verticalLayout_13.setObjectName("verticalLayout_13") - self.label_49 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_49 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_49.setFont(font) + self.label_49.setText("OF") self.label_49.setObjectName("label_49") self.verticalLayout_13.addWidget(self.label_49) - self.OF = QFlagRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.OF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.OF.setFont(font) + self.OF.setText("0") self.OF.setObjectName("OF") self.verticalLayout_13.addWidget(self.OF) self.horizontalLayout_21.addLayout(self.verticalLayout_13) self.verticalLayout_19.addLayout(self.horizontalLayout_21) spacerItem4 = QtWidgets.QSpacerItem(20, 15, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) self.verticalLayout_19.addItem(spacerItem4) - self.label_30 = QtWidgets.QLabel(self.scrollAreaWidgetContents_Registers) + self.label_30 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.label_30.setFont(font) self.label_30.setObjectName("label_30") self.verticalLayout_19.addWidget(self.label_30) - self.line_3 = QtWidgets.QFrame(self.scrollAreaWidgetContents_Registers) + self.line_3 = QtWidgets.QFrame(parent=self.scrollAreaWidgetContents_Registers) self.line_3.setFrameShape(QtWidgets.QFrame.Shape.HLine) self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_3.setObjectName("line_3") @@ -502,16 +546,18 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_4 = QtWidgets.QVBoxLayout() self.verticalLayout_4.setSpacing(0) self.verticalLayout_4.setObjectName("verticalLayout_4") - self.CS = QRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.CS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.CS.setFont(font) + self.CS.setText("CS=") self.CS.setObjectName("CS") self.verticalLayout_4.addWidget(self.CS) - self.ES = QRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.ES = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.ES.setFont(font) + self.ES.setText("ES=") self.ES.setObjectName("ES") self.verticalLayout_4.addWidget(self.ES) self.horizontalLayout_2.addLayout(self.verticalLayout_4) @@ -520,16 +566,18 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_15 = QtWidgets.QVBoxLayout() self.verticalLayout_15.setSpacing(0) self.verticalLayout_15.setObjectName("verticalLayout_15") - self.SS = QRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.SS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.SS.setFont(font) + self.SS.setText("SS=") self.SS.setObjectName("SS") self.verticalLayout_15.addWidget(self.SS) - self.GS = QRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.GS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.GS.setFont(font) + self.GS.setText("GS=") self.GS.setObjectName("GS") self.verticalLayout_15.addWidget(self.GS) self.horizontalLayout_2.addLayout(self.verticalLayout_15) @@ -538,21 +586,23 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_18 = QtWidgets.QVBoxLayout() self.verticalLayout_18.setSpacing(0) self.verticalLayout_18.setObjectName("verticalLayout_18") - self.DS = QRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.DS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.DS.setFont(font) + self.DS.setText("DS=") self.DS.setObjectName("DS") self.verticalLayout_18.addWidget(self.DS) - self.FS = QRegisterLabel(self.scrollAreaWidgetContents_Registers) + self.FS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.FS.setFont(font) + self.FS.setText("FS=") self.FS.setObjectName("FS") self.verticalLayout_18.addWidget(self.FS) self.horizontalLayout_2.addLayout(self.verticalLayout_18) self.verticalLayout_19.addLayout(self.horizontalLayout_2) - self.pushButton_ShowFloatRegisters = QtWidgets.QPushButton(self.scrollAreaWidgetContents_Registers) + self.pushButton_ShowFloatRegisters = QtWidgets.QPushButton(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setPointSize(9) self.pushButton_ShowFloatRegisters.setFont(font) @@ -566,18 +616,18 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_8.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) self.scrollArea_Registers.setWidget(self.scrollAreaWidgetContents_Registers) self.gridLayout_4.addWidget(self.scrollArea_Registers, 0, 0, 1, 1) - self.splitter_HexView_StackView = QtWidgets.QSplitter(self.splitter_MainMiddle) + self.splitter_HexView_StackView = QtWidgets.QSplitter(parent=self.splitter_MainMiddle) self.splitter_HexView_StackView.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter_HexView_StackView.setHandleWidth(10) self.splitter_HexView_StackView.setObjectName("splitter_HexView_StackView") - self.widget_HexView = QtWidgets.QWidget(self.splitter_HexView_StackView) + self.widget_HexView = QtWidgets.QWidget(parent=self.splitter_HexView_StackView) self.widget_HexView.setObjectName("widget_HexView") self.gridLayout = QtWidgets.QGridLayout(self.widget_HexView) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setHorizontalSpacing(0) self.gridLayout.setVerticalSpacing(4) self.gridLayout.setObjectName("gridLayout") - self.scrollArea_Hex = QtWidgets.QScrollArea(self.widget_HexView) + self.scrollArea_Hex = QtWidgets.QScrollArea(parent=self.widget_HexView) self.scrollArea_Hex.setWidgetResizable(True) self.scrollArea_Hex.setObjectName("scrollArea_Hex") self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() @@ -590,7 +640,7 @@ def setupUi(self, MainWindow_MemoryView): self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setSpacing(0) self.horizontalLayout_5.setObjectName("horizontalLayout_5") - self.tableWidget_HexView_Address = QtWidgets.QTableWidget(self.scrollAreaWidgetContents_2) + self.tableWidget_HexView_Address = QtWidgets.QTableWidget(parent=self.scrollAreaWidgetContents_2) self.tableWidget_HexView_Address.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_HexView_Address.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_HexView_Address.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -603,32 +653,32 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_HexView_Address.horizontalHeader().setVisible(False) self.tableWidget_HexView_Address.verticalHeader().setVisible(False) self.horizontalLayout_5.addWidget(self.tableWidget_HexView_Address) - self.line_5 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) + self.line_5 = QtWidgets.QFrame(parent=self.scrollAreaWidgetContents_2) self.line_5.setFrameShape(QtWidgets.QFrame.Shape.VLine) self.line_5.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_5.setObjectName("line_5") self.horizontalLayout_5.addWidget(self.line_5) - self.tableView_HexView_Hex = QHexView(self.scrollAreaWidgetContents_2) + self.tableView_HexView_Hex = QHexView(parent=self.scrollAreaWidgetContents_2) self.tableView_HexView_Hex.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) self.tableView_HexView_Hex.setObjectName("tableView_HexView_Hex") self.horizontalLayout_5.addWidget(self.tableView_HexView_Hex) - self.line_4 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) + self.line_4 = QtWidgets.QFrame(parent=self.scrollAreaWidgetContents_2) self.line_4.setFrameShape(QtWidgets.QFrame.Shape.VLine) self.line_4.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_4.setObjectName("line_4") self.horizontalLayout_5.addWidget(self.line_4) - self.tableView_HexView_Ascii = QAsciiView(self.scrollAreaWidgetContents_2) + self.tableView_HexView_Ascii = QAsciiView(parent=self.scrollAreaWidgetContents_2) self.tableView_HexView_Ascii.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) self.tableView_HexView_Ascii.setObjectName("tableView_HexView_Ascii") self.horizontalLayout_5.addWidget(self.tableView_HexView_Ascii) spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_5.addItem(spacerItem9) self.gridLayout_11.addLayout(self.horizontalLayout_5, 2, 0, 1, 1) - self.label_HexView_Information = QtWidgets.QLabel(self.scrollAreaWidgetContents_2) + self.label_HexView_Information = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_2) self.label_HexView_Information.setText("") self.label_HexView_Information.setObjectName("label_HexView_Information") self.gridLayout_11.addWidget(self.label_HexView_Information, 0, 0, 1, 1) - self.line_6 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) + self.line_6 = QtWidgets.QFrame(parent=self.scrollAreaWidgetContents_2) self.line_6.setFrameShape(QtWidgets.QFrame.Shape.HLine) self.line_6.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_6.setObjectName("line_6") @@ -637,17 +687,17 @@ def setupUi(self, MainWindow_MemoryView): self.line_6.raise_() self.scrollArea_Hex.setWidget(self.scrollAreaWidgetContents_2) self.gridLayout.addWidget(self.scrollArea_Hex, 0, 0, 1, 1) - self.verticalScrollBar_HexView = QtWidgets.QScrollBar(self.widget_HexView) + self.verticalScrollBar_HexView = QtWidgets.QScrollBar(parent=self.widget_HexView) self.verticalScrollBar_HexView.setOrientation(QtCore.Qt.Orientation.Vertical) self.verticalScrollBar_HexView.setObjectName("verticalScrollBar_HexView") self.gridLayout.addWidget(self.verticalScrollBar_HexView, 0, 1, 1, 1) - self.widget_StackView = QtWidgets.QWidget(self.splitter_HexView_StackView) + self.widget_StackView = QtWidgets.QWidget(parent=self.splitter_HexView_StackView) self.widget_StackView.setObjectName("widget_StackView") self.gridLayout_3 = QtWidgets.QGridLayout(self.widget_StackView) self.gridLayout_3.setContentsMargins(0, 0, 0, 0) self.gridLayout_3.setSpacing(0) self.gridLayout_3.setObjectName("gridLayout_3") - self.stackedWidget_StackScreens = QtWidgets.QStackedWidget(self.widget_StackView) + self.stackedWidget_StackScreens = QtWidgets.QStackedWidget(parent=self.widget_StackView) self.stackedWidget_StackScreens.setObjectName("stackedWidget_StackScreens") self.StackTrace = QtWidgets.QWidget() self.StackTrace.setObjectName("StackTrace") @@ -655,7 +705,7 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_9.setContentsMargins(0, 0, 0, 0) self.gridLayout_9.setSpacing(0) self.gridLayout_9.setObjectName("gridLayout_9") - self.tableWidget_StackTrace = QtWidgets.QTableWidget(self.StackTrace) + self.tableWidget_StackTrace = QtWidgets.QTableWidget(parent=self.StackTrace) font = QtGui.QFont() font.setPointSize(9) self.tableWidget_StackTrace.setFont(font) @@ -682,7 +732,7 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_10.setContentsMargins(0, 0, 0, 0) self.gridLayout_10.setSpacing(0) self.gridLayout_10.setObjectName("gridLayout_10") - self.tableWidget_Stack = QtWidgets.QTableWidget(self.Stack) + self.tableWidget_Stack = QtWidgets.QTableWidget(parent=self.Stack) font = QtGui.QFont() font.setPointSize(9) self.tableWidget_Stack.setFont(font) @@ -707,68 +757,68 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_3.addWidget(self.stackedWidget_StackScreens, 0, 0, 1, 1) self.gridLayout_5.addWidget(self.splitter_MainMiddle, 0, 0, 1, 1) MainWindow_MemoryView.setCentralWidget(self.centralwidget) - self.menubar = QtWidgets.QMenuBar(MainWindow_MemoryView) + self.menubar = QtWidgets.QMenuBar(parent=MainWindow_MemoryView) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) self.menubar.setObjectName("menubar") - self.menuView = QtWidgets.QMenu(self.menubar) + self.menuView = QtWidgets.QMenu(parent=self.menubar) self.menuView.setObjectName("menuView") - self.menuDebug = QtWidgets.QMenu(self.menubar) + self.menuDebug = QtWidgets.QMenu(parent=self.menubar) self.menuDebug.setObjectName("menuDebug") - self.menuTools = QtWidgets.QMenu(self.menubar) + self.menuTools = QtWidgets.QMenu(parent=self.menubar) self.menuTools.setObjectName("menuTools") - self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile = QtWidgets.QMenu(parent=self.menubar) self.menuFile.setObjectName("menuFile") - self.menuHelp = QtWidgets.QMenu(self.menubar) + self.menuHelp = QtWidgets.QMenu(parent=self.menubar) self.menuHelp.setObjectName("menuHelp") MainWindow_MemoryView.setMenuBar(self.menubar) - self.statusbar = QtWidgets.QStatusBar(MainWindow_MemoryView) + self.statusbar = QtWidgets.QStatusBar(parent=MainWindow_MemoryView) self.statusbar.setObjectName("statusbar") MainWindow_MemoryView.setStatusBar(self.statusbar) - self.actionBookmarks = QtGui.QAction(MainWindow_MemoryView) + self.actionBookmarks = QtGui.QAction(parent=MainWindow_MemoryView) self.actionBookmarks.setObjectName("actionBookmarks") - self.actionStackTrace_Info = QtGui.QAction(MainWindow_MemoryView) + self.actionStackTrace_Info = QtGui.QAction(parent=MainWindow_MemoryView) self.actionStackTrace_Info.setObjectName("actionStackTrace_Info") - self.actionInject_so_file = QtGui.QAction(MainWindow_MemoryView) + self.actionInject_so_file = QtGui.QAction(parent=MainWindow_MemoryView) self.actionInject_so_file.setObjectName("actionInject_so_file") - self.actionRun = QtGui.QAction(MainWindow_MemoryView) + self.actionRun = QtGui.QAction(parent=MainWindow_MemoryView) self.actionRun.setObjectName("actionRun") - self.actionBreak = QtGui.QAction(MainWindow_MemoryView) + self.actionBreak = QtGui.QAction(parent=MainWindow_MemoryView) self.actionBreak.setObjectName("actionBreak") - self.actionStep = QtGui.QAction(MainWindow_MemoryView) + self.actionStep = QtGui.QAction(parent=MainWindow_MemoryView) self.actionStep.setObjectName("actionStep") - self.actionStep_Over = QtGui.QAction(MainWindow_MemoryView) + self.actionStep_Over = QtGui.QAction(parent=MainWindow_MemoryView) self.actionStep_Over.setObjectName("actionStep_Over") - self.actionExecute_Till_Return = QtGui.QAction(MainWindow_MemoryView) + self.actionExecute_Till_Return = QtGui.QAction(parent=MainWindow_MemoryView) self.actionExecute_Till_Return.setObjectName("actionExecute_Till_Return") - self.actionToggle_Breakpoint = QtGui.QAction(MainWindow_MemoryView) + self.actionToggle_Breakpoint = QtGui.QAction(parent=MainWindow_MemoryView) self.actionToggle_Breakpoint.setObjectName("actionToggle_Breakpoint") - self.actionBreakpoints = QtGui.QAction(MainWindow_MemoryView) + self.actionBreakpoints = QtGui.QAction(parent=MainWindow_MemoryView) self.actionBreakpoints.setObjectName("actionBreakpoints") - self.actionFunctions = QtGui.QAction(MainWindow_MemoryView) + self.actionFunctions = QtGui.QAction(parent=MainWindow_MemoryView) self.actionFunctions.setObjectName("actionFunctions") - self.actionSet_Address = QtGui.QAction(MainWindow_MemoryView) + self.actionSet_Address = QtGui.QAction(parent=MainWindow_MemoryView) self.actionSet_Address.setObjectName("actionSet_Address") - self.actionCall_Function = QtGui.QAction(MainWindow_MemoryView) + self.actionCall_Function = QtGui.QAction(parent=MainWindow_MemoryView) self.actionCall_Function.setObjectName("actionCall_Function") - self.actionLoad_Trace = QtGui.QAction(MainWindow_MemoryView) + self.actionLoad_Trace = QtGui.QAction(parent=MainWindow_MemoryView) self.actionLoad_Trace.setObjectName("actionLoad_Trace") - self.actionlibpince = QtGui.QAction(MainWindow_MemoryView) + self.actionlibpince = QtGui.QAction(parent=MainWindow_MemoryView) self.actionlibpince.setObjectName("actionlibpince") - self.actionGDB_Log_File = QtGui.QAction(MainWindow_MemoryView) + self.actionGDB_Log_File = QtGui.QAction(parent=MainWindow_MemoryView) self.actionGDB_Log_File.setObjectName("actionGDB_Log_File") - self.actionSearch_Opcode = QtGui.QAction(MainWindow_MemoryView) + self.actionSearch_Opcode = QtGui.QAction(parent=MainWindow_MemoryView) self.actionSearch_Opcode.setObjectName("actionSearch_Opcode") - self.actionMemory_Regions = QtGui.QAction(MainWindow_MemoryView) + self.actionMemory_Regions = QtGui.QAction(parent=MainWindow_MemoryView) self.actionMemory_Regions.setObjectName("actionMemory_Regions") - self.actionDissect_Code = QtGui.QAction(MainWindow_MemoryView) + self.actionDissect_Code = QtGui.QAction(parent=MainWindow_MemoryView) self.actionDissect_Code.setObjectName("actionDissect_Code") - self.actionReferenced_Strings = QtGui.QAction(MainWindow_MemoryView) + self.actionReferenced_Strings = QtGui.QAction(parent=MainWindow_MemoryView) self.actionReferenced_Strings.setObjectName("actionReferenced_Strings") - self.actionReferenced_Calls = QtGui.QAction(MainWindow_MemoryView) + self.actionReferenced_Calls = QtGui.QAction(parent=MainWindow_MemoryView) self.actionReferenced_Calls.setObjectName("actionReferenced_Calls") - self.actionToggle_Attach = QtGui.QAction(MainWindow_MemoryView) + self.actionToggle_Attach = QtGui.QAction(parent=MainWindow_MemoryView) self.actionToggle_Attach.setObjectName("actionToggle_Attach") - self.actionRestore_Instructions = QtGui.QAction(MainWindow_MemoryView) + self.actionRestore_Instructions = QtGui.QAction(parent=MainWindow_MemoryView) self.actionRestore_Instructions.setObjectName("actionRestore_Instructions") self.menuView.addAction(self.actionBookmarks) self.menuView.addAction(self.actionStackTrace_Info) @@ -819,58 +869,8 @@ def retranslateUi(self, MainWindow_MemoryView): item = self.tableWidget_Disassemble.horizontalHeaderItem(3) item.setText(_translate("MainWindow_MemoryView", "Comment")) self.label_3.setText(_translate("MainWindow_MemoryView", "Registers")) - self.RAX.setText(_translate("MainWindow_MemoryView", "RAX=")) - self.RBX.setText(_translate("MainWindow_MemoryView", "RBX=")) - self.RCX.setText(_translate("MainWindow_MemoryView", "RCX=")) - self.RDX.setText(_translate("MainWindow_MemoryView", "RDX=")) - self.RSI.setText(_translate("MainWindow_MemoryView", "RSI=")) - self.RDI.setText(_translate("MainWindow_MemoryView", "RDI=")) - self.RBP.setText(_translate("MainWindow_MemoryView", "RBP=")) - self.RSP.setText(_translate("MainWindow_MemoryView", "RSP=")) - self.R8.setText(_translate("MainWindow_MemoryView", "R8=")) - self.R9.setText(_translate("MainWindow_MemoryView", "R9=")) - self.R10.setText(_translate("MainWindow_MemoryView", "R10=")) - self.R11.setText(_translate("MainWindow_MemoryView", "R11=")) - self.R12.setText(_translate("MainWindow_MemoryView", "R12=")) - self.R13.setText(_translate("MainWindow_MemoryView", "R13=")) - self.R14.setText(_translate("MainWindow_MemoryView", "R14=")) - self.R15.setText(_translate("MainWindow_MemoryView", "R15=")) - self.RIP.setText(_translate("MainWindow_MemoryView", "RIP=")) - self.EAX.setText(_translate("MainWindow_MemoryView", "EAX=")) - self.EBX.setText(_translate("MainWindow_MemoryView", "EBX=")) - self.ECX.setText(_translate("MainWindow_MemoryView", "ECX=")) - self.EDX.setText(_translate("MainWindow_MemoryView", "EDX=")) - self.ESI.setText(_translate("MainWindow_MemoryView", "ESI=")) - self.EDI.setText(_translate("MainWindow_MemoryView", "EDI=")) - self.EBP.setText(_translate("MainWindow_MemoryView", "EBP=")) - self.ESP.setText(_translate("MainWindow_MemoryView", "ESP=")) - self.EIP.setText(_translate("MainWindow_MemoryView", "EIP=")) self.label_29.setText(_translate("MainWindow_MemoryView", "Flags")) - self.label_31.setText(_translate("MainWindow_MemoryView", "CF")) - self.CF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_35.setText(_translate("MainWindow_MemoryView", "PF")) - self.PF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_37.setText(_translate("MainWindow_MemoryView", "AF")) - self.AF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_39.setText(_translate("MainWindow_MemoryView", "ZF")) - self.ZF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_41.setText(_translate("MainWindow_MemoryView", "SF")) - self.SF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_43.setText(_translate("MainWindow_MemoryView", "TF")) - self.TF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_45.setText(_translate("MainWindow_MemoryView", "IF")) - self.IF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_47.setText(_translate("MainWindow_MemoryView", "DF")) - self.DF.setText(_translate("MainWindow_MemoryView", "0")) - self.label_49.setText(_translate("MainWindow_MemoryView", "OF")) - self.OF.setText(_translate("MainWindow_MemoryView", "0")) self.label_30.setText(_translate("MainWindow_MemoryView", "Segment Registers")) - self.CS.setText(_translate("MainWindow_MemoryView", "CS=")) - self.ES.setText(_translate("MainWindow_MemoryView", "ES=")) - self.SS.setText(_translate("MainWindow_MemoryView", "SS=")) - self.GS.setText(_translate("MainWindow_MemoryView", "GS=")) - self.DS.setText(_translate("MainWindow_MemoryView", "DS=")) - self.FS.setText(_translate("MainWindow_MemoryView", "FS=")) self.pushButton_ShowFloatRegisters.setText(_translate("MainWindow_MemoryView", "Show Float Registers")) item = self.tableWidget_HexView_Address.horizontalHeaderItem(0) item.setText(_translate("MainWindow_MemoryView", "Address")) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 79c7620f..1334b6ce 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -296,7 +296,7 @@ - RAX= + RAX= @@ -308,7 +308,7 @@ - RBX= + RBX= @@ -320,7 +320,7 @@ - RCX= + RCX= @@ -332,7 +332,7 @@ - RDX= + RDX= @@ -344,7 +344,7 @@ - RSI= + RSI= @@ -356,7 +356,7 @@ - RDI= + RDI= @@ -368,7 +368,7 @@ - RBP= + RBP= @@ -380,7 +380,7 @@ - RSP= + RSP= @@ -412,7 +412,7 @@ - R8= + R8= @@ -424,7 +424,7 @@ - R9= + R9= @@ -436,7 +436,7 @@ - R10= + R10= @@ -448,7 +448,7 @@ - R11= + R11= @@ -460,7 +460,7 @@ - R12= + R12= @@ -472,7 +472,7 @@ - R13= + R13= @@ -484,7 +484,7 @@ - R14= + R14= @@ -496,7 +496,7 @@ - R15= + R15= @@ -517,7 +517,7 @@ - RIP= + RIP= @@ -593,7 +593,7 @@ - EAX= + EAX= @@ -605,7 +605,7 @@ - EBX= + EBX= @@ -617,7 +617,7 @@ - ECX= + ECX= @@ -629,7 +629,7 @@ - EDX= + EDX= @@ -641,7 +641,7 @@ - ESI= + ESI= @@ -653,7 +653,7 @@ - EDI= + EDI= @@ -665,7 +665,7 @@ - EBP= + EBP= @@ -677,7 +677,7 @@ - ESP= + ESP= @@ -689,7 +689,7 @@ - EIP= + EIP= @@ -753,7 +753,7 @@ - CF + CF @@ -765,7 +765,7 @@ - 0 + 0 @@ -784,7 +784,7 @@ - PF + PF @@ -796,7 +796,7 @@ - 0 + 0 @@ -815,7 +815,7 @@ - AF + AF @@ -827,7 +827,7 @@ - 0 + 0 @@ -846,7 +846,7 @@ - ZF + ZF @@ -858,7 +858,7 @@ - 0 + 0 @@ -877,7 +877,7 @@ - SF + SF @@ -889,7 +889,7 @@ - 0 + 0 @@ -908,7 +908,7 @@ - TF + TF @@ -920,7 +920,7 @@ - 0 + 0 @@ -939,7 +939,7 @@ - IF + IF @@ -951,7 +951,7 @@ - 0 + 0 @@ -970,7 +970,7 @@ - DF + DF @@ -982,7 +982,7 @@ - 0 + 0 @@ -1001,7 +1001,7 @@ - OF + OF @@ -1013,7 +1013,7 @@ - 0 + 0 @@ -1074,7 +1074,7 @@ - CS= + CS= @@ -1086,7 +1086,7 @@ - ES= + ES= @@ -1118,7 +1118,7 @@ - SS= + SS= @@ -1130,7 +1130,7 @@ - GS= + GS= @@ -1162,7 +1162,7 @@ - DS= + DS= @@ -1174,7 +1174,7 @@ - FS= + FS= diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 63503f24..f6d166a1 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SettingsDialog.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -19,7 +19,7 @@ def setupUi(self, Dialog): self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.listWidget_Options = QtWidgets.QListWidget(Dialog) + self.listWidget_Options = QtWidgets.QListWidget(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -38,7 +38,7 @@ def setupUi(self, Dialog): item = QtWidgets.QListWidgetItem() self.listWidget_Options.addItem(item) self.horizontalLayout_2.addWidget(self.listWidget_Options) - self.stackedWidget = QtWidgets.QStackedWidget(Dialog) + self.stackedWidget = QtWidgets.QStackedWidget(parent=Dialog) self.stackedWidget.setMinimumSize(QtCore.QSize(500, 500)) self.stackedWidget.setObjectName("stackedWidget") self.page = QtWidgets.QWidget() @@ -53,33 +53,35 @@ def setupUi(self, Dialog): self.verticalLayout_3.setObjectName("verticalLayout_3") self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") - self.checkBox_AutoUpdateAddressTable = QtWidgets.QCheckBox(self.page) + self.checkBox_AutoUpdateAddressTable = QtWidgets.QCheckBox(parent=self.page) self.checkBox_AutoUpdateAddressTable.setChecked(True) self.checkBox_AutoUpdateAddressTable.setObjectName("checkBox_AutoUpdateAddressTable") self.verticalLayout_2.addWidget(self.checkBox_AutoUpdateAddressTable) self.verticalLayout_3.addLayout(self.verticalLayout_2) - self.QWidget_UpdateInterval = QtWidgets.QWidget(self.page) + self.QWidget_UpdateInterval = QtWidgets.QWidget(parent=self.page) self.QWidget_UpdateInterval.setObjectName("QWidget_UpdateInterval") self.horizontalLayout_UpdateInterval = QtWidgets.QHBoxLayout(self.QWidget_UpdateInterval) self.horizontalLayout_UpdateInterval.setContentsMargins(-1, 0, -1, -1) self.horizontalLayout_UpdateInterval.setObjectName("horizontalLayout_UpdateInterval") - self.label = QtWidgets.QLabel(self.QWidget_UpdateInterval) + self.label = QtWidgets.QLabel(parent=self.QWidget_UpdateInterval) self.label.setMinimumSize(QtCore.QSize(102, 0)) self.label.setObjectName("label") self.horizontalLayout_UpdateInterval.addWidget(self.label) - self.lineEdit_UpdateInterval = QtWidgets.QLineEdit(self.QWidget_UpdateInterval) + self.lineEdit_UpdateInterval = QtWidgets.QLineEdit(parent=self.QWidget_UpdateInterval) + self.lineEdit_UpdateInterval.setText("500") self.lineEdit_UpdateInterval.setObjectName("lineEdit_UpdateInterval") self.horizontalLayout_UpdateInterval.addWidget(self.lineEdit_UpdateInterval) - self.label_2 = QtWidgets.QLabel(self.QWidget_UpdateInterval) + self.label_2 = QtWidgets.QLabel(parent=self.QWidget_UpdateInterval) + self.label_2.setText("ms") self.label_2.setObjectName("label_2") self.horizontalLayout_UpdateInterval.addWidget(self.label_2) self.verticalLayout_3.addWidget(self.QWidget_UpdateInterval) - self.LockInterval = QtWidgets.QWidget(self.page) + self.LockInterval = QtWidgets.QWidget(parent=self.page) self.LockInterval.setObjectName("LockInterval") self.horizontalLayout_14 = QtWidgets.QHBoxLayout(self.LockInterval) self.horizontalLayout_14.setContentsMargins(-1, 0, -1, -1) self.horizontalLayout_14.setObjectName("horizontalLayout_14") - self.label_12 = QtWidgets.QLabel(self.LockInterval) + self.label_12 = QtWidgets.QLabel(parent=self.LockInterval) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -89,16 +91,18 @@ def setupUi(self, Dialog): self.label_12.setBaseSize(QtCore.QSize(0, 0)) self.label_12.setObjectName("label_12") self.horizontalLayout_14.addWidget(self.label_12) - self.lineEdit_FreezeInterval = QtWidgets.QLineEdit(self.LockInterval) + self.lineEdit_FreezeInterval = QtWidgets.QLineEdit(parent=self.LockInterval) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lineEdit_FreezeInterval.sizePolicy().hasHeightForWidth()) self.lineEdit_FreezeInterval.setSizePolicy(sizePolicy) self.lineEdit_FreezeInterval.setBaseSize(QtCore.QSize(20, 0)) + self.lineEdit_FreezeInterval.setText("100") self.lineEdit_FreezeInterval.setObjectName("lineEdit_FreezeInterval") self.horizontalLayout_14.addWidget(self.lineEdit_FreezeInterval) - self.label_10 = QtWidgets.QLabel(self.LockInterval) + self.label_10 = QtWidgets.QLabel(parent=self.LockInterval) + self.label_10.setText("ms") self.label_10.setObjectName("label_10") self.horizontalLayout_14.addWidget(self.label_10) self.verticalLayout_3.addWidget(self.LockInterval) @@ -106,24 +110,24 @@ def setupUi(self, Dialog): spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_7.addItem(spacerItem) self.verticalLayout_5.addLayout(self.horizontalLayout_7) - self.checkBox_MessageBoxOnException = QtWidgets.QCheckBox(self.page) + self.checkBox_MessageBoxOnException = QtWidgets.QCheckBox(parent=self.page) self.checkBox_MessageBoxOnException.setChecked(True) self.checkBox_MessageBoxOnException.setObjectName("checkBox_MessageBoxOnException") self.verticalLayout_5.addWidget(self.checkBox_MessageBoxOnException) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.label_8 = QtWidgets.QLabel(self.page) + self.label_8 = QtWidgets.QLabel(parent=self.page) self.label_8.setObjectName("label_8") self.horizontalLayout_3.addWidget(self.label_8) - self.checkBox_OutputModeAsync = QtWidgets.QCheckBox(self.page) + self.checkBox_OutputModeAsync = QtWidgets.QCheckBox(parent=self.page) self.checkBox_OutputModeAsync.setChecked(True) self.checkBox_OutputModeAsync.setObjectName("checkBox_OutputModeAsync") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeAsync) - self.checkBox_OutputModeCommand = QtWidgets.QCheckBox(self.page) + self.checkBox_OutputModeCommand = QtWidgets.QCheckBox(parent=self.page) self.checkBox_OutputModeCommand.setChecked(True) self.checkBox_OutputModeCommand.setObjectName("checkBox_OutputModeCommand") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeCommand) - self.checkBox_OutputModeCommandInfo = QtWidgets.QCheckBox(self.page) + self.checkBox_OutputModeCommandInfo = QtWidgets.QCheckBox(parent=self.page) self.checkBox_OutputModeCommandInfo.setChecked(True) self.checkBox_OutputModeCommandInfo.setObjectName("checkBox_OutputModeCommandInfo") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeCommandInfo) @@ -133,22 +137,22 @@ def setupUi(self, Dialog): self.horizontalLayout_12 = QtWidgets.QHBoxLayout() self.horizontalLayout_12.setContentsMargins(-1, 0, -1, -1) self.horizontalLayout_12.setObjectName("horizontalLayout_12") - self.label_9 = QtWidgets.QLabel(self.page) + self.label_9 = QtWidgets.QLabel(parent=self.page) self.label_9.setObjectName("label_9") self.horizontalLayout_12.addWidget(self.label_9) - self.lineEdit_AutoAttachList = QtWidgets.QLineEdit(self.page) + self.lineEdit_AutoAttachList = QtWidgets.QLineEdit(parent=self.page) self.lineEdit_AutoAttachList.setObjectName("lineEdit_AutoAttachList") self.horizontalLayout_12.addWidget(self.lineEdit_AutoAttachList) - self.checkBox_AutoAttachRegex = QtWidgets.QCheckBox(self.page) + self.checkBox_AutoAttachRegex = QtWidgets.QCheckBox(parent=self.page) self.checkBox_AutoAttachRegex.setObjectName("checkBox_AutoAttachRegex") self.horizontalLayout_12.addWidget(self.checkBox_AutoAttachRegex) self.verticalLayout_5.addLayout(self.horizontalLayout_12) self.horizontalLayout_15 = QtWidgets.QHBoxLayout() self.horizontalLayout_15.setObjectName("horizontalLayout_15") - self.label_11 = QtWidgets.QLabel(self.page) + self.label_11 = QtWidgets.QLabel(parent=self.page) self.label_11.setObjectName("label_11") self.horizontalLayout_15.addWidget(self.label_11) - self.comboBox_Logo = QtWidgets.QComboBox(self.page) + self.comboBox_Logo = QtWidgets.QComboBox(parent=self.page) self.comboBox_Logo.setObjectName("comboBox_Logo") self.horizontalLayout_15.addWidget(self.comboBox_Logo) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -166,10 +170,10 @@ def setupUi(self, Dialog): self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.verticalLayout_4 = QtWidgets.QVBoxLayout() self.verticalLayout_4.setObjectName("verticalLayout_4") - self.label_3 = QtWidgets.QLabel(self.page_2) + self.label_3 = QtWidgets.QLabel(parent=self.page_2) self.label_3.setObjectName("label_3") self.verticalLayout_4.addWidget(self.label_3) - self.listWidget_Functions = QtWidgets.QListWidget(self.page_2) + self.listWidget_Functions = QtWidgets.QListWidget(parent=self.page_2) self.listWidget_Functions.setObjectName("listWidget_Functions") self.verticalLayout_4.addWidget(self.listWidget_Functions) self.horizontalLayout_5.addLayout(self.verticalLayout_4) @@ -177,7 +181,7 @@ def setupUi(self, Dialog): self.verticalLayout_6.setObjectName("verticalLayout_6") self.verticalLayout_Hotkey = QtWidgets.QVBoxLayout() self.verticalLayout_Hotkey.setObjectName("verticalLayout_Hotkey") - self.label_4 = QtWidgets.QLabel(self.page_2) + self.label_4 = QtWidgets.QLabel(parent=self.page_2) self.label_4.setObjectName("label_4") self.verticalLayout_Hotkey.addWidget(self.label_4) self.verticalLayout_6.addLayout(self.verticalLayout_Hotkey) @@ -185,7 +189,7 @@ def setupUi(self, Dialog): self.horizontalLayout_4.setObjectName("horizontalLayout_4") spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_4.addItem(spacerItem4) - self.pushButton_ClearHotkey = QtWidgets.QPushButton(self.page_2) + self.pushButton_ClearHotkey = QtWidgets.QPushButton(parent=self.page_2) self.pushButton_ClearHotkey.setObjectName("pushButton_ClearHotkey") self.horizontalLayout_4.addWidget(self.pushButton_ClearHotkey) self.verticalLayout_6.addLayout(self.horizontalLayout_4) @@ -204,7 +208,7 @@ def setupUi(self, Dialog): self.horizontalLayout_8.setObjectName("horizontalLayout_8") self.verticalLayout_8 = QtWidgets.QVBoxLayout() self.verticalLayout_8.setObjectName("verticalLayout_8") - self.label_5 = QtWidgets.QLabel(self.page_3) + self.label_5 = QtWidgets.QLabel(parent=self.page_3) self.label_5.setObjectName("label_5") self.verticalLayout_8.addWidget(self.label_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() @@ -213,11 +217,11 @@ def setupUi(self, Dialog): self.horizontalLayout_6.addItem(spacerItem6) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setObjectName("verticalLayout_7") - self.radioButton_SimpleDLopenCall = QtWidgets.QRadioButton(self.page_3) + self.radioButton_SimpleDLopenCall = QtWidgets.QRadioButton(parent=self.page_3) self.radioButton_SimpleDLopenCall.setChecked(True) self.radioButton_SimpleDLopenCall.setObjectName("radioButton_SimpleDLopenCall") self.verticalLayout_7.addWidget(self.radioButton_SimpleDLopenCall) - self.radioButton_AdvancedInjection = QtWidgets.QRadioButton(self.page_3) + self.radioButton_AdvancedInjection = QtWidgets.QRadioButton(parent=self.page_3) self.radioButton_AdvancedInjection.setEnabled(False) self.radioButton_AdvancedInjection.setObjectName("radioButton_AdvancedInjection") self.verticalLayout_7.addWidget(self.radioButton_AdvancedInjection) @@ -237,7 +241,7 @@ def setupUi(self, Dialog): self.gridLayout_5.setObjectName("gridLayout_5") self.verticalLayout_10 = QtWidgets.QVBoxLayout() self.verticalLayout_10.setObjectName("verticalLayout_10") - self.checkBox_BringDisassembleToFront = QtWidgets.QCheckBox(self.page_4) + self.checkBox_BringDisassembleToFront = QtWidgets.QCheckBox(parent=self.page_4) self.checkBox_BringDisassembleToFront.setChecked(True) self.checkBox_BringDisassembleToFront.setObjectName("checkBox_BringDisassembleToFront") self.verticalLayout_10.addWidget(self.checkBox_BringDisassembleToFront) @@ -245,10 +249,10 @@ def setupUi(self, Dialog): self.horizontalLayout_10.setObjectName("horizontalLayout_10") self.horizontalLayout_9 = QtWidgets.QHBoxLayout() self.horizontalLayout_9.setObjectName("horizontalLayout_9") - self.label_6 = QtWidgets.QLabel(self.page_4) + self.label_6 = QtWidgets.QLabel(parent=self.page_4) self.label_6.setObjectName("label_6") self.horizontalLayout_9.addWidget(self.label_6) - self.lineEdit_InstructionsPerScroll = QtWidgets.QLineEdit(self.page_4) + self.lineEdit_InstructionsPerScroll = QtWidgets.QLineEdit(parent=self.page_4) self.lineEdit_InstructionsPerScroll.setObjectName("lineEdit_InstructionsPerScroll") self.horizontalLayout_9.addWidget(self.lineEdit_InstructionsPerScroll) self.horizontalLayout_10.addLayout(self.horizontalLayout_9) @@ -269,24 +273,24 @@ def setupUi(self, Dialog): self.horizontalLayout_11.setObjectName("horizontalLayout_11") self.horizontalLayout_101 = QtWidgets.QHBoxLayout() self.horizontalLayout_101.setObjectName("horizontalLayout_101") - self.label_7 = QtWidgets.QLabel(self.page_5) + self.label_7 = QtWidgets.QLabel(parent=self.page_5) self.label_7.setObjectName("label_7") self.horizontalLayout_101.addWidget(self.label_7) - self.lineEdit_GDBPath = QtWidgets.QLineEdit(self.page_5) + self.lineEdit_GDBPath = QtWidgets.QLineEdit(parent=self.page_5) self.lineEdit_GDBPath.setObjectName("lineEdit_GDBPath") self.horizontalLayout_101.addWidget(self.lineEdit_GDBPath) self.horizontalLayout_11.addLayout(self.horizontalLayout_101) - self.pushButton_GDBPath = QtWidgets.QPushButton(self.page_5) + self.pushButton_GDBPath = QtWidgets.QPushButton(parent=self.page_5) self.pushButton_GDBPath.setText("") self.pushButton_GDBPath.setObjectName("pushButton_GDBPath") self.horizontalLayout_11.addWidget(self.pushButton_GDBPath) self.verticalLayout_11.addLayout(self.horizontalLayout_11) - self.checkBox_GDBLogging = QtWidgets.QCheckBox(self.page_5) + self.checkBox_GDBLogging = QtWidgets.QCheckBox(parent=self.page_5) self.checkBox_GDBLogging.setObjectName("checkBox_GDBLogging") self.verticalLayout_11.addWidget(self.checkBox_GDBLogging) self.horizontalLayout_16 = QtWidgets.QHBoxLayout() self.horizontalLayout_16.setObjectName("horizontalLayout_16") - self.pushButton_HandleSignals = QtWidgets.QPushButton(self.page_5) + self.pushButton_HandleSignals = QtWidgets.QPushButton(parent=self.page_5) self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -300,12 +304,12 @@ def setupUi(self, Dialog): self.verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.pushButton_ResetSettings = QtWidgets.QPushButton(Dialog) + self.pushButton_ResetSettings = QtWidgets.QPushButton(parent=Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem13) - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") @@ -338,11 +342,7 @@ def retranslateUi(self, Dialog): self.listWidget_Options.setSortingEnabled(__sortingEnabled) self.checkBox_AutoUpdateAddressTable.setText(_translate("Dialog", "Auto-update address table")) self.label.setText(_translate("Dialog", "Update Interval")) - self.lineEdit_UpdateInterval.setText(_translate("Dialog", "500")) - self.label_2.setText(_translate("Dialog", "ms")) self.label_12.setText(_translate("Dialog", "Freeze Interval")) - self.lineEdit_FreezeInterval.setText(_translate("Dialog", "100")) - self.label_10.setText(_translate("Dialog", "ms")) self.checkBox_MessageBoxOnException.setText(_translate("Dialog", "Show a MessageBox on InferiorRunning and GDBInitialize exceptions")) self.label_8.setText(_translate("Dialog", "GDB output:")) self.checkBox_OutputModeAsync.setText(_translate("Dialog", "Async")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 1fa6f4cf..6a54e539 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -114,14 +114,14 @@ - 500 + 500 - ms + ms @@ -174,14 +174,14 @@ - 100 + 100 - ms + ms diff --git a/GUI/TraceInstructionsPromptDialog.py b/GUI/TraceInstructionsPromptDialog.py index a35b47bc..7006c7c6 100644 --- a/GUI/TraceInstructionsPromptDialog.py +++ b/GUI/TraceInstructionsPromptDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TraceInstructionsPromptDialog.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.5.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -17,47 +17,48 @@ def setupUi(self, Dialog): self.gridLayout.setObjectName("gridLayout") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.label = QtWidgets.QLabel(Dialog) + self.label = QtWidgets.QLabel(parent=Dialog) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) - self.lineEdit_MaxTraceCount = QtWidgets.QLineEdit(Dialog) + self.lineEdit_MaxTraceCount = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_MaxTraceCount.setText("1000") self.lineEdit_MaxTraceCount.setObjectName("lineEdit_MaxTraceCount") self.verticalLayout.addWidget(self.lineEdit_MaxTraceCount) - self.label_3 = QtWidgets.QLabel(Dialog) + self.label_3 = QtWidgets.QLabel(parent=Dialog) self.label_3.setObjectName("label_3") self.verticalLayout.addWidget(self.label_3) - self.lineEdit_TriggerCondition = QtWidgets.QLineEdit(Dialog) + self.lineEdit_TriggerCondition = QtWidgets.QLineEdit(parent=Dialog) self.lineEdit_TriggerCondition.setObjectName("lineEdit_TriggerCondition") self.verticalLayout.addWidget(self.lineEdit_TriggerCondition) - self.label_2 = QtWidgets.QLabel(Dialog) + self.label_2 = QtWidgets.QLabel(parent=Dialog) self.label_2.setObjectName("label_2") self.verticalLayout.addWidget(self.label_2) - self.lineEdit_StopCondition = QtWidgets.QLineEdit(Dialog) + self.lineEdit_StopCondition = QtWidgets.QLineEdit(parent=Dialog) self.lineEdit_StopCondition.setObjectName("lineEdit_StopCondition") self.verticalLayout.addWidget(self.lineEdit_StopCondition) - self.checkBox_StepOver = QtWidgets.QCheckBox(Dialog) + self.checkBox_StepOver = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_StepOver.setObjectName("checkBox_StepOver") self.verticalLayout.addWidget(self.checkBox_StepOver) - self.checkBox_StopAfterTrace = QtWidgets.QCheckBox(Dialog) + self.checkBox_StopAfterTrace = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_StopAfterTrace.setObjectName("checkBox_StopAfterTrace") self.verticalLayout.addWidget(self.checkBox_StopAfterTrace) - self.checkBox_GeneralRegisters = QtWidgets.QCheckBox(Dialog) + self.checkBox_GeneralRegisters = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_GeneralRegisters.setChecked(True) self.checkBox_GeneralRegisters.setObjectName("checkBox_GeneralRegisters") self.verticalLayout.addWidget(self.checkBox_GeneralRegisters) - self.checkBox_FlagRegisters = QtWidgets.QCheckBox(Dialog) + self.checkBox_FlagRegisters = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_FlagRegisters.setChecked(True) self.checkBox_FlagRegisters.setObjectName("checkBox_FlagRegisters") self.verticalLayout.addWidget(self.checkBox_FlagRegisters) - self.checkBox_SegmentRegisters = QtWidgets.QCheckBox(Dialog) + self.checkBox_SegmentRegisters = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_SegmentRegisters.setChecked(True) self.checkBox_SegmentRegisters.setObjectName("checkBox_SegmentRegisters") self.verticalLayout.addWidget(self.checkBox_SegmentRegisters) - self.checkBox_FloatRegisters = QtWidgets.QCheckBox(Dialog) + self.checkBox_FloatRegisters = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_FloatRegisters.setChecked(True) self.checkBox_FloatRegisters.setObjectName("checkBox_FloatRegisters") self.verticalLayout.addWidget(self.checkBox_FloatRegisters) - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") @@ -74,7 +75,6 @@ def retranslateUi(self, Dialog): Dialog.setWindowTitle(_translate("Dialog", "Parameters for tracing")) self.label.setToolTip(_translate("Dialog", "Number of the instructions that\'ll be traced")) self.label.setText(_translate("Dialog", "Max trace count(1 or greater):")) - self.lineEdit_MaxTraceCount.setText(_translate("Dialog", "1000")) self.label_3.setToolTip(_translate("Dialog", "Tracing will start if this condition is met")) self.label_3.setText(_translate("Dialog", "Trigger condition(Optional, gdb expression):")) self.label_2.setToolTip(_translate("Dialog", "Tracing will stop whenever this condition is met")) diff --git a/GUI/TraceInstructionsPromptDialog.ui b/GUI/TraceInstructionsPromptDialog.ui index 57c6e2c1..558f3d24 100644 --- a/GUI/TraceInstructionsPromptDialog.ui +++ b/GUI/TraceInstructionsPromptDialog.ui @@ -29,7 +29,7 @@ - 1000 + 1000 diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index ffd332b6..31e7cd0d 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1,6 +1,6 @@ - + Dialog @@ -44,25 +44,14 @@ Length - - - - - - 10 - + Lunghezza Address: - - - - - = - + Indirizzo: @@ -89,13 +78,6 @@ Selected regions will be scanned - - - - - - - - Currently scanning range: @@ -197,12 +179,12 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Cancel - + Annulla Settings - + Impostazioni @@ -239,27 +221,11 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Update Interval - - - 500 - - - - - - ms - - Freeze Interval - - - 100 - - Show a MessageBox on InferiorRunning and GDBInitialize exceptions @@ -381,11 +347,6 @@ Patterns at former positions have higher priority if regex is off Max trace count(1 or greater): - - - 1000 - - Tracing will start if this condition is met @@ -475,15 +436,6 @@ Patterns at former positions have higher priority if regex is off GDB Console - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Monospace'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - Send @@ -576,7 +528,7 @@ p, li { white-space: pre-wrap; } Address - + Indirizzo @@ -604,18 +556,13 @@ p, li { white-space: pre-wrap; } type_defs(Type Definitions) - - - 0/0 - - Value - + Valore @@ -715,12 +662,12 @@ p, li { white-space: pre-wrap; } Start - + Inizio End - + Fine @@ -740,7 +687,7 @@ p, li { white-space: pre-wrap; } Cancel - + Annulla @@ -772,11 +719,6 @@ p, li { white-space: pre-wrap; } MainWindow - - - PINCE - - Freeze @@ -796,7 +738,7 @@ p, li { white-space: pre-wrap; } Address - + Indirizzo @@ -807,7 +749,7 @@ p, li { white-space: pre-wrap; } Value - + Valore @@ -862,7 +804,7 @@ p, li { white-space: pre-wrap; } No Process Selected - + Nessun Processo Selezionato @@ -882,12 +824,12 @@ p, li { white-space: pre-wrap; } Previous - + Precedente First Scan - + Prima Ricerca @@ -907,18 +849,13 @@ p, li { white-space: pre-wrap; } &Decimal - + &Decimale Hex - - - <-> - - Scan Type: @@ -942,7 +879,7 @@ p, li { white-space: pre-wrap; } Name of the Process: - + Nome del Processo: @@ -952,12 +889,12 @@ p, li { white-space: pre-wrap; } Username - + Nome Utente Process Name - + Nome Processo @@ -973,7 +910,7 @@ p, li { white-space: pre-wrap; } Cancel - + Annulla @@ -1018,7 +955,7 @@ p, li { white-space: pre-wrap; } Address - + Indirizzo @@ -1040,234 +977,16 @@ p, li { white-space: pre-wrap; } Registers - - - RAX= - - - - - RBX= - - - - - RCX= - - - - - RDX= - - - - - RSI= - - - - - RDI= - - - - - RBP= - - - - - RSP= - - - - - R8= - - - - - R9= - - - - - R10= - - - - - R11= - - - - - R12= - - - - - R13= - - - - - R14= - - - - - R15= - - - - - RIP= - - - - - EAX= - - - - - EBX= - - - - - ECX= - - - - - EDX= - - - - - ESI= - - - - - EDI= - - - - - EBP= - - - - - ESP= - - - - - EIP= - - Flags - - - CF - - - - - - - - - - - - - 0 - - - - - PF - - - - - AF - - - - - ZF - - - - - SF - - - - - TF - - - - - IF - - - - - DF - - - - - OF - - Segment Registers - - - CS= - - - - - ES= - - - - - SS= - - - - - GS= - - - - - DS= - - - - - FS= - - Show Float Registers @@ -1286,7 +1005,7 @@ p, li { white-space: pre-wrap; } Value - + Valore @@ -1484,7 +1203,7 @@ p, li { white-space: pre-wrap; } Address - + Indirizzo @@ -1516,11 +1235,6 @@ p, li { white-space: pre-wrap; } Floating Point Registers - - - FPU - - @@ -1531,12 +1245,7 @@ p, li { white-space: pre-wrap; } Value - - - - - XMM - + Valore @@ -1819,12 +1528,12 @@ To change the current GDB path, check Settings->Debug First Scan - + Prima Ricerca No Process Selected - + Nessun Processo Selezionato @@ -2628,7 +2337,7 @@ Use the char \ to escape special chars such as [ Start - + Inizio @@ -2638,7 +2347,7 @@ Use the char \ to escape special chars such as [ Cancel - + Annulla From 28c178a12af06e12feba45b73d0619bd69cb664c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 20 Jul 2023 00:46:24 +0300 Subject: [PATCH 207/487] colour to color --- PINCE.py | 78 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/PINCE.py b/PINCE.py index 93955fe3..ad3c767e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -192,11 +192,11 @@ def get_hotkeys(): BREAK_HIT_COUNT_COL = 7 BREAK_COND_COL = 8 -# row colours for disassemble qtablewidget -PC_COLOUR = QColorConstants.Blue -BOOKMARK_COLOUR = QColorConstants.Cyan -BREAKPOINT_COLOUR = QColorConstants.Red -REF_COLOUR = QColorConstants.LightGray +# row colors for disassemble qtablewidget +PC_COLOR = QColorConstants.Blue +BOOKMARK_COLOR = QColorConstants.Cyan +BREAKPOINT_COLOR = QColorConstants.Red +REF_COLOR = QColorConstants.LightGray # represents the index of columns in address table FROZEN_COL = 0 # Frozen @@ -3044,7 +3044,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his return False program_counter = GDB_Engine.examine_expression("$pc").address program_counter_int = int(program_counter, 16) - row_colour = {} + row_color = {} breakpoint_info = GDB_Engine.get_breakpoint_info() # TODO: Change this nonsense when the huge refactorization happens @@ -3093,9 +3093,9 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his tooltip_text += "\n..." tooltip_text += f"\n\n{tr.SEE_REFERRERS}" try: - row_colour[row].append(REF_COLOUR) + row_color[row].append(REF_COLOR) except KeyError: - row_colour[row] = [REF_COLOUR] + row_color[row] = [REF_COLOR] real_ref_count = 0 if jmp_ref_exists: real_ref_count += len(jmp_referrers) @@ -3105,15 +3105,15 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his if current_address == program_counter_int: address_info = ">>>" + address_info try: - row_colour[row].append(PC_COLOUR) + row_color[row].append(PC_COLOR) except KeyError: - row_colour[row] = [PC_COLOUR] + row_color[row] = [PC_COLOR] for bookmark_item in self.tableWidget_Disassemble.bookmarks.keys(): if current_address == bookmark_item: try: - row_colour[row].append(BOOKMARK_COLOUR) + row_color[row].append(BOOKMARK_COLOR) except KeyError: - row_colour[row] = [BOOKMARK_COLOUR] + row_color[row] = [BOOKMARK_COLOR] address_info = "(M)" + address_info comment = self.tableWidget_Disassemble.bookmarks[bookmark_item] break @@ -3121,9 +3121,9 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his int_breakpoint_address = int(breakpoint.address, 16) if current_address == int_breakpoint_address: try: - row_colour[row].append(BREAKPOINT_COLOUR) + row_color[row].append(BREAKPOINT_COLOR) except KeyError: - row_colour[row] = [BREAKPOINT_COLOUR] + row_color[row] = [BREAKPOINT_COLOR] breakpoint_mark = "(B" if breakpoint.enabled == "n": breakpoint_mark += "-disabled" @@ -3152,7 +3152,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his self.tableWidget_Disassemble.setItem(row, DISAS_COMMENT_COL, comment_item) jmp_dict.close() call_dict.close() - self.handle_colours(row_colour) + self.handle_colors(row_color) # We append the old record to travel history as last action because we wouldn't like to see unnecessary # addresses in travel history if any error occurs while displaying the next location @@ -3166,41 +3166,41 @@ def refresh_disassemble_view(self): return self.disassemble_expression(self.disassemble_currently_displayed_address) - # Set colour of a row if a specific address is encountered(e.g $pc, a bookmarked address etc.) - def handle_colours(self, row_colour): + # Set color of a row if a specific address is encountered(e.g $pc, a bookmarked address etc.) + def handle_colors(self, row_color): if GDB_Engine.currentpid == -1: return - for row in row_colour: - current_row = row_colour[row] - if PC_COLOUR in current_row: - if BREAKPOINT_COLOUR in current_row: - colour = QColorConstants.Green - elif BOOKMARK_COLOUR in current_row: - colour = QColorConstants.Yellow + for row in row_color: + current_row = row_color[row] + if PC_COLOR in current_row: + if BREAKPOINT_COLOR in current_row: + color = QColorConstants.Green + elif BOOKMARK_COLOR in current_row: + color = QColorConstants.Yellow else: - colour = PC_COLOUR - self.set_row_colour(row, colour) + color = PC_COLOR + self.set_row_color(row, color) continue - if BREAKPOINT_COLOUR in current_row: - if BOOKMARK_COLOUR in current_row: - colour = QColorConstants.Magenta + if BREAKPOINT_COLOR in current_row: + if BOOKMARK_COLOR in current_row: + color = QColorConstants.Magenta else: - colour = BREAKPOINT_COLOUR - self.set_row_colour(row, colour) + color = BREAKPOINT_COLOR + self.set_row_color(row, color) continue - if BOOKMARK_COLOUR in current_row: - self.set_row_colour(row, BOOKMARK_COLOUR) + if BOOKMARK_COLOR in current_row: + self.set_row_color(row, BOOKMARK_COLOR) continue - if REF_COLOUR in current_row: - self.set_row_colour(row, REF_COLOUR) + if REF_COLOR in current_row: + self.set_row_color(row, REF_COLOR) - def set_row_colour(self, row, colour): + def set_row_color(self, row, color): if GDB_Engine.currentpid == -1: return for col in range(self.tableWidget_Disassemble.columnCount()): - colour = QColor(colour) - colour.setAlpha(96) - self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, colour) + color = QColor(color) + color.setAlpha(96) + self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, color) def on_process_stop(self): if GDB_Engine.stop_reason == type_defs.STOP_REASON.PAUSE: From d064db9ed963470b61346298ef986f556b839c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 20 Jul 2023 12:46:30 +0300 Subject: [PATCH 208/487] Remove newlines from trace data --- libpince/gdb_python_scripts/GDBCommandExtensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 4e8887b9..f9b5a08a 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -337,7 +337,7 @@ def invoke(self, arg, from_tty): break except: pass - line_info = gdb.execute("x/i $pc", to_string=True).split(maxsplit=1)[1] + line_info = gdb.execute("x/i $pc", to_string=True).splitlines()[0].split(maxsplit=1)[1] collect_dict = OrderedDict() if collect_general_registers: collect_dict.update(ScriptUtils.get_general_registers()) @@ -351,7 +351,7 @@ def invoke(self, arg, from_tty): tree.append([(line_info, collect_dict), current_root_index, []]) tree[current_root_index][2].append(current_index) # Add a child status_info = (type_defs.TRACE_STATUS.STATUS_TRACING, - line_info + " (" + str(x + 1) + "/" + str(max_trace_count) + ")") + line_info + "\n(" + str(x + 1) + "/" + str(max_trace_count) + ")") pickle.dump(status_info, open(trace_status_file, "wb")) if common_regexes.trace_instructions_ret.search(line_info): if tree[current_root_index][1] is None: # If no parents exist From a925d0546aed2e325fde53bf4c23a3b011146a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 26 Jul 2023 18:31:34 +0300 Subject: [PATCH 209/487] Add translation deps --- install_pince.sh | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index 87dd6fc4..483ac878 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -122,10 +122,10 @@ ask_pkg_mgr() { # About xcb packages -> https://github.com/cdgriffith/FastFlix/wiki/Common-questions-and-problems PKG_NAMES_ALL="python3-pip gdb libtool intltool" -PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" -PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" -PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" -PKG_NAMES_ARCH="python-pip readline intltool gdb lsb-release" # arch defaults to py3 nowadays +PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config qt6-l10n-tools libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" +PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" +PKG_NAMES_ARCH="python-pip qt6-tools readline intltool gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES_PIP="pyqt6 pexpect distorm3 keystone-engine pygdbmi keyboard pygobject" INSTALL_COMMAND="install" @@ -135,19 +135,23 @@ set_install_vars() { *SUSE*) PKG_MGR="zypper" PKG_NAMES="$PKG_NAMES_SUSE" + LRELEASE_CMD="lrelease6" ;; *Arch*) PKG_MGR="pacman" PKG_NAMES="$PKG_NAMES_ARCH" INSTALL_COMMAND="-S --needed" + LRELEASE_CMD="usr/lib/qt6/bin/lrelease" ;; *Fedora*) PKG_MGR="dnf -y" PKG_NAMES="$PKG_NAMES_FEDORA" + LRELEASE_CMD="lrelease-qt6" ;; *Debian*|*Ubuntu*) PKG_MGR="apt -y" PKG_NAMES="$PKG_NAMES_DEBIAN" + LRELEASE_CMD="/usr/lib/qt6/bin/lrelease" ;; *) return 1 @@ -157,6 +161,12 @@ set_install_vars() { return 0 } +compile_translations() { + ${LRELEASE_CMD} i18n/ts/* + mkdir -p i18n/qm + mv i18n/ts/*.qm i18n/qm/ +} + LSB_RELEASE="$(command -v lsb_release)" if [ -n "$LSB_RELEASE" ]; then OS_NAME="$(${LSB_RELEASE} -d -s)" @@ -193,6 +203,8 @@ pip3 install ${PKG_NAMES_PIP} || exit_on_error install_scanmem || exit_on_error +compile_translations || exit_on_error + echo echo "PINCE has been installed successfully!" echo "Now, just run 'sh PINCE.sh' from terminal" From 4966543cc807192c94382cbcea01951dbb9cdac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 26 Jul 2023 18:41:20 +0300 Subject: [PATCH 210/487] Fix typo in lrelease path --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index 483ac878..f722e25f 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -141,7 +141,7 @@ set_install_vars() { PKG_MGR="pacman" PKG_NAMES="$PKG_NAMES_ARCH" INSTALL_COMMAND="-S --needed" - LRELEASE_CMD="usr/lib/qt6/bin/lrelease" + LRELEASE_CMD="/usr/lib/qt6/bin/lrelease" ;; *Fedora*) PKG_MGR="dnf -y" From 5abe91cd60177b9e113d801cb4aada562a365dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Wed, 26 Jul 2023 18:47:24 +0300 Subject: [PATCH 211/487] Update scanmem commit checkout --- scanmem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scanmem b/scanmem index 65f8e700..8b0d9e88 160000 --- a/scanmem +++ b/scanmem @@ -1 +1 @@ -Subproject commit 65f8e700c56d9858fe01dba393d9b8238040b8ee +Subproject commit 8b0d9e889c5449c0a585428f414251a9ceac8844 From edaf53115f48df3a7a0dafaaffbd0bb1787b767a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Wed, 26 Jul 2023 18:48:28 +0300 Subject: [PATCH 212/487] Remove misc.py dependency --- install_pince.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index f722e25f..abe104a4 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -78,11 +78,8 @@ install_scanmem() { fi cp --preserve .libs/libscanmem.so ../libpince/libscanmem/ cp --preserve wrappers/scanmem.py ../libpince/libscanmem - cp --preserve wrappers/misc.py ../libpince/libscanmem echo "Exiting scanmem" ) || return 1 - # required for relative import, since it will throw an import error if it's just `import misc` - sed -i 's/import misc/from \. import misc/g' libpince/libscanmem/scanmem.py return 0 } From f2d02323f6d7f2c542c2ceb1f5158a888b76836c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 1 Aug 2023 19:24:42 +0300 Subject: [PATCH 213/487] Implement background execution --- GUI/ConsoleWidget.py | 13 +- GUI/ConsoleWidget.ui | 14 +- GUI/CustomLabels/FlagRegisterLabel.py | 4 +- GUI/CustomLabels/RegisterLabel.py | 5 +- GUI/TrackBreakpointWidget.py | 42 +- GUI/TrackBreakpointWidget.ui | 90 ++-- PINCE.py | 120 ++--- README.md | 5 +- i18n/ts/it_IT.ts | 467 +++++++++--------- libpince/GDB_Engine.py | 103 ++-- libpince/common_regexes.py | 5 +- .../GDBCommandExtensions.py | 2 +- libpince/type_defs.py | 5 - tr/tr.py | 20 +- 14 files changed, 365 insertions(+), 530 deletions(-) diff --git a/GUI/ConsoleWidget.py b/GUI/ConsoleWidget.py index 03eb8d80..094c882c 100644 --- a/GUI/ConsoleWidget.py +++ b/GUI/ConsoleWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ConsoleWidget.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -57,13 +57,12 @@ def setupUi(self, Form): font.setFamily("Monospace") font.setBold(False) font.setItalic(False) - font.setWeight(50) self.textBrowser.setFont(font) self.textBrowser.setHtml("\n" -"\n" -"


") +"\n" +"


") self.textBrowser.setObjectName("textBrowser") self.verticalLayout.addWidget(self.textBrowser) self.horizontalLayout = QtWidgets.QHBoxLayout() @@ -74,9 +73,6 @@ def setupUi(self, Form): self.pushButton_Send = QtWidgets.QPushButton(parent=Form) self.pushButton_Send.setObjectName("pushButton_Send") self.horizontalLayout.addWidget(self.pushButton_Send) - self.pushButton_SendCtrl = QtWidgets.QPushButton(parent=Form) - self.pushButton_SendCtrl.setObjectName("pushButton_SendCtrl") - self.horizontalLayout.addWidget(self.pushButton_SendCtrl) self.radioButton_CLI = QtWidgets.QRadioButton(parent=Form) self.radioButton_CLI.setObjectName("radioButton_CLI") self.horizontalLayout.addWidget(self.radioButton_CLI) @@ -94,6 +90,5 @@ def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "GDB Console")) self.pushButton_Send.setText(_translate("Form", "Send")) - self.pushButton_SendCtrl.setText(_translate("Form", "Send ctrl+c")) self.radioButton_CLI.setText(_translate("Form", "CLI")) self.radioButton_MI.setText(_translate("Form", "MI")) diff --git a/GUI/ConsoleWidget.ui b/GUI/ConsoleWidget.ui index 501534e8..f2639453 100644 --- a/GUI/ConsoleWidget.ui +++ b/GUI/ConsoleWidget.ui @@ -124,17 +124,16 @@ Monospace - 50 false false <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Monospace'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:9pt;"><br /></p></body></html> +</style></head><body style=" font-family:'Monospace'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
@@ -150,13 +149,6 @@ p, li { white-space: pre-wrap; } - - - - Send ctrl+c - - - diff --git a/GUI/CustomLabels/FlagRegisterLabel.py b/GUI/CustomLabels/FlagRegisterLabel.py index 9a292f99..1cf6cb78 100644 --- a/GUI/CustomLabels/FlagRegisterLabel.py +++ b/GUI/CustomLabels/FlagRegisterLabel.py @@ -17,7 +17,7 @@ from PyQt6.QtWidgets import QLabel from PyQt6.QtGui import QCursor from PyQt6.QtCore import Qt -from libpince import GDB_Engine +from libpince import GDB_Engine, type_defs from PINCE import InputDialogForm @@ -38,7 +38,7 @@ def enterEvent(self, QEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): - if GDB_Engine.currentpid == -1: + if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: return registers = GDB_Engine.read_registers() current_flag = self.objectName().lower() diff --git a/GUI/CustomLabels/RegisterLabel.py b/GUI/CustomLabels/RegisterLabel.py index 915fd8e8..1e2c70c0 100644 --- a/GUI/CustomLabels/RegisterLabel.py +++ b/GUI/CustomLabels/RegisterLabel.py @@ -17,8 +17,7 @@ from PyQt6.QtWidgets import QLabel, QMenu from PyQt6.QtGui import QCursor from PyQt6.QtCore import Qt -from libpince import GDB_Engine -from libpince import GuiUtils +from libpince import GDB_Engine, GuiUtils, type_defs from PINCE import InputDialogForm @@ -39,7 +38,7 @@ def enterEvent(self, QEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): - if GDB_Engine.currentpid == -1: + if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: return registers = GDB_Engine.read_registers() current_register = self.objectName().lower() diff --git a/GUI/TrackBreakpointWidget.py b/GUI/TrackBreakpointWidget.py index cd9d9632..1d27a685 100644 --- a/GUI/TrackBreakpointWidget.py +++ b/GUI/TrackBreakpointWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TrackBreakpointWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -15,20 +15,7 @@ def setupUi(self, Form): Form.resize(549, 437) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - self.pushButton_Stop = QtWidgets.QPushButton(Form) - self.pushButton_Stop.setObjectName("pushButton_Stop") - self.horizontalLayout.addWidget(self.pushButton_Stop) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem) - self.comboBox_ValueType = QtWidgets.QComboBox(Form) - self.comboBox_ValueType.setToolTip("") - self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) - self.comboBox_ValueType.setObjectName("comboBox_ValueType") - self.horizontalLayout.addWidget(self.comboBox_ValueType) - self.gridLayout.addLayout(self.horizontalLayout, 3, 0, 1, 1) - self.tableWidget_TrackInfo = QtWidgets.QTableWidget(Form) + self.tableWidget_TrackInfo = QtWidgets.QTableWidget(parent=Form) self.tableWidget_TrackInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_TrackInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_TrackInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -50,15 +37,19 @@ def setupUi(self, Form): self.tableWidget_TrackInfo.verticalHeader().setDefaultSectionSize(16) self.tableWidget_TrackInfo.verticalHeader().setMinimumSectionSize(16) self.gridLayout.addWidget(self.tableWidget_TrackInfo, 0, 0, 1, 1) - self.label_Info = QtWidgets.QLabel(Form) - self.label_Info.setText("") - self.label_Info.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label_Info.setObjectName("label_Info") - self.gridLayout.addWidget(self.label_Info, 1, 0, 1, 1) - self.label_AdditionalInfo = QtWidgets.QLabel(Form) - self.label_AdditionalInfo.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label_AdditionalInfo.setObjectName("label_AdditionalInfo") - self.gridLayout.addWidget(self.label_AdditionalInfo, 2, 0, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.pushButton_Stop = QtWidgets.QPushButton(parent=Form) + self.pushButton_Stop.setObjectName("pushButton_Stop") + self.horizontalLayout.addWidget(self.pushButton_Stop) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.comboBox_ValueType = QtWidgets.QComboBox(parent=Form) + self.comboBox_ValueType.setToolTip("") + self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) + self.comboBox_ValueType.setObjectName("comboBox_ValueType") + self.horizontalLayout.addWidget(self.comboBox_ValueType) + self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) self.retranslateUi(Form) self.comboBox_ValueType.setCurrentIndex(-1) @@ -67,7 +58,6 @@ def setupUi(self, Form): def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) - self.pushButton_Stop.setText(_translate("Form", "Stop")) item = self.tableWidget_TrackInfo.horizontalHeaderItem(0) item.setText(_translate("Form", "Count")) item = self.tableWidget_TrackInfo.horizontalHeaderItem(1) @@ -76,4 +66,4 @@ def retranslateUi(self, Form): item.setText(_translate("Form", "Value")) item = self.tableWidget_TrackInfo.horizontalHeaderItem(3) item.setText(_translate("Form", "Source")) - self.label_AdditionalInfo.setText(_translate("Form", "Try changing combobox index if the \'Value\' part of table still isn\'t updated")) + self.pushButton_Stop.setText(_translate("Form", "Stop")) diff --git a/GUI/TrackBreakpointWidget.ui b/GUI/TrackBreakpointWidget.ui index f58c8fd4..c525bf20 100644 --- a/GUI/TrackBreakpointWidget.ui +++ b/GUI/TrackBreakpointWidget.ui @@ -14,43 +14,6 @@ Form - - - - - - Stop - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - -1 - - - QComboBox::AdjustToContents - - - - - @@ -103,24 +66,41 @@ - - - - - - Qt::AlignCenter - - - - - - - Try changing combobox index if the 'Value' part of table still isn't updated - - - Qt::AlignCenter - - + + + + + Stop + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + -1 + + + QComboBox::AdjustToContents + + + + diff --git a/PINCE.py b/PINCE.py index ad3c767e..42ef6953 100755 --- a/PINCE.py +++ b/PINCE.py @@ -306,11 +306,6 @@ def except_hook(exception_type, value, tb): if focused_widget: if exception_type == type_defs.GDBInitializeException: QMessageBox.information(focused_widget, tr.ERROR, tr.GDB_INIT) - elif exception_type == type_defs.InferiorRunningException: - error_dialog = InputDialogForm( - item_list=[(tr.PROCESS_RUNNING.format(Hotkeys.break_hotkey.get_active_key()),)], - buttons=[QDialogButtonBox.StandardButton.Ok]) - error_dialog.exec() traceback.print_exception(exception_type, value, tb) @@ -555,7 +550,6 @@ def set_default_settings(self): self.settings.endGroup() self.apply_settings() - @GDB_Engine.execute_with_temporary_interruption def apply_after_init(self): global gdb_logging global ignored_signals @@ -751,7 +745,6 @@ def treeWidget_AddressTable_context_menu_event(self, event): except KeyError: pass - @GDB_Engine.execute_with_temporary_interruption def exec_track_watchpoint_widget(self, watchpoint_type): selected_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not selected_row: @@ -963,10 +956,7 @@ def update_address_table(self): else: address_expr_list.append(address_data) rows.append(row) - try: - address_list = [item.address for item in GDB_Engine.examine_expressions(address_expr_list)] - except type_defs.InferiorRunningException: - address_list = address_expr_list + address_list = [item.address for item in GDB_Engine.examine_expressions(address_expr_list)] for index, row in enumerate(rows): value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) address = address_list[index] @@ -1195,7 +1185,6 @@ def _scan_to_length(self, type_index): return len(self.lineEdit_Scan.text()) return 0 - @GDB_Engine.execute_with_temporary_interruption def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) @@ -1565,11 +1554,8 @@ def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, addre address = GDB_Engine.read_pointer(address_expr) address_text = f'P->{hex(address)}' if address != None else address_expr.get_base_address() else: - try: - address = GDB_Engine.examine_expression(address_expr).address - except type_defs.InferiorRunningException: - address = address_expr - address_text = hex(address) if type(address) != str else address + address = GDB_Engine.examine_expression(address_expr).address + address_text = address value = '' if address: value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, @@ -1578,7 +1564,7 @@ def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, addre assert isinstance(row, QTreeWidgetItem) row.setText(DESC_COL, description) row.setData(ADDR_COL, Qt.ItemDataRole.UserRole, address_expr) - row.setText(ADDR_COL, address_text or address_expr) + row.setText(ADDR_COL, address_text) row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, value_type) row.setText(TYPE_COL, value_type.text()) row.setText(VALUE_COL, "" if value is None else str(value)) @@ -1810,11 +1796,7 @@ def update_value_of_address(self): address_text = "??" self.lineEdit_address.setText(address_text) else: - address = self.lineEdit_address.text() - try: - address = GDB_Engine.examine_expression(address).address - except type_defs.InferiorRunningException: - pass + address = GDB_Engine.examine_expression(self.lineEdit_address.text()).address if not address: self.label_valueofaddress.setText("??") return @@ -2386,19 +2368,17 @@ def __init__(self, parent=None): self.completer.setMaxVisibleItems(8) self.lineEdit.setCompleter(self.completer) self.quit_commands = ("q", "quit", "-gdb-exit") + self.continue_commands = ("c", "continue", "-exec-continue") self.input_history = [""] self.current_history_index = -1 self.await_async_output_thread = AwaitAsyncOutput() self.await_async_output_thread.async_output_ready.connect(self.on_async_output) self.await_async_output_thread.start() self.pushButton_Send.clicked.connect(self.communicate) - self.pushButton_SendCtrl.clicked.connect(lambda: self.communicate(control=True)) self.shortcut_send = QShortcut(QKeySequence("Return"), self) self.shortcut_send.activated.connect(self.communicate) self.shortcut_complete_command = QShortcut(QKeySequence("Tab"), self) self.shortcut_complete_command.activated.connect(self.complete_command) - self.shortcut_send_ctrl = QShortcut(QKeySequence("Ctrl+C"), self) - self.shortcut_send_ctrl.activated.connect(lambda: self.communicate(control=True)) self.shortcut_multiline_mode = QShortcut(QKeySequence("Ctrl+Return"), self) self.shortcut_multiline_mode.activated.connect(self.enter_multiline_mode) self.lineEdit.textEdited.connect(self.finish_completion) @@ -2408,17 +2388,14 @@ def __init__(self, parent=None): self.lineEdit.keyPressEvent = self.lineEdit_key_press_event self.reset_console_text() - def communicate(self, control=False): + def communicate(self): self.current_history_index = -1 self.input_history[-1] = "" - if control: - console_input = "/Ctrl+C" - else: - console_input = self.lineEdit.text() - last_input = self.input_history[-2] if len(self.input_history) > 1 else "" - if console_input != last_input and console_input != "": - self.input_history[-1] = console_input - self.input_history.append("") + console_input = self.lineEdit.text() + last_input = self.input_history[-2] if len(self.input_history) > 1 else "" + if console_input != last_input and console_input != "": + self.input_history[-1] = console_input + self.input_history.append("") if console_input.lower() == "/clear": self.lineEdit.clear() self.reset_console_text() @@ -2426,18 +2403,13 @@ def communicate(self, control=False): self.lineEdit.clear() if console_input.strip().lower() in self.quit_commands: console_output = tr.QUIT_SESSION_CRASH + if console_input.strip().lower() in self.continue_commands: + console_output = tr.CONT_SESSION_CRASH else: - if not control: - if self.radioButton_CLI.isChecked(): - console_output = GDB_Engine.send_command(console_input, cli_output=True) - else: - console_output = GDB_Engine.send_command(console_input) - if not console_output: - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - console_output = tr.INFERIOR_RUNNING + if self.radioButton_CLI.isChecked(): + console_output = GDB_Engine.send_command(console_input, cli_output=True) else: - GDB_Engine.interrupt_inferior() - console_output = "" + console_output = GDB_Engine.send_command(console_input) self.textBrowser.append("-->" + console_input) if console_output: self.textBrowser.append(console_output) @@ -2493,8 +2465,7 @@ def finish_completion(self): self.completion_model.setStringList([]) def complete_command(self): - if GDB_Engine.gdb_initialized and GDB_Engine.currentpid != -1 and self.lineEdit.text() and \ - GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: + if GDB_Engine.gdb_initialized and GDB_Engine.currentpid != -1 and self.lineEdit.text(): self.completion_model.setStringList(GDB_Engine.complete_command(self.lineEdit.text())) self.completer.complete() else: @@ -2665,7 +2636,6 @@ def initialize_disassemble_view(self): self.tableWidget_Disassemble.itemSelectionChanged.connect(self.tableWidget_Disassemble_item_selection_changed) def initialize_hex_view(self): - self.cached_breakpoint_info = [] self.hex_view_last_selected_address_int = 0 self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) self.widget_HexView.wheelEvent = self.widget_HexView_wheel_event @@ -2763,7 +2733,6 @@ def nop_instruction(self): GDB_Engine.nop_instruction(current_address_int, len(array_of_bytes.split())) self.refresh_disassemble_view() - @GDB_Engine.execute_with_temporary_interruption def toggle_breakpoint(self): if GDB_Engine.currentpid == -1: return @@ -2902,8 +2871,6 @@ def hex_view_scrollbar_sliderchanged(self, event): if self.bHexViewScrolling: return self.bHexViewScrolling = True - # if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: - # return maximum = self.verticalScrollBar_HexView.maximum() minimum = self.verticalScrollBar_HexView.minimum() midst = (maximum + minimum) / 2 @@ -2930,8 +2897,6 @@ def disassemble_scrollbar_sliderchanged(self, even): if self.bDisassemblyScrolling: return self.bDisassemblyScrolling = True - # if GDB_Engine.inferior_status != type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: - # return maximum = self.verticalScrollBar_Disassemble.maximum() minimum = self.verticalScrollBar_Disassemble.minimum() midst = (maximum + minimum) / 2 @@ -2991,15 +2956,7 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL self.tableWidget_HexView_Address.setMinimumWidth(tableWidget_HexView_column_size) self.tableWidget_HexView_Address.setColumnWidth(0, tableWidget_HexView_column_size) data_array = GDB_Engine.hex_dump(int_address, offset) - - # TODO: Use GDB_Engine.breakpoint_on_hit_dict instead of caching breakpoints if possible - # Currently, breakpoint_on_hit_dict is not updated if the user manually adds a breakpoint via gdb - # A possible fix would be to hook the breakpoint commands but it needs to be tested thoroughly - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - breakpoint_info = self.cached_breakpoint_info - else: - breakpoint_info = GDB_Engine.get_breakpoint_info() - self.cached_breakpoint_info = breakpoint_info + breakpoint_info = GDB_Engine.get_breakpoint_info() self.hex_model.refresh(int_address, offset, data_array, breakpoint_info) self.ascii_model.refresh(int_address, offset, data_array, breakpoint_info) for index in range(offset): @@ -3043,7 +3000,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his QMessageBox.information(app.focusWidget(), tr.ERROR, tr.EXPRESSION_ACCESS_ERROR.format(expression)) return False program_counter = GDB_Engine.examine_expression("$pc").address - program_counter_int = int(program_counter, 16) + program_counter_int = int(program_counter, 16) if program_counter else None row_color = {} breakpoint_info = GDB_Engine.get_breakpoint_info() @@ -4301,6 +4258,7 @@ def __init__(self, address, length, watchpoint_type, parent=None): instances.append(self) GuiUtils.center(self) self.setWindowFlags(Qt.WindowType.Window) + self.update_timer = QTimer() if watchpoint_type == type_defs.WATCHPOINT_TYPE.WRITE_ONLY: string = tr.OPCODE_WRITING_TO.format(address) elif watchpoint_type == type_defs.WATCHPOINT_TYPE.READ_ONLY: @@ -4323,7 +4281,6 @@ def __init__(self, address, length, watchpoint_type, parent=None): self.pushButton_Refresh.clicked.connect(self.update_list) self.tableWidget_Opcodes.itemDoubleClicked.connect(self.tableWidget_Opcodes_item_double_clicked) self.tableWidget_Opcodes.selectionModel().currentChanged.connect(self.tableWidget_Opcodes_current_changed) - self.update_timer = QTimer() self.update_timer.setInterval(100) self.update_timer.timeout.connect(self.update_list) self.update_timer.start() @@ -4368,17 +4325,18 @@ def tableWidget_Opcodes_item_double_clicked(self, index): def pushButton_Stop_clicked(self): if self.stopped: self.close() - if not GDB_Engine.execute_func_temporary_interruption(GDB_Engine.delete_breakpoint, self.address): + return + if not GDB_Engine.delete_breakpoint(self.address): QMessageBox.information(self, tr.ERROR, tr.DELETE_WATCHPOINT_FAILED.format(self.address)) return self.stopped = True self.pushButton_Stop.setText(tr.CLOSE) - @GDB_Engine.execute_with_temporary_interruption def closeEvent(self, QCloseEvent): global instances self.update_timer.stop() - GDB_Engine.delete_breakpoint(self.address) + if not self.stopped: + GDB_Engine.delete_breakpoint(self.address) self.deleteLater() instances.remove(self) @@ -4397,10 +4355,6 @@ def __init__(self, address, instruction, register_expressions, parent=None): if not breakpoint: QMessageBox.information(self, tr.ERROR, tr.TRACK_BREAKPOINT_FAILED.format(address)) return - # This part will be deleted after non-pause patch, not translating - self.label_Info.setText("Pause the process to refresh 'Value' part of the table(" + - Hotkeys.pause_hotkey.get_active_key() + " or " + - Hotkeys.break_hotkey.get_active_key() + ")") self.address = address self.breakpoint = breakpoint self.info = {} @@ -4461,6 +4415,7 @@ def tableWidget_TrackInfo_item_double_clicked(self, index): def pushButton_Stop_clicked(self): if self.stopped: self.close() + return if not GDB_Engine.delete_breakpoint(self.address): QMessageBox.information(self, tr.ERROR, tr.DELETE_BREAKPOINT_FAILED.format(self.address)) return @@ -4469,17 +4424,13 @@ def pushButton_Stop_clicked(self): self.parent().refresh_disassemble_view() def closeEvent(self, QCloseEvent): - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - QCloseEvent.ignore() - raise type_defs.InferiorRunningException - try: - self.update_timer.stop() - except AttributeError: - pass global instances - instances.remove(self) - GDB_Engine.execute_func_temporary_interruption(GDB_Engine.delete_breakpoint, self.address) + self.update_timer.stop() + if not self.stopped: + GDB_Engine.delete_breakpoint(self.address) self.parent().refresh_disassemble_view() + self.deleteLater() + instances.remove(self) class TraceInstructionsPromptDialogForm(QDialog, TraceInstructionsPromptDialog): @@ -4566,10 +4517,7 @@ def closeEvent(self, QCloseEvent): != type_defs.TRACE_STATUS.STATUS_FINISHED: sleep(0.1) app.processEvents() - try: - GDB_Engine.delete_breakpoint(self.address) - except type_defs.InferiorRunningException: - pass + GDB_Engine.delete_breakpoint(self.address) self.widget_closed.emit() @@ -4715,8 +4663,6 @@ def __init__(self, parent=None): self.pushButton_Help.clicked.connect(self.pushButton_Help_clicked) def refresh_table(self): - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - raise type_defs.InferiorRunningException input_text = self.lineEdit_SearchInput.text() case_sensitive = self.checkBox_CaseSensitive.isChecked() self.loading_dialog = LoadingDialogForm(self) @@ -5268,8 +5214,6 @@ def __init__(self, start="", end="", parent=None): self.tableWidget_Opcodes.contextMenuEvent = self.tableWidget_Opcodes_context_menu_event def refresh_table(self): - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - raise type_defs.InferiorRunningException start_address = self.lineEdit_Start.text() end_address = self.lineEdit_End.text() regex = self.lineEdit_Regex.text() diff --git a/README.md b/README.md index ddae959e..e9525fa7 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,13 @@ Pre-release screenshots: # Features - **Memory searching:** PINCE uses a specialized fork of [libscanmem](https://github.com/brkzlr/scanmem-PINCE) to search the memory efficiently +- **Background Execution:** PINCE uses background execution by default, allowing users to run GDB commands while process is running - **Variable Inspection&Modification** * **CheatEngine-like value type support:** Currently supports all types of CE and scanmem along with extended strings(utf-8, utf-16, utf-32) * **Symbol Recognition:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) * **Automatic Variable Allocation:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) * **Dynamic Address Table:** Supports drag&drop, recursive copy&pasting&inserting and many more * **Smart casting:** PINCE lets you modify multiple different-type values together as long as the input is parsable. All parsing/memory errors are directed to the terminal - * **Continuous Address Table Update:** You can adjust update timer or cancel updating by modifying settings * **Variable Locking:** PINCE lets you freeze(constantly write a value to memory cell) variables - **Memory View** * **Assembler:** PINCE uses keystone engine to assemble code on the fly @@ -96,7 +96,6 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - - Extend string types with LE and BE variants of UTF-16 and UTF-32 - - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others - - Implement a custom combobox class for comboBox_ValueType and create a context menu for String_Others item -- Having to stop the process to resolve symbols sucks, we already resolve base addresses of libs by ourselves, try to replace this gdb functionality with something else, like parsing from the memory - Implement "Investigate Registers" button to gather information about the addresses registers point to(independent from other steps) - Implement selectionChanged signal of lineEdit_HexView - Implement multi selection for HexView @@ -105,7 +104,7 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run - Extend search_referenced_strings with relative search - Consider adding type guessing for the StackView(independent from other steps) - Move GUI classes of PINCE.py to their own files -- Use gdb python API breakpoints instead of breakpoint commands for optimization, also find a way to eliminate output coming from stepping commands such as ```stepi``` or ```nexti```(independent from other steps) +- Use gdb python API breakpoints instead of breakpoint commands for optimization, also find a way to eliminate output coming from stepping commands such as ```stepi&``` or ```nexti&```(independent from other steps) - Implement a psuedo-terminal for the inferior like edb does(independent from other steps) - Implement libpince engine - Implement auto-ESP&aimbot (depends on libpince engine) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 31e7cd0d..04438be4 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -441,11 +441,6 @@ Patterns at former positions have higher priority if regex is off Send - - - Send ctrl+c - - CLI @@ -689,12 +684,6 @@ Patterns at former positions have higher priority if regex is off Cancel Annulla - - - - Stop - - @@ -707,8 +696,9 @@ Patterns at former positions have higher priority if regex is off + - Try changing combobox index if the 'Value' part of table still isn't updated + Stop @@ -1307,359 +1297,351 @@ Patterns at former positions have higher priority if regex is off - Process is running -Press {} to stop process - -Go to Settings->General to disable this dialog - - - - Unable to initialize GDB You might want to reinstall GDB or use the system GDB To change the current GDB path, check Settings->Debug - + Edit - + Show as hexadecimal - + Show as decimal - + Show as unsigned - + Show as signed - + Toggle selected records - + Freeze - + Default - + Incremental - + Decremental - + Browse this memory region - + Disassemble this address - + Cut selected records - + Copy selected records - + Cut selected records (recursive) - + Copy selected records (recursive) - + Paste selected records before - + Paste selected records after - + Paste selected records inside - + Delete selected records - + Find out what writes to this address - + Find out what reads this address - + Find out what accesses this address - + Invalid clipboard content - + New Scan - + Match count: {} ({} shown) - + Match count: {} - + No Description - + Open PCT file(s) - + PINCE Cheat Table (*.pct);;All files (*) - + Clear address table? - + File {} is inaccessible or contains invalid content - + Save PCT file - + Cannot save to file - + Nice try, smartass - + Selected process is not valid - + You're debugging this process already - + That process is already being traced by {}, could not attach to the process - + Permission denied, could not attach to the process - + An error occurred while trying to create process - + Scan for - + First Scan Prima Ricerca - + No Process Selected Nessun Processo Selezionato - + [detached] - + [stopped] - + Enter the new value - + Enter the new description - + Edit Address - + Please select a process first - + Select the target binary - + Enter the optional arguments - + LD_PRELOAD .so path (optional) - + Refresh - + Length is not valid - + Length must be greater than 0 - + Can't parse the input - + Update interval must be an int - + Freeze interval must be an int - + Instruction count must be an int - + Instruction count cannot be lower than {} - + Interval cannot be a negative number - + You are asking for it, aren't you? - + Update interval should be bigger than {} ms Setting update interval less than {} ms may cause slowdown Proceed? - + {} isn't a valid regex - + You have changed the GDB path, reset GDB now? - + This will reset to the default settings Proceed? - + Mouse over on this text for examples - + asdf|qwer --> search for asdf or qwer [as]df --> search for both adf and sdf Use the char \ to escape special chars such as [ @@ -1667,34 +1649,33 @@ Use the char \ to escape special chars such as [ - + Separate processes with {} - + Select the gdb binary - + Quitting current session will crash PINCE - - Inferior is running + + Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior - + Hotkeys: ----------------------------- -Send=Enter | -Send ctrl+c=Ctrl+C | -Multi-line mode=Ctrl+Enter | -Complete command=Tab | ----------------------------- +----------------------------- +Send: Enter | +Multi-line mode: Ctrl+Enter | +Complete command: Tab | +----------------------------- Commands: ---------------------------------------------------------- /clear: Clear the console | @@ -1708,146 +1689,146 @@ pince-execute-from-so-file lib.func(params): Execute a function from lib # CLI output mode doesn't work very well with .so extensions, use MI output mode instead | --------------------------------------------------------------------------------------------------- You can change the output mode from bottom right -Note: Changing output mode only affects commands sent. Any other output coming from external sources(e.g async output) will be shown in MI format +Changing output mode only affects commands sent. Any other output coming from external sources(e.g async output) will be shown in MI format - + Break[{}] - + Run[{}] - + Toggle Attach[{}] - + Failed to set breakpoint at address {} - + Enter the watchpoint length in size of bytes - + {} can't be parsed as an integer - + Breakpoint length can't be lower than {} - + Failed to set watchpoint at address {} - + Copy to Clipboard - + Go to expression - + Add this address to address list - + Set Watchpoint - + Write Only - + Read Only - + Both - + Add/Change condition for breakpoint - + Delete Breakpoint - + Enter the expression - + {} is invalid - + Protection:{} | Base:{}-{} | Module:{} - + Invalid Region - + Cannot access memory at expression {} - + Referenced by: - + Press 'Ctrl+E' to see a detailed list of referrers - + Memory Viewer - Paused - + Memory Viewer - Currently debugging {} - + Memory Viewer - Running - + Enter the expression for condition, for instance: $eax==0x523 @@ -1856,148 +1837,148 @@ printf($r10)==3 - + Failed to set condition for address {} Check terminal for details - + Full Stack - + Copy Return Address - + Copy Frame Address - + Stacktrace - + Copy Address - + Copy Value - + Copy Points to - + Disassemble 'value' pointer address - + Show 'value' pointer in HexView - + Back - + Show this address in HexView - + Follow - + Examine Referrers - + Bookmark this address - + Delete this bookmark - + Change comment - + Go to bookmarked address - + Toggle Breakpoint - + Edit instruction - + Replace instruction with NOPs - + Find out which addresses this instruction accesses - + Break and trace instructions - + Dissect this region - + Copy Bytes - + Copy Opcode - + Copy Comment - + Copy All - + Enter the register expression(s) you want to track Register names must start with $ Each expression must be separated with a comma @@ -2013,42 +1994,42 @@ PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] - + This address has already been bookmarked - + Enter the comment for bookmarked address - + Select the .so file - + Shared object library (*.so) - + Success - + The file has been injected - + Failed to inject the .so file - + Enter the expression for the function that'll be called from the inferior You can view functions list from View->Functions @@ -2063,189 +2044,189 @@ You can use the assigned variable from the GDB Console - + Failed to call the expression {} - + Invalid expression or address - + Invalid entries detected, refreshing the page - + Add new entry - + Delete - + Enter the new value of register {} - + Restore this instruction - + Enter the hit count({} or higher) - + Hit count must be an integer - + Hit count can't be lower than {} - + Change condition - + Enable - + Disable - + Disable after hit - + Disable after X hits - + Delete after hit - + Opcodes writing to the address {} - + Opcodes reading from the address {} - + Opcodes accessing to the address {} - + Unable to track watchpoint at expression {} - + Unable to delete watchpoint at expression {} - + Close - + Addresses accessed by instruction {} - + Unable to track breakpoint at expression {} - + Accessed by {} - + Unable to delete breakpoint at expression {} - + Max trace count must be greater than or equal to {} - + Processing the collected data - + Save trace file - + Trace File (*.trace);;All Files (*) - + Open trace file - + Expand All - + Collapse All - + DEFINED - + This symbol is defined. You can use its body as a gdb expression. For instance: void func(param) can be used as 'func' as a gdb expression - + Copy Symbol - + Here's some useful regex tips: ^quaso --> search for everything that starts with quaso [ab]cd --> search for both acd and bcd @@ -2260,58 +2241,58 @@ It means that the function is overloaded - + New opcode is {} bytes long but old opcode is only {} bytes long This will cause an overflow, proceed? - + {} isn't a valid expression - + Log File of PID {} - + Contents of {} (only last {} bytes are shown) - + ON - + OFF - + LOGGING: {} - + Unable to read log file at {} - + Go to Settings->Debug to enable logging - + Invalid Regex - + Here's some useful regex examples: call|rax --> search for opcodes that contain call or rax [re]cx --> search for both rcx and ecx @@ -2320,148 +2301,148 @@ Use the char \ to escape special chars such as [ - + Copy Addresses - + Copy Offset - + Copy Path - + Start Inizio - + Currently scanning region: - + Cancel Annulla - + Scan finished - + Scan was canceled - + Please stop the process first - + Select at least one region - + You need to dissect code first Proceed? - + Waiting for breakpoint to trigger - + Tracing has been canceled - + Tracing has been completed - + Exact - + Increased - + Increased by - + Decreased - + Decreased by - + Less Than - + More Than - + Between - + Changed - + Unchanged - + Unknown Value - + Basic - + Normal - + Read+Write - + Full diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index cddcce7d..6e486c31 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -51,8 +51,8 @@ #:tag:GDBInformation #:doc: -# A dictionary. Holds breakpoint addresses and what to do on hit -# Format: {address1:on_hit1, address2:on_hit2, ...} +# A dictionary. Holds breakpoint numbers and what to do on hit +# Format: {bp_num1:on_hit1, bp_num2:on_hit2, ...} breakpoint_on_hit_dict = {} #:tag:GDBInformation @@ -200,8 +200,6 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, time0 = time() if not gdb_initialized: raise type_defs.GDBInitializeException - if inferior_status is type_defs.INFERIOR_STATUS.INFERIOR_RUNNING and not control: - raise type_defs.InferiorRunningException gdb_output = "" if send_with_file: send_file = SysUtils.get_ipc_from_pince_file(currentpid) @@ -279,45 +277,40 @@ def state_observe_thread(): Should be called by creating a thread. Usually called in initialization process by attach function """ - def check_inferior_status(cache=None): - if cache: - data = cache - else: - data = child.before - matches = common_regexes.gdb_state_observe.findall(data) + def check_inferior_status(): + matches = common_regexes.gdb_state_observe.findall(child.before) if len(matches) > 0: global stop_reason global inferior_status - - if matches[-1][0]: # stopped + old_status = inferior_status + stop_info = matches[-1][0] + if stop_info: + bp_num = common_regexes.breakpoint_number.search(stop_info) + if bp_num and breakpoint_on_hit_dict[bp_num.group(1)] != type_defs.BREAKPOINT_ON_HIT.BREAK: + return stop_reason = type_defs.STOP_REASON.DEBUG inferior_status = type_defs.INFERIOR_STATUS.INFERIOR_STOPPED else: inferior_status = type_defs.INFERIOR_STATUS.INFERIOR_RUNNING - with status_changed_condition: - status_changed_condition.notify_all() + if old_status != inferior_status: + with status_changed_condition: + status_changed_condition.notify_all() global child global gdb_output - stored_output = "" try: while True: child.expect_exact("\r\n") # A new line for TTY devices child.before = child.before.strip() if not child.before: continue - stored_output += "\n" + child.before - if child.before == "(gdb)": - check_inferior_status(stored_output) - stored_output = "" - continue + check_inferior_status() command_file = re.escape(SysUtils.get_gdb_command_file(currentpid)) if common_regexes.gdb_command_source(command_file).search(child.before): child.expect_exact("(gdb)") child.before = child.before.strip() check_inferior_status() gdb_output = child.before - stored_output = "" with gdb_waiting_for_prompt_condition: gdb_waiting_for_prompt_condition.notify_all() if gdb_output_mode.command_output: @@ -330,15 +323,6 @@ def check_inferior_status(cache=None): print("Exiting state_observe_thread") -def execute_with_temporary_interruption(func): - """Decorator version of execute_func_temporary_interruption""" - - def wrapper(*args, **kwargs): - execute_func_temporary_interruption(func, *args, **kwargs) - - return wrapper - - #:tag:GDBCommunication def execute_func_temporary_interruption(func, *args, **kwargs): """Interrupts the inferior before executing the given function, continues inferior's execution after calling the @@ -357,12 +341,10 @@ def execute_func_temporary_interruption(func, *args, **kwargs): old_status = inferior_status if old_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: interrupt_inferior(type_defs.STOP_REASON.PAUSE) + wait_for_stop() result = func(*args, **kwargs) if old_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - try: - continue_inferior() - except type_defs.InferiorRunningException: - pass + continue_inferior() return result @@ -410,7 +392,7 @@ def interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): if currentpid == -1: return global stop_reason - send_command("c", control=True) + send_command("interrupt") wait_for_stop() stop_reason = interrupt_reason @@ -420,25 +402,25 @@ def continue_inferior(): """Continue the inferior""" if currentpid == -1: return - send_command("c") + send_command("c&") #:tag:Debug def step_instruction(): """Step one assembly instruction""" - send_command("stepi") + send_command("stepi&") #:tag:Debug def step_over_instruction(): """Step over one assembly instruction""" - send_command("nexti") + send_command("nexti&") #:tag:Debug def execute_till_return(): """Continues inferior till current stack frame returns""" - send_command("finish") + send_command("finish&") #:tag:Debug @@ -675,8 +657,6 @@ def toggle_attach(): """ if currentpid == -1: return - if inferior_status==type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - interrupt_inferior(type_defs.STOP_REASON.PAUSE) if is_attached(): if common_regexes.gdb_error.search(send_command("phase-out")): return @@ -756,18 +736,7 @@ def read_pointer(pointer_type): value_index = type_defs.VALUE_INDEX.INDEX_INT32 else: value_index = type_defs.VALUE_INDEX.INDEX_INT64 - - try: - start_address = examine_expression(pointer_type.base_address).address - except type_defs.InferiorRunningException: - if type(pointer_type.base_address) == str: - try: - start_address = int(pointer_type.base_address, 16) - except ValueError: - start_address = 0 - else: - start_address = pointer_type.base_address - + start_address = examine_expression(pointer_type.base_address).address try: with memory_handle() as mem_handle: final_address = deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) @@ -784,7 +753,6 @@ def read_pointer(pointer_type): final_address = offset_address except OSError: final_address = start_address - return final_address @@ -1400,13 +1368,8 @@ def get_breakpoint_info(): address = SysUtils.extract_address(what) if not address: address = examine_expression(what).address - try: - int_address = int(address, 16) - except ValueError: - on_hit = type_defs.on_hit_to_text_dict.get(type_defs.BREAKPOINT_ON_HIT.BREAK) - else: - on_hit_dict_value = breakpoint_on_hit_dict.get(int_address, type_defs.BREAKPOINT_ON_HIT.BREAK) - on_hit = type_defs.on_hit_to_text_dict.get(on_hit_dict_value, "Unknown") + on_hit_dict_value = breakpoint_on_hit_dict.get(number, type_defs.BREAKPOINT_ON_HIT.BREAK) + on_hit = type_defs.on_hit_to_text_dict.get(on_hit_dict_value, "Unknown") if breakpoint_type.find("breakpoint") >= 0: size = 1 else: @@ -1499,8 +1462,9 @@ def add_breakpoint(expression, breakpoint_type=type_defs.BREAKPOINT_TYPE.HARDWAR output = send_command("break *" + str_address) if common_regexes.breakpoint_created.search(output): global breakpoint_on_hit_dict - breakpoint_on_hit_dict[int(str_address, 16)] = on_hit - return common_regexes.breakpoint_number.search(output).group(1) + number = common_regexes.breakpoint_number.search(output).group(1) + breakpoint_on_hit_dict[number] = on_hit + return number else: return @@ -1549,7 +1513,8 @@ def add_watchpoint(expression, length=4, watchpoint_type=type_defs.WATCHPOINT_TY breakpoint_length = max_length else: breakpoint_length = remaining_length - output = send_command(watch_command + " * (char[" + str(breakpoint_length) + "] *) " + hex(str_address_int)) + cmd = f"{watch_command} * (char[{breakpoint_length}] *) {hex(str_address_int)}" + output = execute_func_temporary_interruption(send_command, cmd) if common_regexes.breakpoint_created.search(output): breakpoint_addresses.append([str_address_int, breakpoint_length]) else: @@ -1558,7 +1523,7 @@ def add_watchpoint(expression, length=4, watchpoint_type=type_defs.WATCHPOINT_TY breakpoint_number = common_regexes.breakpoint_number.search(output).group(1) breakpoints_set.append(breakpoint_number) global breakpoint_on_hit_dict - breakpoint_on_hit_dict[str_address_int] = on_hit + breakpoint_on_hit_dict[breakpoint_number] = on_hit remaining_length -= max_length str_address_int += max_length global chained_breakpoints @@ -1668,10 +1633,10 @@ def delete_breakpoint(expression): breakpoint_number = found_breakpoint.number global breakpoint_on_hit_dict try: - del breakpoint_on_hit_dict[breakpoint[0]] + del breakpoint_on_hit_dict[breakpoint_number] except KeyError: pass - send_command("delete " + str(breakpoint_number)) + send_command("delete " + breakpoint_number) return True @@ -1695,7 +1660,7 @@ def track_watchpoint(expression, length, watchpoint_type): for breakpoint in breakpoints: send_command("commands " + breakpoint + "\npince-get-track-watchpoint-info " + str(breakpoints) - + "\nc" + + "\nc&" + "\nend") return breakpoints @@ -1746,7 +1711,7 @@ def track_breakpoint(expression, register_expressions): return send_command("commands " + breakpoint + "\npince-get-track-breakpoint-info " + register_expressions.replace(" ", "") + "," + breakpoint - + "\nc" + + "\nc&" + "\nend") return breakpoint diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index b27f1138..9a07d10d 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -15,14 +15,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from re import compile, VERBOSE +from re import compile, VERBOSE, MULTILINE # The comments near regular expressions shows the expected gdb output, hope it helps to the future developers # --------------------------------------------GDB_Engine---------------------------------------------------------------- -# stopped-threads="all" # *running,thread-id="all" -gdb_state_observe = compile(r"(stopped)-threads=\"all\"|\*(running),thread-id=\"all\"") +gdb_state_observe = compile(r"^\*(stopped.+)|^\*(running)", MULTILINE) gdb_error = compile(r"\^error") hex_plain = compile(r"[0-9a-fA-F]+") hex_number = compile(r"0x" + hex_plain.pattern) diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index f9b5a08a..3467d93d 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -382,7 +382,7 @@ def invoke(self, arg, from_tty): status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "") pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: - gdb.execute("c") + gdb.execute("c&") class InitSoFile(gdb.Command): diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 42ca4c1c..674fc068 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -392,11 +392,6 @@ class SCAN_SCOPE: gdb_output_mode = collections.namedtuple("gdb_output_mode", "async_output command_output command_info") -class InferiorRunningException(Exception): - def __init__(self, message="Inferior is running"): - super(InferiorRunningException, self).__init__(message) - - class GDBInitializeException(Exception): def __init__(self, message="GDB not initialized"): super(GDBInitializeException, self).__init__(message) diff --git a/tr/tr.py b/tr/tr.py index bdd05684..274dfa69 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -19,9 +19,6 @@ def translate(): UNCHANGED_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Unchanged") ERROR = QT_TR_NOOP("Error") GDB_INIT = QT_TR_NOOP("GDB isn't initialized yet") - PROCESS_RUNNING = QT_TR_NOOP("Process is running\n" - "Press {} to stop process\n" - "\nGo to Settings->General to disable this dialog") GDB_INIT_ERROR = QT_TR_NOOP("Unable to initialize GDB\n" "You might want to reinstall GDB or use the system GDB\n" "To change the current GDB path, check Settings->Debug") @@ -106,15 +103,14 @@ def translate(): SEPARATE_PROCESSES_WITH = QT_TR_NOOP("Separate processes with {}") SELECT_GDB_BINARY = QT_TR_NOOP("Select the gdb binary") QUIT_SESSION_CRASH = QT_TR_NOOP("Quitting current session will crash PINCE") - INFERIOR_RUNNING = QT_TR_NOOP("Inferior is running") + CONT_SESSION_CRASH = QT_TR_NOOP("Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior") GDB_CONSOLE_INIT = QT_TR_NOOP( "Hotkeys:\n" - "----------------------------\n" - "Send=Enter |\n" - "Send ctrl+c=Ctrl+C |\n" - "Multi-line mode=Ctrl+Enter |\n" - "Complete command=Tab |\n" - "----------------------------\n" + "-----------------------------\n" + "Send: Enter |\n" + "Multi-line mode: Ctrl+Enter |\n" + "Complete command: Tab |\n" + "-----------------------------\n" "Commands:\n" "----------------------------------------------------------\n" "/clear: Clear the console |\n" @@ -128,8 +124,8 @@ def translate(): "# CLI output mode doesn't work very well with .so extensions, use MI output mode instead |\n" "---------------------------------------------------------------------------------------------------\n" "You can change the output mode from bottom right\n" - "Note: Changing output mode only affects commands sent. Any other output coming from " - "external sources(e.g async output) will be shown in MI format") + "Changing output mode only affects commands sent. Any other output coming from external sources" + "(e.g async output) will be shown in MI format") BREAK = QT_TR_NOOP("Break[{}]") RUN = QT_TR_NOOP("Run[{}]") TOGGLE_ATTACH = QT_TR_NOOP("Toggle Attach[{}]") From d6357f095a472085a043789b1bf2e7a82ac0ce9f Mon Sep 17 00:00:00 2001 From: detiam Date: Tue, 1 Aug 2023 08:36:21 +0800 Subject: [PATCH 214/487] Add zh_CN in compile_ts.sh --- compile_ts.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compile_ts.sh b/compile_ts.sh index c8a1dfe2..f994e987 100755 --- a/compile_ts.sh +++ b/compile_ts.sh @@ -1 +1,5 @@ -pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts i18n/ts/it_IT.ts +#!/bin/bash +langlist="it_IT zh_CN" +for lang in $langlist; do + pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts i18n/ts/"$lang".ts +done \ No newline at end of file From 4b4fa6a7c6830da2b2d5d97728dd286ae3b4ae76 Mon Sep 17 00:00:00 2001 From: detiam Date: Tue, 1 Aug 2023 08:37:05 +0800 Subject: [PATCH 215/487] Update zh_CN translation --- i18n/ts/zh_CN.ts | 2546 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2546 insertions(+) create mode 100644 i18n/ts/zh_CN.ts diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts new file mode 100644 index 00000000..b0399df0 --- /dev/null +++ b/i18n/ts/zh_CN.ts @@ -0,0 +1,2546 @@ + + + + + Dialog + + + Add Address Manually + 手动添加地址 + + + + Base Address: + 基址: + + + + Add Offset + 添加偏移量 + + + + Remove Offset + 移除偏移量 + + + + + Pointer + 指针 + + + + Type: + 类型: + + + + + Zero-Terminated + 以零终止 + + + + + Length + 长度 + + + + + + Address: + 地址: + + + + Description: + 备注: + + + + Dissect Code + 分析代码 + + + + Regions + 区域 + + + + Path + 路径 + + + + Selected regions will be scanned + 选中区域将会被扫描 + + + + Currently scanning range: + 当前扫描范围: + + + + String references found: + 找到的 字符串引用: + + + + Jumps found: + 找到的 跳转: + + + + Calls found: + 找到的 调用: + + + + Entries that can't be decoded as utf-8 won't be included in referenced strings +Unchecking it makes ReferencedStringsWidget load slower but allows you to examine non-string pointers on it + 无法解码为 UTF-8 的条目将不会包含在引用的字符串中 +取消勾选此选项会导致 ReferencedStringsWidget 加载变慢,但允许你检查其中的非字符串指针 + + + + Discard invalid strings + 丢弃无效的字符串 + + + + Edit Instruction + 编辑指令 + + + + Instruction: + 指令: + + + + Multiple entries are separated with ; + 多个条目用分号(;)分隔 + + + + Type + 类型 + + + + Select the new type + 选择一个新类型 + + + + + Handle Signals + 处理信号 + + + + Signal + 信号 + + + + Ignore + 忽略 + + + + Hex Edit + 十六进制编辑 + + + + Length: + 长度: + + + + Refresh + 刷新 + + + + + Dialog + 对话框 + + + + Processing + 处理中 + + + + Cancel + 取消 + + + + Settings + 设置 + + + + General + 通用 + + + + Hotkeys + 快捷键 + + + + Code Injection + 代码注入 + + + + Disassemble + 反汇编 + + + + Debug + 调试 + + + + Auto-update address table + 自动更新地址表 + + + + Update Interval + 更新间隔 + + + + Freeze Interval + 冻结间隔 + + + + Show a MessageBox on InferiorRunning and GDBInitialize exceptions + 出现 "InferiorRunning" 和 "GDBInitialize" 异常时显示一个消息框 + + + + GDB output: + GDB 输出: + + + + Async + 异步 + + + + Command + 命令 + + + + Command info + 命令信息 + + + + On start, automatically attach to processes with name matching one of the entries +Patterns at former positions have higher priority if regex is off + 启动时,自动附加到名称与其中一个条目匹配的进程 +如果正则表达式关闭,靠前的条目有更高的优先级 + + + + Auto-attach on start + 启动时自动附加到 + + + + Regex + 正则表达式 + + + + Logo + 图标 + + + + Functions + 功能 + + + + Hotkey + 快捷键 + + + + Clear + 清除 + + + + Code injection method: + 代码注入模式: + + + + Simp&le dlopen call + 简单的 dlopen 调用[&l] + + + + Advanced In&jection + 高级注入[&j] + + + + Bring disassemble screen to front when the inferior is stopped + 在程序(inferior)停止运行时,将反汇编(disassemble)屏幕置于前台显示 + + + + Instructions shown per scroll + 每次滚动时显示的指令数量 + + + + GDB Path + GDB 路径 + + + + GDB Logging + GDB 日志记录 + + + + Reset Settings + 重置设置 + + + + Hit Esc to cancel and Ctrl+Enter to accept + 按 Esc 取消,按 Ctrl+Enter 接受 + + + + Parameters for tracing + 用于追踪的参数 + + + + Number of the instructions that'll be traced + 将被追踪的指令数量 + + + + Max trace count(1 or greater): + 最大追踪次数(1 或更多): + + + + Tracing will start if this condition is met + 如果满足此条件,将开始追踪 + + + + Trigger condition(Optional, gdb expression): + 触发条件(可选,gdb表达式): + + + + Tracing will stop whenever this condition is met + 每当满足此条件时,追踪将停止 + + + + Stop condition(Optional, gdb expression): + 停止条件(可选,gdb表达式): + + + + Step over instead of single step + 步过(Step over)而不是单步 + + + + Stop when tracing ends + 当追踪结束时停止 + + + + Collect general registers + 收集通用(general)寄存器 + + + + Collect flag registers + 收集标志(flag)寄存器 + + + + Collect segment registers + 收集段(segment)寄存器 + + + + Collect float registers + 收集浮点(float)寄存器 + + + + Select an address to track + 选择要跟踪的地址 + + + + Pointed Address + 指向的地址 + + + + Form + + + Bookmarks + 书签 + + + + Bookmarked Addresses + 书签地址 + + + + + Info + 信息 + + + + Comment + 注解 + + + + GDB Console + GDB 控制台 + + + + Send + 发送 + + + + Send ctrl+c + 发送 Ctrl+C + + + + CLI + CLI + + + + MI + MI + + + + Examine Referrers + 检查引用来源 + + + + + + + + Enter a string or a python regex + 输入字符串或 Python 正则表达式 + + + + + + + + Ignore case if checked + 如果选中则忽略大小写 + + + + + + + + Case sensitive + 大小写敏感 + + + + + + + Your string will be treated as a regex if checked + 如果选中,你的字符串将被视为正则表达式 + + + + + + + + Regex + 正则 + + + + + + + + Search(Enter) + 搜索(Enter) + + + + Functions + 函数 + + + + + + + + + + Address + 地址 + + + + Symbol + 符号 + + + + Enter the regex. Leave blank to see all functions + 请输入正则表达式。如果不输入任何内容,则会显示所有函数 + + + + libpince Reference + libpince 引用 + + + + + Search + 搜索 + + + + type_defs(Type Definitions) + type_defs(类型定义) + + + + + + + Value + + + + + Item Name + 条目名 + + + + Source File + 源文件 + + + + Resources(Mouse-over items to see docstrings) + 资源(将鼠标悬停在项目上以查看文档字符串) + + + + Hide type_defs + 隐藏 type_defs + + + + + + + Form + 表格 + + + + + TextLabel + 文本标签 + + + + Memory Regions + 内存区域 + + + + Regions + 区域 + + + + Perms + 权限 + + + + Offset + 偏移量 + + + + Path + 路径 + + + + Referenced Calls + 引用的调用 + + + + + Refcount + 引用计数 + + + + Referenced Strings and Values + 引用的字符串和值 + + + + Restore Instructions + 还原指令 + + + + Original OpCode + 原始操作码 + + + + Original Instruction + 原始指令 + + + + Search for Opcodes + 搜索操作码 + + + + Start + 开始 + + + + End + 结束 + + + + Opcodes + 操作码 + + + + StackTrace Information + 堆栈跟踪信息 + + + + Return Address + 返回地址 + + + + Cancel + 取消 + + + + + Stop + 停止 + + + + + Count + 计数 + + + + Source + + + + + Try changing combobox index if the 'Value' part of table still isn't updated + 如果表中“值”的内容仍未更新,请尝试更改组合框(ComboBox)的索引 + + + + Refresh + 刷新 + + + + MainWindow + + + Freeze + 冻结 + + + + Freeze the value + 冻结这个值 + + + + Description + 备注 + + + + + Address + 地址 + + + + Type + 类型 + + + + + Value + + + + + Memory View + 内存查看器 + + + + Copy selected items to the address table + 将所选项目复制到地址表 + + + + Erase all the table contents + 删除地址表中所有内容 + + + + Refresh the address table[R] + 刷新地址表[R] + + + + Add Address Manually + 手动添加地址 + + + + Create or attach to a process + 创建或附加到进程 + + + + Open a cheat table + 打开一个PCT文件 + + + + Save current table to a file + 将当前表保存到文件 + + + + Wiki + 文档 + + + + About + 关于 + + + + No Process Selected + 未附加到任何进程 + + + + Open a gdb console + 打开一个 GDB 控制台 + + + + Configure options + 配置选项 + + + + Match count: 0 + 匹配次数:0 + + + + Previous + 先前的值 + + + + First Scan + 首次扫描 + + + + Next Scan + 再次扫描 + + + + Undo Scan + 撤销扫描 + + + + B&its + 比特[&i] + + + + &Decimal + 数字[&D] + + + + Hex + 十六进制 + + + + Scan Type: + 扫描类型: + + + + Value Type: + 值类型: + + + + Scan Scope: + 扫描范围: + + + + Please select a Process + 请选择一个进程 + + + + Name of the Process: + 进程名称: + + + + PID + PID + + + + Username + 用户名 + + + + Process Name + 进程名称 + + + + Attach to the selected process + 附加到选中进程 + + + + + Open + 打开 + + + + Cancel + 取消 + + + + Open an executable + 打开一个可执行程序 + + + + Create Process[F1] + 创建进程[F1] + + + + Tracer + 追踪器 + + + + File + 文件 + + + + Save + 保存 + + + + Save as a text file + 保存为文本文件 + + + + MainWindow_MemoryView + + + Memory Viewer + 内存查看器 + + + + + + Address + 地址 + + + + Bytes + 字节 + + + + Opcodes + 操作码 + + + + Comment + 注解 + + + + Registers + 寄存器(Registers) + + + + Flags + 状态标志(Flags) + + + + Segment Registers + 段(Segment)寄存器 + + + + Show Float Registers + 显示浮点(Float)寄存器 + + + + Return Address + 返回地址 + + + + Frame Address + 帧地址 + + + + Value + + + + + Points to + 指向 + + + + V&iew + 视图[&i] + + + + &Debug + 调试[&D] + + + + &Tools + 工具[&T] + + + + Fi&le + 文件[&l] + + + + Help + 帮助 + + + + &Bookmarks + 书签[&B] + + + + &StackTrace Info + 堆栈跟踪信息[&S] + + + + &Inject .so file + 注入 .so 文件[&I] + + + + &Break + 中断[&B] + + + + &Run + 运行[&R] + + + + &Step[F7] + 步进[&S][F7] + + + + Step &Over[F8] + 步过[&O][F8] + + + + &Execute Till Return[Shift+F8] + 执行直到返回[&E][Shift+F8] + + + + &Toggle Breakpoint[F5] + 切换断点[&T][F5] + + + + B&reakpoints + 断点[&r] + + + + &Functions + 函数[&F] + + + + Set Address[Shift+F4] + 设置地址[Shift+F4] + + + + &Call Function + 调用函数[&C] + + + + &Load Trace + 加载追踪[&L] + + + + &libpince + &libpince + + + + &GDB Log File + &GDB 日志文件 + + + + &Search Opcode + 搜索操作码[&S] + + + + &Memory Regions + 内存区域[&M] + + + + &Dissect Code + 分析代码[&D] + + + + R&eferenced Strings + 引用的字符串[&e] + + + + Referenced &Calls + 引用的调用[&C] + + + + To&ggle Attach + 切换附加​​[&g] + + + + Restore Instructions + 还原指令 + + + + TabWidget + + + About PINCE + 关于 PINCE + + + + Contributors + 贡献者 + + + + License + 许可 + + + + Breakpoints + 断点 + + + + Interactive + 交互 + + + + No + No + + + + Type + 类型 + + + + Disp + 显示 + + + + Enabled + 启用 + + + + Address + 地址 + + + + Size + 大小 + + + + On Hit + 命中时 + + + + Hit Count + 命中计数 + + + + Condition + 条件 + + + + Raw + 原始 + + + + Floating Point Registers + 浮点寄存器 + + + + + Register + 寄存器 + + + + + Value + + + + + TranslationConstants + + + Pause the process + 暂停进程 + + + + Break the process + 中断进程 + + + + Continue the process + 继续进程 + + + + Toggle attach/detach + 切换附加/分离 + + + + Next Scan - Exact + 再次扫描 - 精确 + + + + Next Scan - Increased + 再次扫描 - 增加 + + + + Next Scan - Decreased + 再次扫描 - 减少 + + + + Next Scan - Changed + 再次扫描 - 改变 + + + + Next Scan - Unchanged + 再次扫描 - 未变 + + + + Error + 错误 + + + + GDB isn't initialized yet + GDB 尚未初始化 + + + + Process is running +Press {} to stop process + +Go to Settings->General to disable this dialog + 进程正在运行 +按 {} 停止进程 + +转到 “设置” -> “通用” 以禁用此对话框 + + + + Unable to initialize GDB +You might want to reinstall GDB or use the system GDB +To change the current GDB path, check Settings->Debug + 无法初始化 GDB +你可能想重新安装 GDB 或者使用系统 GDB +要更改当前 GDB 路径,请检查 “设置” -> “调试” + + + + Edit + 编辑 + + + + Show as hexadecimal + 显示为十六进制 + + + + Show as decimal + 显示为十进制 + + + + Show as unsigned + 显示为无符号数 + + + + Show as signed + 显示为有符号数 + + + + Toggle selected records + 切换选定的记录 + + + + Freeze + 冻结 + + + + Default + 默认 + + + + Incremental + 递增 + + + + Decremental + 递减 + + + + Browse this memory region + 浏览此内存区域 + + + + Disassemble this address + 反汇编这个地址 + + + + Cut selected records + 剪切选定的记录 + + + + Copy selected records + 复制选定的记录 + + + + Cut selected records (recursive) + 剪切选定的记录(递归) + + + + Copy selected records (recursive) + 复制选定的记录(递归) + + + + Paste selected records before + 在之前粘贴选定的记录 + + + + Paste selected records after + 在之后粘贴选定的记录 + + + + Paste selected records inside + 在之中粘贴选定的记录 + + + + Delete selected records + 删除选定的记录 + + + + Find out what writes to this address + 找出是什么写入了这个地址 + + + + Find out what reads this address + 找出是什么读取了这个地址 + + + + Find out what accesses this address + 找出是什么访问了这个地址 + + + + Invalid clipboard content + 剪贴板内容无效 + + + + New Scan + 新的扫描 + + + + Match count: {} ({} shown) + 匹配次数:{}(显示了{}个) + + + + Match count: {} + 匹配次数:{} + + + + No Description + 无备注 + + + + Open PCT file(s) + 打开 PCT 文件 + + + + PINCE Cheat Table (*.pct);;All files (*) + PINCE 作弊表 (*.pct);;所有文件 (*) + + + + Clear address table? + 清除地址表? + + + + File {} is inaccessible or contains invalid content + 文件 {} 无法访问或包含无效的内容 + + + + Save PCT file + 保存 PCT 文件 + + + + Cannot save to file + 无法保存为文件 + + + + Nice try, smartass + 好会试,聪明屁股 + + + + Selected process is not valid + 所选进程无效 + + + + You're debugging this process already + 你已经在调试这个进程了 + + + + That process is already being traced by {}, could not attach to the process + 此进程已被 {} 追踪,无法附加到此进程 + + + + Permission denied, could not attach to the process + 请求被拒,无法附加到此进程 + + + + An error occurred while trying to create process + 尝试创建进程时发生错误 + + + + Scan for + 在这里输入扫描内容 + + + + First Scan + 首次扫描 + + + + No Process Selected + 未附加到任何进程 + + + + [detached] + [已分离] + + + + [stopped] + [已停止] + + + + Enter the new value + 输入新值 + + + + Enter the new description + 输入新备注 + + + + Edit Address + 编辑地址 + + + + Please select a process first + 请先选择一个进程 + + + + Select the target binary + 选择目标二进制文件 + + + + Enter the optional arguments + 输入可选参数 + + + + LD_PRELOAD .so path (optional) + LD_PRELOAD .so 路径(可选) + + + + Refresh + 刷新 + + + + Length is not valid + 长度无效 + + + + Length must be greater than 0 + 长度必须大于0 + + + + Can't parse the input + 无法解析输入 + + + + Update interval must be an int + 更新间隔必须是 int + + + + Freeze interval must be an int + 冻结间隔必须是 int + + + + Instruction count must be an int + 指令计数必须是 int + + + + Instruction count cannot be lower than {} + 指令计数不能低于 {} + + + + Interval cannot be a negative number + 间隔不能为负数 + + + + You are asking for it, aren't you? + 这是你自找的,不是吗? + + + + Update interval should be bigger than {} ms +Setting update interval less than {} ms may cause slowdown +Proceed? + 更新间隔应大于 {} 毫秒 +将更新间隔设置为小于 {} 毫秒可能会导致速度变慢 +继续? + + + + {} isn't a valid regex + {} 非有效正则表达式 + + + + You have changed the GDB path, reset GDB now? + 你已经更改了 GDB 路径,现在重置 GDB 吗? + + + + This will reset to the default settings +Proceed? + 这将会重置设置为默认 +继续? + + + + Mouse over on this text for examples + 将鼠标悬停在此文本上查看示例 + + + + asdf|qwer --> search for asdf or qwer +[as]df --> search for both adf and sdf +Use the char \ to escape special chars such as [ +\[asdf\] --> search for opcodes that contain [asdf] + asdf|qwer --> 搜索 asdf 或 qwer +[as]df --> 搜索 adf 和 sdf +使用字符 \ 转义特殊字符,如 [ +\[asdf\] --> 搜索包含 [asdf] 的操作码 + + + + Separate processes with {} + 使用 {} 分隔进程 + + + + Select the gdb binary + 选择 GDB 的可执行文件 + + + + Quitting current session will crash PINCE + 退出当前会话会导致 PINCE 崩溃 + + + + Inferior is running + 被调试进程正在运行 + + + + Hotkeys: +---------------------------- +Send=Enter | +Send ctrl+c=Ctrl+C | +Multi-line mode=Ctrl+Enter | +Complete command=Tab | +---------------------------- +Commands: +---------------------------------------------------------- +/clear: Clear the console | +phase-out: Detach from the current process | +phase-in: Attach back to the previously detached process | +--------------------------------------------------------------------------------------------------- +pince-init-so-file so_file_path: Initializes 'lib' variable | +pince-get-so-file-information: Get information about current lib | +pince-execute-from-so-file lib.func(params): Execute a function from lib | +# Check https://github.com/korcankaraokcu/PINCE/wiki#extending-pince-with-so-files for an example | +# CLI output mode doesn't work very well with .so extensions, use MI output mode instead | +--------------------------------------------------------------------------------------------------- +You can change the output mode from bottom right +Note: Changing output mode only affects commands sent. Any other output coming from external sources(e.g async output) will be shown in MI format + 快捷键: +---------------------------- +发送 = Enter | +发送 ctrl+c = Ctrl+C | +多行模式 = Ctrl+Enter | +补全命令 = Tab | +---------------------------- +Commands: +---------------------------------------------------------- +/clear: 清空控制台 | +phase-out: 分离当前进程 | +phase-in: 重新附加上一个分离的进程 | +--------------------------------------------------------------------------------------------------- +pince-init-so-file so_file_path:初始化 'lib' 变量 | +pince-get-so-file-information:获得当前 lib 的信息 | +pince-execute-from-so-file lib.func(params):运行 lib 中的一个函数 | +# 查看 https://github.com/korcankaraokcu/PINCE/wiki#extending-pince-with-so-files 获取示例 | +# CLI 输出模式与 .so 扩展兼容不佳, 请改用 MI 输出模式 | +--------------------------------------------------------------------------------------------------- +你可以在右下角切换输出模式 +提示:更改输出模式仅影响命令的发送。来自外部源的任何其他输出(例如异步输出)将以 MI 格式显示 + + + + Break[{}] + 中断[{}] + + + + Run[{}] + 运行[{}] + + + + Toggle Attach[{}] + 切换附加[{}] + + + + Failed to set breakpoint at address {} + 在地址 {} 处设置断点失败 + + + + Enter the watchpoint length in size of bytes + 输入监视点长度,以字节为单位 + + + + {} can't be parsed as an integer + {} 无法解析为整数 + + + + Breakpoint length can't be lower than {} + 断点长度不能小于 {} + + + + Failed to set watchpoint at address {} + 无法在地址 {} 设置监视点 + + + + Copy to Clipboard + 复制到剪切板 + + + + Go to expression + 跳转到表达式 + + + + Add this address to address list + 添加此地址到地址列表 + + + + Set Watchpoint + 设置监视点 + + + + Write Only + 仅写入 + + + + Read Only + 仅读取 + + + + Both + 两者都 + + + + Add/Change condition for breakpoint + 添加/更改断点条件 + + + + Delete Breakpoint + 删除断点 + + + + Enter the expression + 输入表达式 + + + + {} is invalid + {} 无效 + + + + Protection:{} | Base:{}-{} | Module:{} + 保护:{} | 基础:{}-{} | 模块:{} + + + + Invalid Region + 无效的区域 + + + + Cannot access memory at expression {} + 无法访问表达式 {} 处的内存 + + + + Referenced by: + 引用自: + + + + Press 'Ctrl+E' to see a detailed list of referrers + 按下 'Ctrl+E' 可以查看引用来源的详细列表 + + + + Memory Viewer - Paused + 内存查看器 - 已暂停 + + + + Memory Viewer - Currently debugging {} + 内存查看器 - 正调试 {} + + + + Memory Viewer - Running + 内存查看器 - 运行中 + + + + Enter the expression for condition, for instance: + +$eax==0x523 +$rax>0 && ($rbp<0 || $rsp==0) +printf($r10)==3 + 输入条件表达式,例如: + +$eax==0x523 +$rax>0 && ($rbp<0 || $rsp==0) +printf($r10)==3 + + + + Failed to set condition for address {} +Check terminal for details + 无法设置地址 {} 的条件 +检查终端了解详情 + + + + Full Stack + 全栈 + + + + Copy Return Address + 复制返回地址 + + + + Copy Frame Address + 复制帧地址 + + + + Stacktrace + 堆栈跟踪 + + + + Copy Address + 复制地址 + + + + Copy Value + 复制值 + + + + Copy Points to + 复制指向 + + + + Disassemble 'value' pointer address + 反汇编 '值' 指针地址 + + + + Show 'value' pointer in HexView + 在十六进制视图中显示 '值' 指针 + + + + Back + 后退 + + + + Show this address in HexView + 在十六进制视图中显示这个地址 + + + + Follow + 跟踪 + + + + Examine Referrers + 检查引用来源 + + + + Bookmark this address + 添加此地址到书签 + + + + Delete this bookmark + 删除此书签 + + + + Change comment + 更改注解 + + + + Go to bookmarked address + 跳转到已添加书签的地址 + + + + Toggle Breakpoint + 切换断点 + + + + Edit instruction + 编辑指令 + + + + Replace instruction with NOPs + 用 NOPs 替换指令 + + + + Find out which addresses this instruction accesses + 找出此指令访问的地址 + + + + Break and trace instructions + 中断并跟踪指令 + + + + Dissect this region + 分析此区域 + + + + Copy Bytes + 复制字节 + + + + Copy Opcode + 复制操作码 + + + + Copy Comment + 复制注解 + + + + Copy All + 复制全部 + + + + Enter the register expression(s) you want to track +Register names must start with $ +Each expression must be separated with a comma + +For instance: +Let's say the instruction is mov [rax+rbx],30 +Then you should enter $rax+$rbx +So PINCE can track address [rax+rbx] + +Another example: +If you enter $rax,$rbx*$rcx+4,$rbp +PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] + 请输入你想要追踪的寄存器表达式 +寄存器名称必须以$开头 +每个表达式必须用逗号分隔 + +例如: +假设指令是 mov [rax+rbx],30 +那么你应该输入 $rax+$rbx +这样 PINCE 就可以追踪地址 [rax+rbx] + +另一个例子: +如果你输入 $rax,$rbx*$rcx+4,$rbp +PINCE 将追踪地址 [rax],[rbx*rcx+4] 和 [rbp] + + + + This address has already been bookmarked + 这个地址已经被添加到书签了 + + + + Enter the comment for bookmarked address + 输入已书签地址的注解 + + + + Select the .so file + 选择 .so 文件 + + + + Shared object library (*.so) + 共享对象库 (*.so) + + + + Success + 成功 + + + + The file has been injected + 此文件已被注入 + + + + Failed to inject the .so file + 注入 .so 文件失败 + + + + Enter the expression for the function that'll be called from the inferior +You can view functions list from View->Functions + +For instance: +Calling printf("1234") will yield something like this +↓ +$28 = 4 + +$28 is the assigned convenience variable +4 is the result +You can use the assigned variable from the GDB Console + 请输入从被调试程序(inferior)中将要调用的函数表达式 +你可以从 视图 -> 函数 查看函数列表 + +例如: +调用 printf("1234") 将产生类似下面的结果 +↓ +$28 = 4 + +$28 是分配的便利变量 +4 是函数调用的结果 +你可以从 GDB 控制台中使用分配的变量 + + + + Failed to call the expression {} + 调用表达式 {} 失败 + + + + Invalid expression or address + 无效的表达式或地址 + + + + Invalid entries detected, refreshing the page + 检测到无效条目,正在刷新页面 + + + + Add new entry + 添加新条目 + + + + Delete + 删除 + + + + Enter the new value of register {} + 输入寄存器{}的新值 + + + + Restore this instruction + 还原此指令 + + + + Enter the hit count({} or higher) + 输入命中计数({}或更高) + + + + Hit count must be an integer + 命中计数必须是整数 + + + + Hit count can't be lower than {} + 命中计数不能少于 {} + + + + Change condition + 更改条件 + + + + Enable + 开启 + + + + Disable + 关闭 + + + + Disable after hit + 命中后关闭 + + + + Disable after X hits + 命中 X 次后关闭 + + + + Delete after hit + 命中后删除 + + + + Opcodes writing to the address {} + 写入地址 {} 的操作码 + + + + Opcodes reading from the address {} + 读取地址 {} 的操作码 + + + + Opcodes accessing to the address {} + 访问地址 {} 的操作码 + + + + Unable to track watchpoint at expression {} + 无法追踪表达式 {} 处的监视点 + + + + Unable to delete watchpoint at expression {} + 无法删除表达式 {} 处的监视点 + + + + Close + 关闭 + + + + Addresses accessed by instruction {} + 指令 {} 访问的地址 + + + + Unable to track breakpoint at expression {} + 无法跟踪表达式 {} 处的断点 + + + + Accessed by {} + 访问自 {} + + + + Unable to delete breakpoint at expression {} + 无法删除表达式 {} 处的断点 + + + + Max trace count must be greater than or equal to {} + 最大追踪次数必须大或等于 {} + + + + Processing the collected data + 处理收集的数据 + + + + Save trace file + 保存追踪文件 + + + + Trace File (*.trace);;All Files (*) + 追踪文件 (*.trace);;所有文件 (*) + + + + Open trace file + 打开追踪文件 + + + + Expand All + 展开全部 + + + + Collapse All + 收起全部 + + + + DEFINED + 定义 + + + + This symbol is defined. You can use its body as a gdb expression. For instance: + +void func(param) can be used as 'func' as a gdb expression + 该符号已定义。您可以将其作为 GDB 表达式使用其主体。例如: + +void func(param) 可以作为 'func' 作为 GDB 表达式使用 + + + + Copy Symbol + 复制符号 + + + + Here's some useful regex tips: +^quaso --> search for everything that starts with quaso +[ab]cd --> search for both acd and bcd + + How to interpret symbols: +A symbol that looks like 'func(param)@plt' consists of 3 pieces +func, func(param), func(param)@plt +These 3 functions will have different addresses +@plt means this function is a subroutine for the original one +There can be more than one of the same function +It means that the function is overloaded + 以下是一些有用的正则表达式提示: +^quaso --> 搜索以 quaso 开头的所有内容 +[ab]cd --> 搜索同时包含 acd 和 bcd 的内容 + + 如何解释符号: +一个看起来像 'func(param)@plt' 的符号由三个部分组成: +func, func(param), func(param)@plt +这三个函数将有不同的地址 +@plt 表示该函数是原始函数的一个子程序 +同一个函数可能有多个 +这意味着函数是重载的 + + + + New opcode is {} bytes long but old opcode is only {} bytes long +This will cause an overflow, proceed? + 新的操作码长度为 {} 字节,但旧的操作码只有 {} 字节长 +这将导致溢出,是否继续? + + + + {} isn't a valid expression + {} 不是有效的表达式 + + + + Log File of PID {} + PID {} 的日志文件 + + + + Contents of {} (only last {} bytes are shown) + {} 的内容(仅显示最后 {} 字节) + + + + ON + + + + + OFF + + + + + LOGGING: {} + 日志: {} + + + + Unable to read log file at {} + 无法读取位于 {} 的日志文件 + + + + Go to Settings->Debug to enable logging + 请转到“设置”->“调试”以启用日志记录 + + + + Invalid Regex + 无效的正则表达式 + + + + Here's some useful regex examples: +call|rax --> search for opcodes that contain call or rax +[re]cx --> search for both rcx and ecx +Use the char \ to escape special chars such as [ +\[rsp\] --> search for opcodes that contain [rsp] + 这里有一些有用的正则表达式示例: +call|rax --> 搜索包含 call 或 rax 的操作码 +[re]cx --> 搜索 rcx 和 ecx +使用字符 \ 转义特殊字符,如 [ +\[rsp\] --> 搜索包含 [rsp] 的操作码 + + + + Copy Addresses + 复制地址 + + + + Copy Offset + 复制偏移量 + + + + Copy Path + 复制路径 + + + + Start + 开始 + + + + Currently scanning region: + 当前扫描区域: + + + + Cancel + 取消 + + + + Scan finished + 扫描完成 + + + + Scan was canceled + 扫描被取消了 + + + + Please stop the process first + 请先停止此进程 + + + + Select at least one region + 选中至少一个区域 + + + + You need to dissect code first +Proceed? + 你需要先分析代码 +是否继续? + + + + Waiting for breakpoint to trigger + 等待断点被触发 + + + + Tracing has been canceled + 追踪已取消 + + + + Tracing has been completed + 追踪已完成 + + + + Exact + 精确 + + + + Increased + 增加 + + + + Increased by + 增加自 + + + + Decreased + 减少 + + + + Decreased by + 减少自 + + + + Less Than + 少于 + + + + More Than + 多于 + + + + Between + 介于 + + + + Changed + 改变 + + + + Unchanged + 未变 + + + + Unknown Value + 未知值 + + + + Basic + 基础 + + + + Normal + 正常 + + + + Read+Write + 读+写 + + + + Full + 全部 + + + From f1d9471dd251bb1f04ee83b2c47dbb419689f8cf Mon Sep 17 00:00:00 2001 From: detiam Date: Tue, 1 Aug 2023 22:08:12 +0800 Subject: [PATCH 216/487] Update any .ts file in 'i18n/ts' if valid --- compile_ts.sh | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/compile_ts.sh b/compile_ts.sh index f994e987..5bbead93 100755 --- a/compile_ts.sh +++ b/compile_ts.sh @@ -1,5 +1,26 @@ #!/bin/bash -langlist="it_IT zh_CN" -for lang in $langlist; do - pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts i18n/ts/"$lang".ts -done \ No newline at end of file +file_supportlocale='/usr/share/i18n/SUPPORTED' +list_ts=$(find i18n/ts -maxdepth 1 -type f -name '*.ts') + +if [[ -e $file_supportlocale ]]; then + for ts in $list_ts; do + # Check if the locale is valid + if grep -E "^$(basename "$ts" .ts)(.)?.*\s.*" "$file_supportlocale" > /dev/null 2>&1; then + # Remove empty file to prevent error + # "invalid translation file: no element found: line 1, column 0" + [[ -s $ts ]] || rm "$ts" + pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts "$ts" + else + list_invalidts="$list_invalidts $ts" + fi + done +else + echo "file $file_supportlocale not exist, aborting" + exit 2 +fi + +if [[ -n $list_invalidts ]]; then + echo + echo -e "ERROR: The following locales are invalid, please check: \n $list_invalidts" + exit 1 +fi From 8fba4fe3427b803fba2b7cd64b948a5d2ded3e69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 2 Aug 2023 18:51:33 +0300 Subject: [PATCH 217/487] Remove unused INFERIOR_STOPPED check --- PINCE.py | 3 - i18n/ts/it_IT.ts | 43 ++-- i18n/ts/zh_CN.ts | 499 +++++++++++++++++++++-------------------------- tr/tr.py | 1 - 4 files changed, 245 insertions(+), 301 deletions(-) diff --git a/PINCE.py b/PINCE.py index 42ef6953..5a0fecf8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -5449,9 +5449,6 @@ def pushButton_StartCancel_clicked(self): self.label_ScanInfo.setText(tr.SCAN_CANCELED) self.init_pre_scan_gui() else: - if not GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: - QMessageBox.information(self, tr.ERROR, tr.STOP_PROCESS) - return selected_rows = self.tableWidget_ExecutableMemoryRegions.selectionModel().selectedRows() if not selected_rows: QMessageBox.information(self, tr.ERROR, tr.SELECT_ONE_REGION) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 04438be4..d03199c3 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -2342,107 +2342,102 @@ Use the char \ to escape special chars such as [ - Please stop the process first - - - - Select at least one region - + You need to dissect code first Proceed? - + Waiting for breakpoint to trigger - + Tracing has been canceled - + Tracing has been completed - + Exact - + Increased - + Increased by - + Decreased - + Decreased by - + Less Than - + More Than - + Between - + Changed - + Unchanged - + Unknown Value - + Basic - + Normal - + Read+Write - + Full diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index b0399df0..25a4e4af 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -443,11 +443,6 @@ Patterns at former positions have higher priority if regex is off Send 发送 - - - Send ctrl+c - 发送 Ctrl+C - CLI @@ -691,12 +686,6 @@ Patterns at former positions have higher priority if regex is off Cancel 取消 - - - - Stop - 停止 - @@ -709,9 +698,10 @@ Patterns at former positions have higher priority if regex is off + - Try changing combobox index if the 'Value' part of table still isn't updated - 如果表中“值”的内容仍未更新,请尝试更改组合框(ComboBox)的索引 + Stop + 停止 @@ -1309,17 +1299,6 @@ Patterns at former positions have higher priority if regex is off - Process is running -Press {} to stop process - -Go to Settings->General to disable this dialog - 进程正在运行 -按 {} 停止进程 - -转到 “设置” -> “通用” 以禁用此对话框 - - - Unable to initialize GDB You might want to reinstall GDB or use the system GDB To change the current GDB path, check Settings->Debug @@ -1328,317 +1307,317 @@ To change the current GDB path, check Settings->Debug 要更改当前 GDB 路径,请检查 “设置” -> “调试” - + Edit 编辑 - + Show as hexadecimal 显示为十六进制 - + Show as decimal 显示为十进制 - + Show as unsigned 显示为无符号数 - + Show as signed 显示为有符号数 - + Toggle selected records 切换选定的记录 - + Freeze 冻结 - + Default 默认 - + Incremental 递增 - + Decremental 递减 - + Browse this memory region 浏览此内存区域 - + Disassemble this address 反汇编这个地址 - + Cut selected records 剪切选定的记录 - + Copy selected records 复制选定的记录 - + Cut selected records (recursive) 剪切选定的记录(递归) - + Copy selected records (recursive) 复制选定的记录(递归) - + Paste selected records before 在之前粘贴选定的记录 - + Paste selected records after 在之后粘贴选定的记录 - + Paste selected records inside 在之中粘贴选定的记录 - + Delete selected records 删除选定的记录 - + Find out what writes to this address 找出是什么写入了这个地址 - + Find out what reads this address 找出是什么读取了这个地址 - + Find out what accesses this address 找出是什么访问了这个地址 - + Invalid clipboard content 剪贴板内容无效 - + New Scan 新的扫描 - + Match count: {} ({} shown) 匹配次数:{}(显示了{}个) - + Match count: {} 匹配次数:{} - + No Description 无备注 - + Open PCT file(s) 打开 PCT 文件 - + PINCE Cheat Table (*.pct);;All files (*) PINCE 作弊表 (*.pct);;所有文件 (*) - + Clear address table? 清除地址表? - + File {} is inaccessible or contains invalid content 文件 {} 无法访问或包含无效的内容 - + Save PCT file 保存 PCT 文件 - + Cannot save to file 无法保存为文件 - + Nice try, smartass 好会试,聪明屁股 - + Selected process is not valid 所选进程无效 - + You're debugging this process already 你已经在调试这个进程了 - + That process is already being traced by {}, could not attach to the process 此进程已被 {} 追踪,无法附加到此进程 - + Permission denied, could not attach to the process 请求被拒,无法附加到此进程 - + An error occurred while trying to create process 尝试创建进程时发生错误 - + Scan for 在这里输入扫描内容 - + First Scan 首次扫描 - + No Process Selected 未附加到任何进程 - + [detached] [已分离] - + [stopped] [已停止] - + Enter the new value 输入新值 - + Enter the new description 输入新备注 - + Edit Address 编辑地址 - + Please select a process first 请先选择一个进程 - + Select the target binary 选择目标二进制文件 - + Enter the optional arguments 输入可选参数 - + LD_PRELOAD .so path (optional) LD_PRELOAD .so 路径(可选) - + Refresh 刷新 - + Length is not valid 长度无效 - + Length must be greater than 0 长度必须大于0 - + Can't parse the input 无法解析输入 - + Update interval must be an int 更新间隔必须是 int - + Freeze interval must be an int 冻结间隔必须是 int - + Instruction count must be an int 指令计数必须是 int - + Instruction count cannot be lower than {} 指令计数不能低于 {} - + Interval cannot be a negative number 间隔不能为负数 - + You are asking for it, aren't you? 这是你自找的,不是吗? - + Update interval should be bigger than {} ms Setting update interval less than {} ms may cause slowdown Proceed? @@ -1647,29 +1626,29 @@ Proceed? 继续? - + {} isn't a valid regex {} 非有效正则表达式 - + You have changed the GDB path, reset GDB now? 你已经更改了 GDB 路径,现在重置 GDB 吗? - + This will reset to the default settings Proceed? 这将会重置设置为默认 继续? - + Mouse over on this text for examples 将鼠标悬停在此文本上查看示例 - + asdf|qwer --> search for asdf or qwer [as]df --> search for both adf and sdf Use the char \ to escape special chars such as [ @@ -1680,34 +1659,33 @@ Use the char \ to escape special chars such as [ \[asdf\] --> 搜索包含 [asdf] 的操作码 - + Separate processes with {} 使用 {} 分隔进程 - + Select the gdb binary 选择 GDB 的可执行文件 - + Quitting current session will crash PINCE 退出当前会话会导致 PINCE 崩溃 - - Inferior is running - 被调试进程正在运行 + + Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior + - + Hotkeys: ----------------------------- -Send=Enter | -Send ctrl+c=Ctrl+C | -Multi-line mode=Ctrl+Enter | -Complete command=Tab | ----------------------------- +----------------------------- +Send: Enter | +Multi-line mode: Ctrl+Enter | +Complete command: Tab | +----------------------------- Commands: ---------------------------------------------------------- /clear: Clear the console | @@ -1721,166 +1699,146 @@ pince-execute-from-so-file lib.func(params): Execute a function from lib # CLI output mode doesn't work very well with .so extensions, use MI output mode instead | --------------------------------------------------------------------------------------------------- You can change the output mode from bottom right -Note: Changing output mode only affects commands sent. Any other output coming from external sources(e.g async output) will be shown in MI format - 快捷键: ----------------------------- -发送 = Enter | -发送 ctrl+c = Ctrl+C | -多行模式 = Ctrl+Enter | -补全命令 = Tab | ----------------------------- -Commands: ----------------------------------------------------------- -/clear: 清空控制台 | -phase-out: 分离当前进程 | -phase-in: 重新附加上一个分离的进程 | ---------------------------------------------------------------------------------------------------- -pince-init-so-file so_file_path:初始化 'lib' 变量 | -pince-get-so-file-information:获得当前 lib 的信息 | -pince-execute-from-so-file lib.func(params):运行 lib 中的一个函数 | -# 查看 https://github.com/korcankaraokcu/PINCE/wiki#extending-pince-with-so-files 获取示例 | -# CLI 输出模式与 .so 扩展兼容不佳, 请改用 MI 输出模式 | ---------------------------------------------------------------------------------------------------- -你可以在右下角切换输出模式 -提示:更改输出模式仅影响命令的发送。来自外部源的任何其他输出(例如异步输出)将以 MI 格式显示 +Changing output mode only affects commands sent. Any other output coming from external sources(e.g async output) will be shown in MI format + - + Break[{}] 中断[{}] - + Run[{}] 运行[{}] - + Toggle Attach[{}] 切换附加[{}] - + Failed to set breakpoint at address {} 在地址 {} 处设置断点失败 - + Enter the watchpoint length in size of bytes 输入监视点长度,以字节为单位 - + {} can't be parsed as an integer {} 无法解析为整数 - + Breakpoint length can't be lower than {} 断点长度不能小于 {} - + Failed to set watchpoint at address {} 无法在地址 {} 设置监视点 - + Copy to Clipboard 复制到剪切板 - + Go to expression 跳转到表达式 - + Add this address to address list 添加此地址到地址列表 - + Set Watchpoint 设置监视点 - + Write Only 仅写入 - + Read Only 仅读取 - + Both 两者都 - + Add/Change condition for breakpoint 添加/更改断点条件 - + Delete Breakpoint 删除断点 - + Enter the expression 输入表达式 - + {} is invalid {} 无效 - + Protection:{} | Base:{}-{} | Module:{} 保护:{} | 基础:{}-{} | 模块:{} - + Invalid Region 无效的区域 - + Cannot access memory at expression {} 无法访问表达式 {} 处的内存 - + Referenced by: 引用自: - + Press 'Ctrl+E' to see a detailed list of referrers 按下 'Ctrl+E' 可以查看引用来源的详细列表 - + Memory Viewer - Paused 内存查看器 - 已暂停 - + Memory Viewer - Currently debugging {} 内存查看器 - 正调试 {} - + Memory Viewer - Running 内存查看器 - 运行中 - + Enter the expression for condition, for instance: $eax==0x523 @@ -1893,149 +1851,149 @@ $rax>0 && ($rbp<0 || $rsp==0) printf($r10)==3 - + Failed to set condition for address {} Check terminal for details 无法设置地址 {} 的条件 检查终端了解详情 - + Full Stack 全栈 - + Copy Return Address 复制返回地址 - + Copy Frame Address 复制帧地址 - + Stacktrace 堆栈跟踪 - + Copy Address 复制地址 - + Copy Value 复制值 - + Copy Points to 复制指向 - + Disassemble 'value' pointer address 反汇编 '值' 指针地址 - + Show 'value' pointer in HexView 在十六进制视图中显示 '值' 指针 - + Back 后退 - + Show this address in HexView 在十六进制视图中显示这个地址 - + Follow 跟踪 - + Examine Referrers 检查引用来源 - + Bookmark this address 添加此地址到书签 - + Delete this bookmark 删除此书签 - + Change comment 更改注解 - + Go to bookmarked address 跳转到已添加书签的地址 - + Toggle Breakpoint 切换断点 - + Edit instruction 编辑指令 - + Replace instruction with NOPs 用 NOPs 替换指令 - + Find out which addresses this instruction accesses 找出此指令访问的地址 - + Break and trace instructions 中断并跟踪指令 - + Dissect this region 分析此区域 - + Copy Bytes 复制字节 - + Copy Opcode 复制操作码 - + Copy Comment 复制注解 - + Copy All 复制全部 - + Enter the register expression(s) you want to track Register names must start with $ Each expression must be separated with a comma @@ -2062,42 +2020,42 @@ PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] PINCE 将追踪地址 [rax],[rbx*rcx+4] 和 [rbp] - + This address has already been bookmarked 这个地址已经被添加到书签了 - + Enter the comment for bookmarked address 输入已书签地址的注解 - + Select the .so file 选择 .so 文件 - + Shared object library (*.so) 共享对象库 (*.so) - + Success 成功 - + The file has been injected 此文件已被注入 - + Failed to inject the .so file 注入 .so 文件失败 - + Enter the expression for the function that'll be called from the inferior You can view functions list from View->Functions @@ -2122,177 +2080,177 @@ $28 是分配的便利变量 你可以从 GDB 控制台中使用分配的变量 - + Failed to call the expression {} 调用表达式 {} 失败 - + Invalid expression or address 无效的表达式或地址 - + Invalid entries detected, refreshing the page 检测到无效条目,正在刷新页面 - + Add new entry 添加新条目 - + Delete 删除 - + Enter the new value of register {} 输入寄存器{}的新值 - + Restore this instruction 还原此指令 - + Enter the hit count({} or higher) 输入命中计数({}或更高) - + Hit count must be an integer 命中计数必须是整数 - + Hit count can't be lower than {} 命中计数不能少于 {} - + Change condition 更改条件 - + Enable 开启 - + Disable 关闭 - + Disable after hit 命中后关闭 - + Disable after X hits 命中 X 次后关闭 - + Delete after hit 命中后删除 - + Opcodes writing to the address {} 写入地址 {} 的操作码 - + Opcodes reading from the address {} 读取地址 {} 的操作码 - + Opcodes accessing to the address {} 访问地址 {} 的操作码 - + Unable to track watchpoint at expression {} 无法追踪表达式 {} 处的监视点 - + Unable to delete watchpoint at expression {} 无法删除表达式 {} 处的监视点 - + Close 关闭 - + Addresses accessed by instruction {} 指令 {} 访问的地址 - + Unable to track breakpoint at expression {} 无法跟踪表达式 {} 处的断点 - + Accessed by {} 访问自 {} - + Unable to delete breakpoint at expression {} 无法删除表达式 {} 处的断点 - + Max trace count must be greater than or equal to {} 最大追踪次数必须大或等于 {} - + Processing the collected data 处理收集的数据 - + Save trace file 保存追踪文件 - + Trace File (*.trace);;All Files (*) 追踪文件 (*.trace);;所有文件 (*) - + Open trace file 打开追踪文件 - + Expand All 展开全部 - + Collapse All 收起全部 - + DEFINED 定义 - + This symbol is defined. You can use its body as a gdb expression. For instance: void func(param) can be used as 'func' as a gdb expression @@ -2301,12 +2259,12 @@ void func(param) can be used as 'func' as a gdb expression void func(param) 可以作为 'func' 作为 GDB 表达式使用 - + Copy Symbol 复制符号 - + Here's some useful regex tips: ^quaso --> search for everything that starts with quaso [ab]cd --> search for both acd and bcd @@ -2331,59 +2289,59 @@ func, func(param), func(param)@plt 这意味着函数是重载的 - + New opcode is {} bytes long but old opcode is only {} bytes long This will cause an overflow, proceed? 新的操作码长度为 {} 字节,但旧的操作码只有 {} 字节长 这将导致溢出,是否继续? - + {} isn't a valid expression {} 不是有效的表达式 - + Log File of PID {} PID {} 的日志文件 - + Contents of {} (only last {} bytes are shown) {} 的内容(仅显示最后 {} 字节) - + ON - + OFF - + LOGGING: {} 日志: {} - + Unable to read log file at {} 无法读取位于 {} 的日志文件 - + Go to Settings->Debug to enable logging 请转到“设置”->“调试”以启用日志记录 - + Invalid Regex 无效的正则表达式 - + Here's some useful regex examples: call|rax --> search for opcodes that contain call or rax [re]cx --> search for both rcx and ecx @@ -2396,149 +2354,144 @@ call|rax --> 搜索包含 call 或 rax 的操作码 \[rsp\] --> 搜索包含 [rsp] 的操作码 - + Copy Addresses 复制地址 - + Copy Offset 复制偏移量 - + Copy Path 复制路径 - + Start 开始 - + Currently scanning region: 当前扫描区域: - + Cancel 取消 - + Scan finished 扫描完成 - + Scan was canceled 扫描被取消了 - - Please stop the process first - 请先停止此进程 - - - + Select at least one region 选中至少一个区域 - + You need to dissect code first Proceed? 你需要先分析代码 是否继续? - + Waiting for breakpoint to trigger 等待断点被触发 - + Tracing has been canceled 追踪已取消 - + Tracing has been completed 追踪已完成 - + Exact 精确 - + Increased 增加 - + Increased by 增加自 - + Decreased 减少 - + Decreased by 减少自 - + Less Than 少于 - + More Than 多于 - + Between 介于 - + Changed 改变 - + Unchanged 未变 - + Unknown Value 未知值 - + Basic 基础 - + Normal 正常 - + Read+Write 读+写 - + Full 全部 diff --git a/tr/tr.py b/tr/tr.py index 274dfa69..6d568c31 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -287,7 +287,6 @@ def translate(): CANCEL = QT_TR_NOOP("Cancel") SCAN_FINISHED = QT_TR_NOOP("Scan finished") SCAN_CANCELED = QT_TR_NOOP("Scan was canceled") - STOP_PROCESS = QT_TR_NOOP("Please stop the process first") SELECT_ONE_REGION = QT_TR_NOOP("Select at least one region") DISSECT_CODE = QT_TR_NOOP("You need to dissect code first\n" "Proceed?") From a1abc9c5da4c155dc22b1c2ec5aaf25cd6ad701d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 2 Aug 2023 19:34:48 +0300 Subject: [PATCH 218/487] Make compile_ts POSIX compatible --- compile_ts.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compile_ts.sh b/compile_ts.sh index 5bbead93..fdc0efaa 100755 --- a/compile_ts.sh +++ b/compile_ts.sh @@ -2,13 +2,13 @@ file_supportlocale='/usr/share/i18n/SUPPORTED' list_ts=$(find i18n/ts -maxdepth 1 -type f -name '*.ts') -if [[ -e $file_supportlocale ]]; then +if [ -e "$file_supportlocale" ]; then for ts in $list_ts; do # Check if the locale is valid if grep -E "^$(basename "$ts" .ts)(.)?.*\s.*" "$file_supportlocale" > /dev/null 2>&1; then # Remove empty file to prevent error # "invalid translation file: no element found: line 1, column 0" - [[ -s $ts ]] || rm "$ts" + [ -s "$ts" ] || rm "$ts" pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts "$ts" else list_invalidts="$list_invalidts $ts" @@ -19,8 +19,9 @@ else exit 2 fi -if [[ -n $list_invalidts ]]; then +if [ -n "$list_invalidts" ]; then echo - echo -e "ERROR: The following locales are invalid, please check: \n $list_invalidts" + echo "ERROR: The following locales are invalid, please check:" + echo "$list_invalidts" exit 1 fi From fcbff7958e0f948fb1109d3283170d18c4d394ef Mon Sep 17 00:00:00 2001 From: Berk Date: Thu, 3 Aug 2023 04:04:42 +0300 Subject: [PATCH 219/487] Update scanmem submodule --- .gitmodules | 6 +++--- libscanmem-PINCE | 1 + scanmem | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) create mode 160000 libscanmem-PINCE delete mode 160000 scanmem diff --git a/.gitmodules b/.gitmodules index 979d6037..9e555db3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "scanmem"] - path = scanmem - url = https://github.com/brkzlr/scanmem-PINCE +[submodule "libscanmem-PINCE"] + path = libscanmem-PINCE + url = https://github.com/brkzlr/libscanmem-PINCE diff --git a/libscanmem-PINCE b/libscanmem-PINCE new file mode 160000 index 00000000..b2f5e048 --- /dev/null +++ b/libscanmem-PINCE @@ -0,0 +1 @@ +Subproject commit b2f5e048aeee778ba7fa3436552076921eb3c1fb diff --git a/scanmem b/scanmem deleted file mode 160000 index 8b0d9e88..00000000 --- a/scanmem +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8b0d9e889c5449c0a585428f414251a9ceac8844 From f375f1b2f7097487a0f47378fddddda18bfecb27 Mon Sep 17 00:00:00 2001 From: Berk Date: Thu, 3 Aug 2023 04:06:55 +0300 Subject: [PATCH 220/487] Update installer script for scanmem. Remove unused dependencies --- install_pince.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index abe104a4..dc8e2464 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -51,7 +51,7 @@ exit_on_error() { compile_scanmem() { sh autogen.sh || return 1 ./configure --prefix="$(pwd)" || return 1 - make -j"$NUM_MAKE_JOBS" libscanmem.la || return 1 + make -j"$NUM_MAKE_JOBS" || return 1 chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file return 0 } @@ -118,11 +118,11 @@ ask_pkg_mgr() { } # About xcb packages -> https://github.com/cdgriffith/FastFlix/wiki/Common-questions-and-problems -PKG_NAMES_ALL="python3-pip gdb libtool intltool" -PKG_NAMES_DEBIAN="$PKG_NAMES_ALL libreadline-dev python3-dev python3-venv pkg-config qt6-l10n-tools libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" -PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc readline-devel python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" -PKG_NAMES_FEDORA="$PKG_NAMES_ALL readline-devel python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" -PKG_NAMES_ARCH="python-pip qt6-tools readline intltool gdb lsb-release" # arch defaults to py3 nowadays +PKG_NAMES_ALL="python3-pip gdb libtool" +PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-dev python3-venv pkg-config qt6-l10n-tools libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" +PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" +PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" +PKG_NAMES_ARCH="python-pip qt6-tools gdb lsb-release" # arch defaults to py3 nowadays PKG_NAMES_PIP="pyqt6 pexpect distorm3 keystone-engine pygdbmi keyboard pygobject" INSTALL_COMMAND="install" From 42f153a03ebd299bc6d7ee78a1160b6177c3dbd0 Mon Sep 17 00:00:00 2001 From: Berk Date: Thu, 3 Aug 2023 04:11:44 +0300 Subject: [PATCH 221/487] Installer scanmem naming changes --- install_pince.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index dc8e2464..c8045f24 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -17,7 +17,7 @@ along with this program. If not, see . ' # this file cannot (or any file) be named `install.sh` since libtoolize(automake) will not work properly if it does -# it will create the necessary files in PINCEs directory instead of scanmems, which will result in having to run `sh autogen.sh` +# it will create the necessary files in PINCEs directory instead of libscanmem's, which will result in having to run `sh autogen.sh` # twice, see this link https://github.com/protocolbuffers/protobuf/issues/149#issuecomment-473092810 if [ "$(id -u)" = "0" ]; then @@ -47,8 +47,8 @@ exit_on_error() { fi } -# assumes you're in scanmem directory -compile_scanmem() { +# assumes you're in libscanmem directory +compile_libscanmem() { sh autogen.sh || return 1 ./configure --prefix="$(pwd)" || return 1 make -j"$NUM_MAKE_JOBS" || return 1 @@ -56,8 +56,8 @@ compile_scanmem() { return 0 } -install_scanmem() { - echo "Downloading scanmem" +install_libscanmem() { + echo "Downloading libscanmem" git submodule update --init --recursive || return 1 if [ ! -d "libpince/libscanmem" ]; then @@ -65,20 +65,20 @@ install_scanmem() { chown -R "${CURRENT_USER}":"${CURRENT_USER}" libpince/libscanmem fi ( - echo "Entering scanmem" - cd scanmem || return 1 + echo "Entering libscanmem directory" + cd libscanmem-PINCE || return 1 if [ -d "./.libs" ]; then - echo "Recompile scanmem? [y/n]" + echo "Recompile libscanmem? [y/n]" read -r answer if echo "$answer" | grep -iq "^[Yy]"; then - compile_scanmem || return 1 + compile_libscanmem || return 1 fi else - compile_scanmem || return 1 + compile_libscanmem || return 1 fi cp --preserve .libs/libscanmem.so ../libpince/libscanmem/ cp --preserve wrappers/scanmem.py ../libpince/libscanmem - echo "Exiting scanmem" + echo "Exiting libscanmem directory" ) || return 1 return 0 } @@ -198,7 +198,7 @@ fi # shellcheck disable=SC2086 pip3 install ${PKG_NAMES_PIP} || exit_on_error -install_scanmem || exit_on_error +install_libscanmem || exit_on_error compile_translations || exit_on_error From 7eb6e738e07066c43f477c712d30b7ecb0123a9a Mon Sep 17 00:00:00 2001 From: Berk Date: Thu, 3 Aug 2023 04:15:00 +0300 Subject: [PATCH 222/487] Libscanmem repo update --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index b2f5e048..df002428 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit b2f5e048aeee778ba7fa3436552076921eb3c1fb +Subproject commit df002428b0ad779a5f7467911d8baf65eebae44a From 81992577d4a3fdd8290f9225d4e6209e72b39fa1 Mon Sep 17 00:00:00 2001 From: Berk Date: Thu, 3 Aug 2023 04:22:45 +0300 Subject: [PATCH 223/487] Remove noptrace option --- PINCE.py | 1 - 1 file changed, 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 5a0fecf8..49b1fde2 100755 --- a/PINCE.py +++ b/PINCE.py @@ -435,7 +435,6 @@ def __init__(self): # Fails if you for example install it to some place like bin libscanmem_path = os.path.join(os.getcwd(), "libpince", "libscanmem", "libscanmem.so") self.backend = Scanmem(libscanmem_path) - self.backend.send_command("option noptrace 1") self.memory_view_window = MemoryViewWindowForm(self) self.about_widget = AboutWidgetForm() self.await_exit_thread = AwaitProcessExit() From 37ef1b21522920c7fe84841ddbb2ce4240fd9b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 4 Aug 2023 20:30:20 +0300 Subject: [PATCH 224/487] Fix line information to 0 to keep git history clean --- compile_ts.sh | 1 + fix_ts.py | 23 +++ i18n/ts/it_IT.ts | 452 +++++++++++++++++++++++------------------------ i18n/ts/zh_CN.ts | 452 +++++++++++++++++++++++------------------------ 4 files changed, 476 insertions(+), 452 deletions(-) create mode 100644 fix_ts.py diff --git a/compile_ts.sh b/compile_ts.sh index fdc0efaa..ba6468fa 100755 --- a/compile_ts.sh +++ b/compile_ts.sh @@ -10,6 +10,7 @@ if [ -e "$file_supportlocale" ]; then # "invalid translation file: no element found: line 1, column 0" [ -s "$ts" ] || rm "$ts" pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts "$ts" + python3 fix_ts.py "$ts" else list_invalidts="$list_invalidts $ts" fi diff --git a/fix_ts.py b/fix_ts.py new file mode 100644 index 00000000..3212307a --- /dev/null +++ b/fix_ts.py @@ -0,0 +1,23 @@ +import xml.etree.ElementTree as ET +import sys + +file = sys.argv[1] +tree = ET.parse(file, parser=ET.XMLParser(encoding="utf-8")) +root = tree.getroot() + +# Removing line info so updating tr.py affects git history much less +for location in root.findall('.//location'): + location.set('line', '0') + +modified_xml = ET.tostring(root, encoding='utf-8', xml_declaration=False).decode() +with open(file, 'r', encoding='utf-8') as f: + original_xml = f.read() + +# These declarations are hardcoded in pylupdate6, make sure everything is correct +declarations = original_xml.split('\n', 2)[:2] +assert declarations[0] == '', 'xml format has changed' +assert declarations[1] == '', 'doctype format has changed' +final_xml = '\n'.join(declarations) + '\n' + modified_xml + '\n' + +with open(file, 'w', encoding='utf-8') as f: + f.write(final_xml) \ No newline at end of file diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index d03199c3..9968bd52 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1241,407 +1241,407 @@ Patterns at former positions have higher priority if regex is off TranslationConstants - + Pause the process - + Break the process - + Continue the process - + Toggle attach/detach - + Next Scan - Exact - + Next Scan - Increased - + Next Scan - Decreased - + Next Scan - Changed - + Next Scan - Unchanged - + Error - + GDB isn't initialized yet - + Unable to initialize GDB You might want to reinstall GDB or use the system GDB To change the current GDB path, check Settings->Debug - + Edit - + Show as hexadecimal - + Show as decimal - + Show as unsigned - + Show as signed - + Toggle selected records - + Freeze - + Default - + Incremental - + Decremental - + Browse this memory region - + Disassemble this address - + Cut selected records - + Copy selected records - + Cut selected records (recursive) - + Copy selected records (recursive) - + Paste selected records before - + Paste selected records after - + Paste selected records inside - + Delete selected records - + Find out what writes to this address - + Find out what reads this address - + Find out what accesses this address - + Invalid clipboard content - + New Scan - + Match count: {} ({} shown) - + Match count: {} - + No Description - + Open PCT file(s) - + PINCE Cheat Table (*.pct);;All files (*) - + Clear address table? - + File {} is inaccessible or contains invalid content - + Save PCT file - + Cannot save to file - + Nice try, smartass - + Selected process is not valid - + You're debugging this process already - + That process is already being traced by {}, could not attach to the process - + Permission denied, could not attach to the process - + An error occurred while trying to create process - + Scan for - + First Scan Prima Ricerca - + No Process Selected Nessun Processo Selezionato - + [detached] - + [stopped] - + Enter the new value - + Enter the new description - + Edit Address - + Please select a process first - + Select the target binary - + Enter the optional arguments - + LD_PRELOAD .so path (optional) - + Refresh - + Length is not valid - + Length must be greater than 0 - + Can't parse the input - + Update interval must be an int - + Freeze interval must be an int - + Instruction count must be an int - + Instruction count cannot be lower than {} - + Interval cannot be a negative number - + You are asking for it, aren't you? - + Update interval should be bigger than {} ms Setting update interval less than {} ms may cause slowdown Proceed? - + {} isn't a valid regex - + You have changed the GDB path, reset GDB now? - + This will reset to the default settings Proceed? - + Mouse over on this text for examples - + asdf|qwer --> search for asdf or qwer [as]df --> search for both adf and sdf Use the char \ to escape special chars such as [ @@ -1649,27 +1649,27 @@ Use the char \ to escape special chars such as [ - + Separate processes with {} - + Select the gdb binary - + Quitting current session will crash PINCE - + Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior - + Hotkeys: ----------------------------- Send: Enter | @@ -1693,142 +1693,142 @@ Changing output mode only affects commands sent. Any other output coming from ex - + Break[{}] - + Run[{}] - + Toggle Attach[{}] - + Failed to set breakpoint at address {} - + Enter the watchpoint length in size of bytes - + {} can't be parsed as an integer - + Breakpoint length can't be lower than {} - + Failed to set watchpoint at address {} - + Copy to Clipboard - + Go to expression - + Add this address to address list - + Set Watchpoint - + Write Only - + Read Only - + Both - + Add/Change condition for breakpoint - + Delete Breakpoint - + Enter the expression - + {} is invalid - + Protection:{} | Base:{}-{} | Module:{} - + Invalid Region - + Cannot access memory at expression {} - + Referenced by: - + Press 'Ctrl+E' to see a detailed list of referrers - + Memory Viewer - Paused - + Memory Viewer - Currently debugging {} - + Memory Viewer - Running - + Enter the expression for condition, for instance: $eax==0x523 @@ -1837,148 +1837,148 @@ printf($r10)==3 - + Failed to set condition for address {} Check terminal for details - + Full Stack - + Copy Return Address - + Copy Frame Address - + Stacktrace - + Copy Address - + Copy Value - + Copy Points to - + Disassemble 'value' pointer address - + Show 'value' pointer in HexView - + Back - + Show this address in HexView - + Follow - + Examine Referrers - + Bookmark this address - + Delete this bookmark - + Change comment - + Go to bookmarked address - + Toggle Breakpoint - + Edit instruction - + Replace instruction with NOPs - + Find out which addresses this instruction accesses - + Break and trace instructions - + Dissect this region - + Copy Bytes - + Copy Opcode - + Copy Comment - + Copy All - + Enter the register expression(s) you want to track Register names must start with $ Each expression must be separated with a comma @@ -1994,42 +1994,42 @@ PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] - + This address has already been bookmarked - + Enter the comment for bookmarked address - + Select the .so file - + Shared object library (*.so) - + Success - + The file has been injected - + Failed to inject the .so file - + Enter the expression for the function that'll be called from the inferior You can view functions list from View->Functions @@ -2044,189 +2044,189 @@ You can use the assigned variable from the GDB Console - + Failed to call the expression {} - + Invalid expression or address - + Invalid entries detected, refreshing the page - + Add new entry - + Delete - + Enter the new value of register {} - + Restore this instruction - + Enter the hit count({} or higher) - + Hit count must be an integer - + Hit count can't be lower than {} - + Change condition - + Enable - + Disable - + Disable after hit - + Disable after X hits - + Delete after hit - + Opcodes writing to the address {} - + Opcodes reading from the address {} - + Opcodes accessing to the address {} - + Unable to track watchpoint at expression {} - + Unable to delete watchpoint at expression {} - + Close - + Addresses accessed by instruction {} - + Unable to track breakpoint at expression {} - + Accessed by {} - + Unable to delete breakpoint at expression {} - + Max trace count must be greater than or equal to {} - + Processing the collected data - + Save trace file - + Trace File (*.trace);;All Files (*) - + Open trace file - + Expand All - + Collapse All - + DEFINED - + This symbol is defined. You can use its body as a gdb expression. For instance: void func(param) can be used as 'func' as a gdb expression - + Copy Symbol - + Here's some useful regex tips: ^quaso --> search for everything that starts with quaso [ab]cd --> search for both acd and bcd @@ -2241,58 +2241,58 @@ It means that the function is overloaded - + New opcode is {} bytes long but old opcode is only {} bytes long This will cause an overflow, proceed? - + {} isn't a valid expression - + Log File of PID {} - + Contents of {} (only last {} bytes are shown) - + ON - + OFF - + LOGGING: {} - + Unable to read log file at {} - + Go to Settings->Debug to enable logging - + Invalid Regex - + Here's some useful regex examples: call|rax --> search for opcodes that contain call or rax [re]cx --> search for both rcx and ecx @@ -2301,143 +2301,143 @@ Use the char \ to escape special chars such as [ - + Copy Addresses - + Copy Offset - + Copy Path - + Start Inizio - + Currently scanning region: - + Cancel Annulla - + Scan finished - + Scan was canceled - + Select at least one region - + You need to dissect code first Proceed? - + Waiting for breakpoint to trigger - + Tracing has been canceled - + Tracing has been completed - + Exact - + Increased - + Increased by - + Decreased - + Decreased by - + Less Than - + More Than - + Between - + Changed - + Unchanged - + Unknown Value - + Basic - + Normal - + Read+Write - + Full diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 25a4e4af..fdc646f3 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1243,62 +1243,62 @@ Patterns at former positions have higher priority if regex is off TranslationConstants - + Pause the process 暂停进程 - + Break the process 中断进程 - + Continue the process 继续进程 - + Toggle attach/detach 切换附加/分离 - + Next Scan - Exact 再次扫描 - 精确 - + Next Scan - Increased 再次扫描 - 增加 - + Next Scan - Decreased 再次扫描 - 减少 - + Next Scan - Changed 再次扫描 - 改变 - + Next Scan - Unchanged 再次扫描 - 未变 - + Error 错误 - + GDB isn't initialized yet GDB 尚未初始化 - + Unable to initialize GDB You might want to reinstall GDB or use the system GDB To change the current GDB path, check Settings->Debug @@ -1307,317 +1307,317 @@ To change the current GDB path, check Settings->Debug 要更改当前 GDB 路径,请检查 “设置” -> “调试” - + Edit 编辑 - + Show as hexadecimal 显示为十六进制 - + Show as decimal 显示为十进制 - + Show as unsigned 显示为无符号数 - + Show as signed 显示为有符号数 - + Toggle selected records 切换选定的记录 - + Freeze 冻结 - + Default 默认 - + Incremental 递增 - + Decremental 递减 - + Browse this memory region 浏览此内存区域 - + Disassemble this address 反汇编这个地址 - + Cut selected records 剪切选定的记录 - + Copy selected records 复制选定的记录 - + Cut selected records (recursive) 剪切选定的记录(递归) - + Copy selected records (recursive) 复制选定的记录(递归) - + Paste selected records before 在之前粘贴选定的记录 - + Paste selected records after 在之后粘贴选定的记录 - + Paste selected records inside 在之中粘贴选定的记录 - + Delete selected records 删除选定的记录 - + Find out what writes to this address 找出是什么写入了这个地址 - + Find out what reads this address 找出是什么读取了这个地址 - + Find out what accesses this address 找出是什么访问了这个地址 - + Invalid clipboard content 剪贴板内容无效 - + New Scan 新的扫描 - + Match count: {} ({} shown) 匹配次数:{}(显示了{}个) - + Match count: {} 匹配次数:{} - + No Description 无备注 - + Open PCT file(s) 打开 PCT 文件 - + PINCE Cheat Table (*.pct);;All files (*) PINCE 作弊表 (*.pct);;所有文件 (*) - + Clear address table? 清除地址表? - + File {} is inaccessible or contains invalid content 文件 {} 无法访问或包含无效的内容 - + Save PCT file 保存 PCT 文件 - + Cannot save to file 无法保存为文件 - + Nice try, smartass 好会试,聪明屁股 - + Selected process is not valid 所选进程无效 - + You're debugging this process already 你已经在调试这个进程了 - + That process is already being traced by {}, could not attach to the process 此进程已被 {} 追踪,无法附加到此进程 - + Permission denied, could not attach to the process 请求被拒,无法附加到此进程 - + An error occurred while trying to create process 尝试创建进程时发生错误 - + Scan for 在这里输入扫描内容 - + First Scan 首次扫描 - + No Process Selected 未附加到任何进程 - + [detached] [已分离] - + [stopped] [已停止] - + Enter the new value 输入新值 - + Enter the new description 输入新备注 - + Edit Address 编辑地址 - + Please select a process first 请先选择一个进程 - + Select the target binary 选择目标二进制文件 - + Enter the optional arguments 输入可选参数 - + LD_PRELOAD .so path (optional) LD_PRELOAD .so 路径(可选) - + Refresh 刷新 - + Length is not valid 长度无效 - + Length must be greater than 0 长度必须大于0 - + Can't parse the input 无法解析输入 - + Update interval must be an int 更新间隔必须是 int - + Freeze interval must be an int 冻结间隔必须是 int - + Instruction count must be an int 指令计数必须是 int - + Instruction count cannot be lower than {} 指令计数不能低于 {} - + Interval cannot be a negative number 间隔不能为负数 - + You are asking for it, aren't you? 这是你自找的,不是吗? - + Update interval should be bigger than {} ms Setting update interval less than {} ms may cause slowdown Proceed? @@ -1626,29 +1626,29 @@ Proceed? 继续? - + {} isn't a valid regex {} 非有效正则表达式 - + You have changed the GDB path, reset GDB now? 你已经更改了 GDB 路径,现在重置 GDB 吗? - + This will reset to the default settings Proceed? 这将会重置设置为默认 继续? - + Mouse over on this text for examples 将鼠标悬停在此文本上查看示例 - + asdf|qwer --> search for asdf or qwer [as]df --> search for both adf and sdf Use the char \ to escape special chars such as [ @@ -1659,27 +1659,27 @@ Use the char \ to escape special chars such as [ \[asdf\] --> 搜索包含 [asdf] 的操作码 - + Separate processes with {} 使用 {} 分隔进程 - + Select the gdb binary 选择 GDB 的可执行文件 - + Quitting current session will crash PINCE 退出当前会话会导致 PINCE 崩溃 - + Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior - + Hotkeys: ----------------------------- Send: Enter | @@ -1703,142 +1703,142 @@ Changing output mode only affects commands sent. Any other output coming from ex - + Break[{}] 中断[{}] - + Run[{}] 运行[{}] - + Toggle Attach[{}] 切换附加[{}] - + Failed to set breakpoint at address {} 在地址 {} 处设置断点失败 - + Enter the watchpoint length in size of bytes 输入监视点长度,以字节为单位 - + {} can't be parsed as an integer {} 无法解析为整数 - + Breakpoint length can't be lower than {} 断点长度不能小于 {} - + Failed to set watchpoint at address {} 无法在地址 {} 设置监视点 - + Copy to Clipboard 复制到剪切板 - + Go to expression 跳转到表达式 - + Add this address to address list 添加此地址到地址列表 - + Set Watchpoint 设置监视点 - + Write Only 仅写入 - + Read Only 仅读取 - + Both 两者都 - + Add/Change condition for breakpoint 添加/更改断点条件 - + Delete Breakpoint 删除断点 - + Enter the expression 输入表达式 - + {} is invalid {} 无效 - + Protection:{} | Base:{}-{} | Module:{} 保护:{} | 基础:{}-{} | 模块:{} - + Invalid Region 无效的区域 - + Cannot access memory at expression {} 无法访问表达式 {} 处的内存 - + Referenced by: 引用自: - + Press 'Ctrl+E' to see a detailed list of referrers 按下 'Ctrl+E' 可以查看引用来源的详细列表 - + Memory Viewer - Paused 内存查看器 - 已暂停 - + Memory Viewer - Currently debugging {} 内存查看器 - 正调试 {} - + Memory Viewer - Running 内存查看器 - 运行中 - + Enter the expression for condition, for instance: $eax==0x523 @@ -1851,149 +1851,149 @@ $rax>0 && ($rbp<0 || $rsp==0) printf($r10)==3 - + Failed to set condition for address {} Check terminal for details 无法设置地址 {} 的条件 检查终端了解详情 - + Full Stack 全栈 - + Copy Return Address 复制返回地址 - + Copy Frame Address 复制帧地址 - + Stacktrace 堆栈跟踪 - + Copy Address 复制地址 - + Copy Value 复制值 - + Copy Points to 复制指向 - + Disassemble 'value' pointer address 反汇编 '值' 指针地址 - + Show 'value' pointer in HexView 在十六进制视图中显示 '值' 指针 - + Back 后退 - + Show this address in HexView 在十六进制视图中显示这个地址 - + Follow 跟踪 - + Examine Referrers 检查引用来源 - + Bookmark this address 添加此地址到书签 - + Delete this bookmark 删除此书签 - + Change comment 更改注解 - + Go to bookmarked address 跳转到已添加书签的地址 - + Toggle Breakpoint 切换断点 - + Edit instruction 编辑指令 - + Replace instruction with NOPs 用 NOPs 替换指令 - + Find out which addresses this instruction accesses 找出此指令访问的地址 - + Break and trace instructions 中断并跟踪指令 - + Dissect this region 分析此区域 - + Copy Bytes 复制字节 - + Copy Opcode 复制操作码 - + Copy Comment 复制注解 - + Copy All 复制全部 - + Enter the register expression(s) you want to track Register names must start with $ Each expression must be separated with a comma @@ -2020,42 +2020,42 @@ PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] PINCE 将追踪地址 [rax],[rbx*rcx+4] 和 [rbp] - + This address has already been bookmarked 这个地址已经被添加到书签了 - + Enter the comment for bookmarked address 输入已书签地址的注解 - + Select the .so file 选择 .so 文件 - + Shared object library (*.so) 共享对象库 (*.so) - + Success 成功 - + The file has been injected 此文件已被注入 - + Failed to inject the .so file 注入 .so 文件失败 - + Enter the expression for the function that'll be called from the inferior You can view functions list from View->Functions @@ -2080,177 +2080,177 @@ $28 是分配的便利变量 你可以从 GDB 控制台中使用分配的变量 - + Failed to call the expression {} 调用表达式 {} 失败 - + Invalid expression or address 无效的表达式或地址 - + Invalid entries detected, refreshing the page 检测到无效条目,正在刷新页面 - + Add new entry 添加新条目 - + Delete 删除 - + Enter the new value of register {} 输入寄存器{}的新值 - + Restore this instruction 还原此指令 - + Enter the hit count({} or higher) 输入命中计数({}或更高) - + Hit count must be an integer 命中计数必须是整数 - + Hit count can't be lower than {} 命中计数不能少于 {} - + Change condition 更改条件 - + Enable 开启 - + Disable 关闭 - + Disable after hit 命中后关闭 - + Disable after X hits 命中 X 次后关闭 - + Delete after hit 命中后删除 - + Opcodes writing to the address {} 写入地址 {} 的操作码 - + Opcodes reading from the address {} 读取地址 {} 的操作码 - + Opcodes accessing to the address {} 访问地址 {} 的操作码 - + Unable to track watchpoint at expression {} 无法追踪表达式 {} 处的监视点 - + Unable to delete watchpoint at expression {} 无法删除表达式 {} 处的监视点 - + Close 关闭 - + Addresses accessed by instruction {} 指令 {} 访问的地址 - + Unable to track breakpoint at expression {} 无法跟踪表达式 {} 处的断点 - + Accessed by {} 访问自 {} - + Unable to delete breakpoint at expression {} 无法删除表达式 {} 处的断点 - + Max trace count must be greater than or equal to {} 最大追踪次数必须大或等于 {} - + Processing the collected data 处理收集的数据 - + Save trace file 保存追踪文件 - + Trace File (*.trace);;All Files (*) 追踪文件 (*.trace);;所有文件 (*) - + Open trace file 打开追踪文件 - + Expand All 展开全部 - + Collapse All 收起全部 - + DEFINED 定义 - + This symbol is defined. You can use its body as a gdb expression. For instance: void func(param) can be used as 'func' as a gdb expression @@ -2259,12 +2259,12 @@ void func(param) can be used as 'func' as a gdb expression void func(param) 可以作为 'func' 作为 GDB 表达式使用 - + Copy Symbol 复制符号 - + Here's some useful regex tips: ^quaso --> search for everything that starts with quaso [ab]cd --> search for both acd and bcd @@ -2289,59 +2289,59 @@ func, func(param), func(param)@plt 这意味着函数是重载的 - + New opcode is {} bytes long but old opcode is only {} bytes long This will cause an overflow, proceed? 新的操作码长度为 {} 字节,但旧的操作码只有 {} 字节长 这将导致溢出,是否继续? - + {} isn't a valid expression {} 不是有效的表达式 - + Log File of PID {} PID {} 的日志文件 - + Contents of {} (only last {} bytes are shown) {} 的内容(仅显示最后 {} 字节) - + ON - + OFF - + LOGGING: {} 日志: {} - + Unable to read log file at {} 无法读取位于 {} 的日志文件 - + Go to Settings->Debug to enable logging 请转到“设置”->“调试”以启用日志记录 - + Invalid Regex 无效的正则表达式 - + Here's some useful regex examples: call|rax --> search for opcodes that contain call or rax [re]cx --> search for both rcx and ecx @@ -2354,144 +2354,144 @@ call|rax --> 搜索包含 call 或 rax 的操作码 \[rsp\] --> 搜索包含 [rsp] 的操作码 - + Copy Addresses 复制地址 - + Copy Offset 复制偏移量 - + Copy Path 复制路径 - + Start 开始 - + Currently scanning region: 当前扫描区域: - + Cancel 取消 - + Scan finished 扫描完成 - + Scan was canceled 扫描被取消了 - + Select at least one region 选中至少一个区域 - + You need to dissect code first Proceed? 你需要先分析代码 是否继续? - + Waiting for breakpoint to trigger 等待断点被触发 - + Tracing has been canceled 追踪已取消 - + Tracing has been completed 追踪已完成 - + Exact 精确 - + Increased 增加 - + Increased by 增加自 - + Decreased 减少 - + Decreased by 减少自 - + Less Than 少于 - + More Than 多于 - + Between 介于 - + Changed 改变 - + Unchanged 未变 - + Unknown Value 未知值 - + Basic 基础 - + Normal 正常 - + Read+Write 读+写 - + Full 全部 From 26505b95c5ccba930abba2b53e174997641155fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 4 Aug 2023 20:46:24 +0300 Subject: [PATCH 225/487] Add console text translation for Chinese --- i18n/ts/zh_CN.ts | 21 ++++++++++++++++++++- tr/tr.py | 4 ++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index fdc646f3..ac2ca7fb 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1700,7 +1700,26 @@ pince-execute-from-so-file lib.func(params): Execute a function from lib --------------------------------------------------------------------------------------------------- You can change the output mode from bottom right Changing output mode only affects commands sent. Any other output coming from external sources(e.g async output) will be shown in MI format - + 快捷键: +---------------------------- +发送 = Enter +多行模式 = Ctrl+Enter +补全命令 = Tab +---------------------------- +Commands: +---------------------------- +/clear: 清空控制台 +phase-out: 分离当前进程 +phase-in: 重新附加上一个分离的进程 +--------------------------------------------------------------------------------------------------- +pince-init-so-file so_file_path:初始化 'lib' 变量 +pince-get-so-file-information:获得当前 lib 的信息 +pince-execute-from-so-file lib.func(params):运行 lib 中的一个函数 +# 查看 https://github.com/korcankaraokcu/PINCE/wiki#extending-pince-with-so-files 获取示例 +# CLI 输出模式与 .so 扩展兼容不佳, 请改用 MI 输出模式 +--------------------------------------------------------------------------------------------------- +你可以在右下角切换输出模式 +更改输出模式仅影响命令的发送。来自外部源的任何其他输出(例如异步输出)将以 MI 格式显示 diff --git a/tr/tr.py b/tr/tr.py index 6d568c31..e45e5933 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -104,6 +104,10 @@ def translate(): SELECT_GDB_BINARY = QT_TR_NOOP("Select the gdb binary") QUIT_SESSION_CRASH = QT_TR_NOOP("Quitting current session will crash PINCE") CONT_SESSION_CRASH = QT_TR_NOOP("Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior") + + # For some languages, it might be hard to keep the pipe characters balanced + # You are free to modify pipes and dashes as you like when translating + # Check Chinese translation for an example GDB_CONSOLE_INIT = QT_TR_NOOP( "Hotkeys:\n" "-----------------------------\n" From f0bdb642953380d9701a69b75335dabe6de61345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 5 Aug 2023 18:58:13 +0300 Subject: [PATCH 226/487] Add language menu --- GUI/SettingsDialog.py | 63 +++++++++++++++++++++++++------------------ GUI/SettingsDialog.ui | 30 ++++++++++++++++++--- PINCE.py | 50 ++++++++++++++++++++++++++-------- i18n/ts/it_IT.ts | 25 +++++++++++++---- i18n/ts/zh_CN.ts | 25 +++++++++++++---- tr/tr.py | 4 ++- 6 files changed, 146 insertions(+), 51 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index f6d166a1..3150cfad 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SettingsDialog.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -135,7 +135,6 @@ def setupUi(self, Dialog): self.horizontalLayout_3.addItem(spacerItem1) self.verticalLayout_5.addLayout(self.horizontalLayout_3) self.horizontalLayout_12 = QtWidgets.QHBoxLayout() - self.horizontalLayout_12.setContentsMargins(-1, 0, -1, -1) self.horizontalLayout_12.setObjectName("horizontalLayout_12") self.label_9 = QtWidgets.QLabel(parent=self.page) self.label_9.setObjectName("label_9") @@ -147,6 +146,17 @@ def setupUi(self, Dialog): self.checkBox_AutoAttachRegex.setObjectName("checkBox_AutoAttachRegex") self.horizontalLayout_12.addWidget(self.checkBox_AutoAttachRegex) self.verticalLayout_5.addLayout(self.horizontalLayout_12) + self.horizontalLayout_13 = QtWidgets.QHBoxLayout() + self.horizontalLayout_13.setObjectName("horizontalLayout_13") + self.label_13 = QtWidgets.QLabel(parent=self.page) + self.label_13.setObjectName("label_13") + self.horizontalLayout_13.addWidget(self.label_13) + self.comboBox_Language = QtWidgets.QComboBox(parent=self.page) + self.comboBox_Language.setObjectName("comboBox_Language") + self.horizontalLayout_13.addWidget(self.comboBox_Language) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_13.addItem(spacerItem2) + self.verticalLayout_5.addLayout(self.horizontalLayout_13) self.horizontalLayout_15 = QtWidgets.QHBoxLayout() self.horizontalLayout_15.setObjectName("horizontalLayout_15") self.label_11 = QtWidgets.QLabel(parent=self.page) @@ -155,11 +165,11 @@ def setupUi(self, Dialog): self.comboBox_Logo = QtWidgets.QComboBox(parent=self.page) self.comboBox_Logo.setObjectName("comboBox_Logo") self.horizontalLayout_15.addWidget(self.comboBox_Logo) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_15.addItem(spacerItem2) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_15.addItem(spacerItem3) self.verticalLayout_5.addLayout(self.horizontalLayout_15) - spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_5.addItem(spacerItem3) + spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_5.addItem(spacerItem4) self.gridLayout_2.addLayout(self.verticalLayout_5, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page) self.page_2 = QtWidgets.QWidget() @@ -187,14 +197,14 @@ def setupUi(self, Dialog): self.verticalLayout_6.addLayout(self.verticalLayout_Hotkey) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem4) + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem5) self.pushButton_ClearHotkey = QtWidgets.QPushButton(parent=self.page_2) self.pushButton_ClearHotkey.setObjectName("pushButton_ClearHotkey") self.horizontalLayout_4.addWidget(self.pushButton_ClearHotkey) self.verticalLayout_6.addLayout(self.horizontalLayout_4) - spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_6.addItem(spacerItem5) + spacerItem6 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_6.addItem(spacerItem6) self.horizontalLayout_5.addLayout(self.verticalLayout_6) self.gridLayout_3.addLayout(self.horizontalLayout_5, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_2) @@ -213,8 +223,8 @@ def setupUi(self, Dialog): self.verticalLayout_8.addWidget(self.label_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") - spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_6.addItem(spacerItem6) + spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_6.addItem(spacerItem7) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setObjectName("verticalLayout_7") self.radioButton_SimpleDLopenCall = QtWidgets.QRadioButton(parent=self.page_3) @@ -228,11 +238,11 @@ def setupUi(self, Dialog): self.horizontalLayout_6.addLayout(self.verticalLayout_7) self.verticalLayout_8.addLayout(self.horizontalLayout_6) self.horizontalLayout_8.addLayout(self.verticalLayout_8) - spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_8.addItem(spacerItem7) + spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_8.addItem(spacerItem8) self.verticalLayout_9.addLayout(self.horizontalLayout_8) - spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_9.addItem(spacerItem8) + spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_9.addItem(spacerItem9) self.gridLayout_4.addLayout(self.verticalLayout_9, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_3) self.page_4 = QtWidgets.QWidget() @@ -256,11 +266,11 @@ def setupUi(self, Dialog): self.lineEdit_InstructionsPerScroll.setObjectName("lineEdit_InstructionsPerScroll") self.horizontalLayout_9.addWidget(self.lineEdit_InstructionsPerScroll) self.horizontalLayout_10.addLayout(self.horizontalLayout_9) - spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_10.addItem(spacerItem9) + spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_10.addItem(spacerItem10) self.verticalLayout_10.addLayout(self.horizontalLayout_10) - spacerItem10 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_10.addItem(spacerItem10) + spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_10.addItem(spacerItem11) self.gridLayout_5.addLayout(self.verticalLayout_10, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_4) self.page_5 = QtWidgets.QWidget() @@ -293,11 +303,11 @@ def setupUi(self, Dialog): self.pushButton_HandleSignals = QtWidgets.QPushButton(parent=self.page_5) self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) - spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_16.addItem(spacerItem11) + spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_16.addItem(spacerItem12) self.verticalLayout_11.addLayout(self.horizontalLayout_16) - spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_11.addItem(spacerItem12) + spacerItem13 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_11.addItem(spacerItem13) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) self.horizontalLayout_2.addWidget(self.stackedWidget) @@ -307,8 +317,8 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(parent=Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem13) + spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem14) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -352,6 +362,7 @@ def retranslateUi(self, Dialog): "Patterns at former positions have higher priority if regex is off")) self.label_9.setText(_translate("Dialog", "Auto-attach on start")) self.checkBox_AutoAttachRegex.setText(_translate("Dialog", "Regex")) + self.label_13.setText(_translate("Dialog", "Language")) self.label_11.setText(_translate("Dialog", "Logo")) self.label_3.setText(_translate("Dialog", "Functions")) self.label_4.setText(_translate("Dialog", "Hotkey")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 6a54e539..b04d384d 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -271,9 +271,6 @@ - - 0 - @@ -297,6 +294,33 @@ Patterns at former positions have higher priority if regex is off + + + + + + Language + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/PINCE.py b/PINCE.py index 49b1fde2..25019a68 100755 --- a/PINCE.py +++ b/PINCE.py @@ -87,15 +87,32 @@ from keyboard import add_hotkey, remove_hotkey from operator import add as opAdd, sub as opSub +# TODO: Carry all settings related things to their own script if possible +language_list = [ + ("English", "en_US"), + ("Italiano", "it_IT"), + ("简体中文", "zh_CN") +] + +def get_locale(): + system_locale = QLocale.system().name() + for _, locale in language_list: + if system_locale == locale: + return locale + return language_list[0][1] + if __name__ == '__main__': app = QApplication(sys.argv) + app.setOrganizationName("PINCE") + app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") + app.setApplicationName("PINCE") QSettings.setPath(QSettings.Format.NativeFormat, QSettings.Scope.UserScope, - SysUtils.get_user_path(type_defs.USER_PATHS.CONFIG_PATH)) + SysUtils.get_user_path(type_defs.USER_PATHS.CONFIG_PATH)) settings = QSettings() translator = QTranslator() locale = settings.value("General/locale", type=str) if not locale: - locale = QLocale.system().name() + locale = get_locale() translator.load(f'i18n/qm/{locale}.qm') app.installTranslator(translator) tr.translate() @@ -103,7 +120,7 @@ instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "master-22" # Increase version by one if you change settings. Format: branch_name-version +current_settings_version = "23" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -111,6 +128,7 @@ gdb_output_mode = tuple auto_attach_list = str auto_attach_regex = bool +locale = str logo_path = str @@ -403,9 +421,6 @@ def __init__(self): self.treeWidget_AddressTable.setColumnWidth(TYPE_COL, 150) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) - app.setOrganizationName("PINCE") - app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") - app.setApplicationName("PINCE") self.settings = QSettings() if not SysUtils.is_path_valid(self.settings.fileName()): self.set_default_settings() @@ -525,8 +540,9 @@ def set_default_settings(self): self.settings.setValue("show_messagebox_on_exception", True) self.settings.setValue("gdb_output_mode", type_defs.gdb_output_mode(True, True, True)) self.settings.setValue("auto_attach_list", "") - self.settings.setValue("logo_path", "ozgurozbek/pince_small_transparent.png") self.settings.setValue("auto_attach_regex", False) + self.settings.setValue("locale", get_locale()) + self.settings.setValue("logo_path", "ozgurozbek/pince_small_transparent.png") self.settings.endGroup() self.settings.beginGroup("Hotkeys") for hotkey in Hotkeys.get_hotkeys(): @@ -568,8 +584,9 @@ def apply_settings(self): global show_messagebox_on_exception global gdb_output_mode global auto_attach_list - global logo_path global auto_attach_regex + global locale + global logo_path global code_injection_method global bring_disassemble_to_front global instructions_per_scroll @@ -582,9 +599,10 @@ def apply_settings(self): show_messagebox_on_exception = self.settings.value("General/show_messagebox_on_exception", type=bool) gdb_output_mode = self.settings.value("General/gdb_output_mode", type=tuple) auto_attach_list = self.settings.value("General/auto_attach_list", type=str) + auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) + locale = self.settings.value("General/locale", type=str) logo_path = self.settings.value("General/logo_path", type=str) app.setWindowIcon(QIcon(os.path.join(SysUtils.get_logo_directory(), logo_path))) - auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) GDB_Engine.set_gdb_output_mode(gdb_output_mode) for hotkey in Hotkeys.get_hotkeys(): hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) @@ -2209,8 +2227,12 @@ def accept(self): QMessageBox.information(self, tr.ERROR, tr.IS_INVALID_REGEX.format(self.lineEdit_AutoAttachList.text())) return self.settings.setValue("General/auto_attach_list", self.lineEdit_AutoAttachList.text()) - self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) self.settings.setValue("General/auto_attach_regex", self.checkBox_AutoAttachRegex.isChecked()) + new_locale = language_list[self.comboBox_Language.currentIndex()][1] + self.settings.setValue("General/locale", new_locale) + if locale != new_locale: + QMessageBox.information(self, tr.INFO, tr.LANG_RESET) + self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) for hotkey in Hotkeys.get_hotkeys(): self.settings.setValue("Hotkeys/" + hotkey.name, self.hotkey_to_value[hotkey.name]) if self.radioButton_SimpleDLopenCall.isChecked(): @@ -2244,13 +2266,19 @@ def config_gui(self): self.checkBox_OutputModeCommand.setChecked(self.settings.value("General/gdb_output_mode").command_output) self.checkBox_OutputModeCommandInfo.setChecked(self.settings.value("General/gdb_output_mode").command_info) self.lineEdit_AutoAttachList.setText(self.settings.value("General/auto_attach_list", type=str)) + self.checkBox_AutoAttachRegex.setChecked(self.settings.value("General/auto_attach_regex", type=bool)) + self.comboBox_Language.clear() + cur_loc = self.settings.value("General/locale", type=str) + for lang, loc in language_list: + self.comboBox_Language.addItem(lang) + if loc == cur_loc: + self.comboBox_Language.setCurrentIndex(self.comboBox_Language.count()-1) logo_directory = SysUtils.get_logo_directory() logo_list = SysUtils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") self.comboBox_Logo.clear() for logo in logo_list: self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) self.comboBox_Logo.setCurrentIndex(logo_list.index(self.settings.value("General/logo_path", type=str))) - self.checkBox_AutoAttachRegex.setChecked(self.settings.value("General/auto_attach_regex", type=bool)) self.listWidget_Functions.clear() self.hotkey_to_value.clear() for hotkey in Hotkeys.get_hotkeys(): diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 9968bd52..bbe8f122 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -267,6 +267,11 @@ Patterns at former positions have higher priority if regex is off Regex + + + Language + + Logo @@ -1290,6 +1295,16 @@ Patterns at former positions have higher priority if regex is off Error + + + Success + + + + + Information + + GDB isn't initialized yet @@ -1624,6 +1639,11 @@ Proceed? {} isn't a valid regex + + + Language settings will take effect upon the next restart + + You have changed the GDB path, reset GDB now? @@ -2013,11 +2033,6 @@ PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] Shared object library (*.so) - - - Success - - The file has been injected diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index ac2ca7fb..9822834f 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -269,6 +269,11 @@ Patterns at former positions have higher priority if regex is off Regex 正则表达式 + + + Language + + Logo @@ -1292,6 +1297,16 @@ Patterns at former positions have higher priority if regex is off Error 错误 + + + Success + 成功 + + + + Information + + GDB isn't initialized yet @@ -1630,6 +1645,11 @@ Proceed? {} isn't a valid regex {} 非有效正则表达式 + + + Language settings will take effect upon the next restart + + You have changed the GDB path, reset GDB now? @@ -2058,11 +2078,6 @@ PINCE 将追踪地址 [rax],[rbx*rcx+4] 和 [rbp] Shared object library (*.so) 共享对象库 (*.so) - - - Success - 成功 - The file has been injected diff --git a/tr/tr.py b/tr/tr.py index e45e5933..a5e1522a 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -18,6 +18,8 @@ def translate(): CHANGED_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Changed") UNCHANGED_SCAN_HOTKEY = QT_TR_NOOP("Next Scan - Unchanged") ERROR = QT_TR_NOOP("Error") + SUCCESS = QT_TR_NOOP("Success") + INFO = QT_TR_NOOP("Information") GDB_INIT = QT_TR_NOOP("GDB isn't initialized yet") GDB_INIT_ERROR = QT_TR_NOOP("Unable to initialize GDB\n" "You might want to reinstall GDB or use the system GDB\n" @@ -92,6 +94,7 @@ def translate(): "Setting update interval less than {} ms may cause slowdown\n" "Proceed?") IS_INVALID_REGEX = QT_TR_NOOP("{} isn't a valid regex") + LANG_RESET = QT_TR_NOOP("Language settings will take effect upon the next restart") GDB_RESET = QT_TR_NOOP("You have changed the GDB path, reset GDB now?") RESET_DEFAULT_SETTINGS = QT_TR_NOOP("This will reset to the default settings\n" "Proceed?") @@ -206,7 +209,6 @@ def translate(): # Same applies here, keep (*.so) SHARED_OBJECT_TYPE = QT_TR_NOOP("Shared object library (*.so)") - SUCCESS = QT_TR_NOOP("Success") FILE_INJECTED = QT_TR_NOOP("The file has been injected") FILE_INJECT_FAILED = QT_TR_NOOP("Failed to inject the .so file") ENTER_CALL_EXPRESSION = QT_TR_NOOP("Enter the expression for the function that'll be called from the inferior\n" From ad2e409c962a736e2e7be4f8077531dbe8cc961c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 5 Aug 2023 19:16:14 +0300 Subject: [PATCH 227/487] Remove keySequenceEdit hack --- GUI/Notes.txt | 4 +--- GUI/SettingsDialog.py | 3 +++ GUI/SettingsDialog.ui | 3 +++ PINCE.py | 25 ++++++++++--------------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/GUI/Notes.txt b/GUI/Notes.txt index a8390a7e..a33f7e52 100644 --- a/GUI/Notes.txt +++ b/GUI/Notes.txt @@ -1,3 +1 @@ -IMPORTANT: SettingsDialog.ui: Don't try to add a QKeySequenceEdit to the 2nd widget of stacked widget, pyuic5 gives error when QKeySequenceEdit is used. I had to implement it in PINCE.py because of this unfortunately. Check SettingsDialogForm class for the usage. - -6/10/2016 - HexView section of MemoryViewerWindow.ui: Changed listWidget_HexView_Address to tableWidget_HexView_Address in order to prevent possible future visual bugs. Logically, it should stay as a listwidget considering it's functionality. But it doesn't play nice with the other neighboring tablewidgets in different pyqt versions, forcing me to use magic numbers for adjusting, which is disgusting(I got the rhymes woohoo) \ No newline at end of file +6/10/2016 - HexView section of MemoryViewerWindow.ui: Changed listWidget_HexView_Address to tableWidget_HexView_Address in order to prevent possible future visual bugs. Logically, it should stay as a listwidget considering it's functionality. But it doesn't play nice with the other neighboring tablewidgets in different pyqt versions, forcing me to use magic numbers for adjusting, which is disgusting(I got the rhymes woohoo) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 3150cfad..c4e8d53a 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -194,6 +194,9 @@ def setupUi(self, Dialog): self.label_4 = QtWidgets.QLabel(parent=self.page_2) self.label_4.setObjectName("label_4") self.verticalLayout_Hotkey.addWidget(self.label_4) + self.keySequenceEdit_Hotkey = QtWidgets.QKeySequenceEdit(parent=self.page_2) + self.keySequenceEdit_Hotkey.setObjectName("keySequenceEdit_Hotkey") + self.verticalLayout_Hotkey.addWidget(self.keySequenceEdit_Hotkey) self.verticalLayout_6.addLayout(self.verticalLayout_Hotkey) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index b04d384d..e8becadb 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -398,6 +398,9 @@ Patterns at former positions have higher priority if regex is off + + + diff --git a/PINCE.py b/PINCE.py index 25019a68..5bb2b7e4 100755 --- a/PINCE.py +++ b/PINCE.py @@ -29,10 +29,9 @@ from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ QKeyEvent, QRegularExpressionValidator, QShortcut, QColorConstants -from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, \ - QKeySequenceEdit, QTabWidget, QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, \ - QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, \ - QPushButton, QFrame +from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ + QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ + QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, \ QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QThreadPool, \ QTranslator, QLocale, pyqtSlot @@ -2161,15 +2160,11 @@ def __init__(self, set_default_settings_func, parent=None): self.settings = QSettings() self.set_default_settings = set_default_settings_func self.hotkey_to_value = {} # Dict[str:str]-->Dict[Hotkey.name:settings_value] - - # Yet another retarded hack, thanks to pyuic5 not supporting QKeySequenceEdit - self.keySequenceEdit = QKeySequenceEdit() - self.verticalLayout_Hotkey.addWidget(self.keySequenceEdit) self.listWidget_Options.currentRowChanged.connect(self.change_display) icons_directory = GuiUtils.get_icons_directory() self.pushButton_GDBPath.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) self.listWidget_Functions.currentRowChanged.connect(self.listWidget_Functions_current_row_changed) - self.keySequenceEdit.keySequenceChanged.connect(self.keySequenceEdit_key_sequence_changed) + self.keySequenceEdit_Hotkey.keySequenceChanged.connect(self.keySequenceEdit_Hotkey_key_sequence_changed) self.pushButton_ClearHotkey.clicked.connect(self.pushButton_ClearHotkey_clicked) self.pushButton_ResetSettings.clicked.connect(self.pushButton_ResetSettings_clicked) self.pushButton_GDBPath.clicked.connect(self.pushButton_GDBPath_clicked) @@ -2301,19 +2296,19 @@ def change_display(self, index): def listWidget_Functions_current_row_changed(self, index): if index == -1: - self.keySequenceEdit.clear() + self.keySequenceEdit_Hotkey.clear() else: - self.keySequenceEdit.setKeySequence(self.hotkey_to_value[Hotkeys.get_hotkeys()[index].name]) + self.keySequenceEdit_Hotkey.setKeySequence(self.hotkey_to_value[Hotkeys.get_hotkeys()[index].name]) - def keySequenceEdit_key_sequence_changed(self): + def keySequenceEdit_Hotkey_key_sequence_changed(self): index = self.listWidget_Functions.currentIndex().row() if index == -1: - self.keySequenceEdit.clear() + self.keySequenceEdit_Hotkey.clear() else: - self.hotkey_to_value[Hotkeys.get_hotkeys()[index].name] = self.keySequenceEdit.keySequence().toString() + self.hotkey_to_value[Hotkeys.get_hotkeys()[index].name] = self.keySequenceEdit_Hotkey.keySequence().toString() def pushButton_ClearHotkey_clicked(self): - self.keySequenceEdit.clear() + self.keySequenceEdit_Hotkey.clear() def pushButton_ResetSettings_clicked(self): confirm_dialog = InputDialogForm(item_list=[(tr.RESET_DEFAULT_SETTINGS,)]) From 946257e9f31ec1094f83db61cbafbd8e0a498f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 6 Aug 2023 16:41:45 +0300 Subject: [PATCH 228/487] Remove unused installation notes --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e9525fa7..13023e0a 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,6 @@ sh install_pince.sh If you like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them if you want ***Notes:*** -- GDB enhancements (peda, pwndbg, etc) that use a global gdbinit file might cause PINCE to misfunction at times. Please disable them or use them locally before starting PINCE - If you are having problems with your default gdb version, you can use the `install_gdb.sh` script to install another version locally. Read the comments in it for more information - Check https://github.com/korcankaraokcu/PINCE/issues/116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` From 58e2f7dfe002ae833908f231c681917d4df9792d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 6 Aug 2023 16:44:36 +0300 Subject: [PATCH 229/487] Remove contact information --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 13023e0a..4c5106be 100644 --- a/README.md +++ b/README.md @@ -134,12 +134,6 @@ How to use line_profiler: Add ```@profile``` tag to the desired function and run # License GPLv3+. See COPYING file for details -# Contact Information -Korcan Karaokçu([korcankaraokcu](https://github.com/korcankaraokcu)) -Çağrı Ulaş([cagriulas](https://github.com/cagriulas)) -Jakob Kreuze([TsarFox](https://github.com/TsarFox)) -Gibus - # Supported platforms - Ubuntu and its flavors, actively tested on Kubuntu - Debian and Debian-based (Kali, Mint etc.) From e53ee94cf8516937ee5814c0af31d1a091e908fb Mon Sep 17 00:00:00 2001 From: detiam Date: Sun, 6 Aug 2023 20:36:05 +0800 Subject: [PATCH 230/487] Update zh_CN translation --- i18n/ts/zh_CN.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 9822834f..b4046c94 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -272,7 +272,7 @@ Patterns at former positions have higher priority if regex is off Language - + 语言 @@ -1305,7 +1305,7 @@ Patterns at former positions have higher priority if regex is off Information - + 信息 @@ -1648,7 +1648,7 @@ Proceed? Language settings will take effect upon the next restart - + 语言设置会在下次重启时生效 @@ -1696,7 +1696,7 @@ Use the char \ to escape special chars such as [ Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior - + 使用全局快捷键或者命令 'interrupt' 和 'c&' 停止/运行被调试程序(inferior) From f3b7fa86caed96acecfdbb6a9bf620783195a52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 8 Aug 2023 20:51:24 +0300 Subject: [PATCH 231/487] Add SIGXCPU to ignored signals --- PINCE.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index 5bb2b7e4..85a41f29 100755 --- a/PINCE.py +++ b/PINCE.py @@ -119,7 +119,7 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "23" # Increase version by one if you change settings +current_settings_version = "24" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -191,7 +191,7 @@ def get_hotkeys(): gdb_logging = bool ignored_signals = str -signal_list = ["SIGUSR1", "SIGPWR", "SIGSEGV"] +signal_list = ["SIGUSR1", "SIGPWR", "SIGXCPU", "SIGSEGV"] # represents the index of columns in instructions restore table INSTR_ADDR_COL = 0 @@ -557,7 +557,7 @@ def set_default_settings(self): self.settings.beginGroup("Debug") self.settings.setValue("gdb_path", type_defs.PATHS.GDB_PATH) self.settings.setValue("gdb_logging", False) - self.settings.setValue("ignored_signals", "1,1,0") + self.settings.setValue("ignored_signals", "1,1,1,0") self.settings.endGroup() self.settings.beginGroup("Misc") self.settings.setValue("version", current_settings_version) From 967194d729eb6bc6ac5276d8ce5cd1a8198dc4f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 12 Aug 2023 23:32:42 +0300 Subject: [PATCH 232/487] Create CONTRIBUTING.md --- CONTRIBUTING.md | 218 +++++++++++++++++++++++++++++++++++++++++++++ GUI/Notes.txt | 1 - Notes.txt | 51 ----------- README.md | 55 ------------ libpince/Notes.txt | 37 -------- 5 files changed, 218 insertions(+), 144 deletions(-) create mode 100644 CONTRIBUTING.md delete mode 100644 GUI/Notes.txt delete mode 100644 Notes.txt delete mode 100644 libpince/Notes.txt diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..97f879a4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,218 @@ +# Code Structure +- [PINCE.py](./PINCE.py) - The main file, it contains everything from GUI logic to libpince communication. A chonky boi, will be trimmed in the future +- [PINCE.sh](./PINCE.sh) - Launch script +- [install_pince.sh](./install_pince.sh) - Installation script +- [compile_ts.sh](./compile_ts.sh) - Gathers translation information from various sources and compiles them into ts files +- [fix_ts.py](./fix_ts.py) - Fixes line information issue, used within [compile_ts.sh](./compile_ts.sh) +- [install_gdb.sh](./install_gdb.sh) - PINCE normally uses system GDB but in cases where system GDB is unavailable, this script is used to compile GDB locally +- [GUI](./GUI) - Contains Qt Designer forms and their respective codes along with some custom Qt classes +- [media](./media) - Contains media files such as logos and icons +- [tr](./tr) - Contains translation constants +- [i18n](./i18n) - Contains translation files. `ts` files are created with Qt Linguist and [compile_ts.sh](./compile_ts.sh), `qm` files are created within the last section of [install_pince.sh](./install_pince.sh) +- ### **[libpince](./libpince)** + - [GDB_Engine.py](./libpince/GDB_Engine.py) - Everything related to communicating with GDB and debugging + - [SysUtils.py](./libpince/SysUtils.py) - Contains generic utility functions such as parsing, file creation, documentation etc + - [GuiUtils.py](./libpince/GuiUtils.py) - Contains GUI related utility functions, it's more affiliated with Qt than libpince, could be moved in the future + - [type_defs.py](./libpince/type_defs.py) - Contains all constants and variable definitions + - [common_regexes.py](./libpince/common_regexes.py) - Contains regexes for parsing GDB output and other things + - [Injection](./libpince/Injection) - An example for injecting .so files + - ### **[gdb_python_scripts](./libpince/gdb_python_scripts)** + - [GDBCommandExtensions.py](./libpince/gdb_python_scripts/GDBCommandExtensions.py) - Contains custom GDB commands + - [ScriptUtils.py](./libpince/gdb_python_scripts/ScriptUtils.py) - Contains utility functions for GDB commands + - [tests](./libpince/gdb_python_scripts/tests) - An example for .so extension, read more [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) + +# Code Style +The rules are about the same with PEP-8, with some changes. While they are not strict, I'd like you to follow them for consistency +- Max characters per line: 120 +- Variable naming for libpince: + - Classes: PascalCase + - Class members: snake_case + - Variables: snake_case + - Functions: snake_case + - Constants: SCREAMING_SNAKE_CASE + - Modules: Not yet specified, a bit random at the moment, will be addressed later on + - Standalone scripts: snake_case +- Variable naming for Qt: + - Classes: PascalCase + - Class members: + - non-Qt: snake_case + - Qt: objectType + PascalCase + For example: `keySequenceEdit_Hotkey` in [PINCE.py](./PINCE.py) + - Variables: snake_case + - Functions: + - non-Qt: snake_case + - Qt: objectName + snake_case + Here's an example: `keySequenceEdit_Hotkey_key_sequence_changed` in [PINCE.py](./PINCE.py) + - Constants: SCREAMING_SNAKE_CASE + - Modules: PascalCase + - Standalone scripts: snake_case + +For convenience, I'm using auto-format tool of vscode. Any modern IDE will most likely have an auto-formatting tool. +Readability and being clear is the most important aspect, so if you decide to not follow the rules, make sure that your code still reads nice and plays well with others. +If you feel unsure to which naming convention you should use, try to check out similar patterns in the code or just ask away in the PINCE discord server! + +The reason behind Qt class member naming convention is that when this project first started, supported python version didn't have type hints. +So, to have an idea about the type of the variable we are working with, I've come up with that naming idea. It's an old habit if anything. +It could maybe replaced with something else after a refactorization + +About the max characters per line, I used to use PyCharm when I first started this project years ago. 120 characters is a limit brought by PyCharm, +I've quit using PyCharm eventually but I think the limit makes the code look quite nice. PEP-8 suggests a limit of 79 characters, which is a bit too short to be frank. +So I think it's good to keep this old habit. This limit however, is not strict at all. A few characters passing the limit is ok, sometimes going for a newline +messes up the readability, trust your guts and decide for yourself + +# UI files +You need to have [Qt6 Designer](https://pkgs.org/search/?q=designer&on=files) and [pyuic6](https://pkgs.org/search/?q=pyuic6&on=files) installed. +Edit or create ui files with the designer and then save them. After saving the files, use pyuic6 to convert them into py files: `pyuic6 SomeDialog.ui -o SomeDialog.py`. +The py files that contains the same name with the ui files are auto-generated, please edit the ui files with designer instead of messing with the py files + +# Translation +You need to have [Qt6 Linguist](https://pkgs.org/search/?q=linguist&on=files) and [pylupdate6](https://pkgs.org/search/?q=pylupdate6&on=files) installed. +Edit ts files in [/i18n/ts](./i18n/ts) with the linguist and then save them. After saving the files, run the [compile_ts.sh](./compile_ts.sh) script. +This script fixes inconsistencies between Qt6 Linguist and pylupdate6, also removes line information so the git history stays cleaner + +Make sure that you read the comments in [tr.py](./tr/tr.py). Some of the translations have caveats that might interest you + +About the untranslated parts of the code, such as context menus of libpince reference widget. You'll see that some of the code serves as a placeholder that'll be +removed or replaced in the future. These are not marked as translatable as translating them would be a waste of time + +# Logo +All logo requests should be posted in `/media/logo/your_username`. Instead of opening a new issue, pull request your logo files to that folder. +Your PR must include at least one png file named pince_small, pince_medium or pince_big, according to its size. So, a minimal PR will look like this: + +`/media/logo/your_username/pince_big.png` + +pince_big is interchangeable with pince_medium and pince_small +A full PR will look like this: +``` +/media/logo/your_username/pince_big.png +/media/logo/your_username/pince_medium.png +/media/logo/your_username/pince_small.png +``` + +# Notes +Here are some notes that explains some of the caveats and hacks, they also include a timestamp. As we upgrade the libraries and the methods we are working with, +some of these notes might become obsolete. You are free to test and provide solutions to these tricks + +- 27/3/2017 - All GUI classes that will be instanced multiple times must contain these code blocks to prevent getting removed by garbage collector: +```python + global instances + instances.append(self) + + def closeEvent(self, QCloseEvent): + global instances + instances.remove(self) +``` +If you need to only create one instance of a GUI class, use this instead to create the instance: +```python + try: + self.window.show() + except AttributeError: + self.window = WindowForm(self) # self parameter is optional + self.window.show() + self.window.activateWindow() +``` +If you need to pass self as a parameter, please don't use `super().__init__(parent=parent)` in the child class, it makes Qt hide the child window. Use this in the child instead: +```python + super().__init__() + self.parent = lambda: parent # A quick hack to make other functions see the correct parent(). But Qt won't see it, so there'll be no bugs +``` + +- 28/8/2018 - All QMessageBoxes that's called from outside of their classes(via parent() etc.) must use 'QApplication.focusWidget()' instead of 'self' in their first parameter. +Refer to issue #57 for more information + +- 23/11/2018 - Don't use get_current_item or get_current_row within currentItemChanged or currentChanged signals. +Qt doesn't update selected rows on first currentChanged or currentItemChanged calls + +- 22/05/2023 - For QTableWidget and QTableView, disabling wordWrap and using ScrollPerPixel as the horizontal scroll mode can help the user experience. +Consider doing these when creating a new QTableWidget or QTableView + +- 2/9/2018 - All functions with docstrings should have their subfunctions written after their docstrings. For instance: +```python + def test(): + """documentation for test""" + def subtest(): + return + return +``` +If test is declared like above, `test.__doc__` will return "documentation for test" correctly. This is the correct documentation +```python + def test(): + def subtest(): + return + """documentation for test""" + return +``` +If test is declared like above, `test.__doc__` will return a null string because subtest blocks the docstring. This is the wrong documentation +All functions that has a subfunction can be found with the regex `def.*:.*\s+def` + +- 2/9/2018 - Seek methods of all file handles that read directly from the memory(/proc/pid/mem etc.) should be wrapped in a try/except block that catches both +OSError and ValueError exceptions. For instance: +```python + try: + self.memory.seek(start_addr) + except (OSError, ValueError): + break +``` +OSError handles I/O related errors and ValueError handles the off_t limit error that prints "cannot fit 'int' into an offset-sized integer" + +- 12/9/2018 - All namedtuples must have the same field name with their variable names. This makes the namedtuple transferable via pickle. For instance: +```python + tuple_examine_expression = collections.namedtuple("tuple_examine_expression", "all address symbol") +``` +- 6/10/2016 - HexView section of MemoryViewerWindow.ui: Changed listWidget_HexView_Address to tableWidget_HexView_Address in order to prevent possible future visual bugs. +Logically, it should stay as a listwidget considering it's functionality. But it doesn't play nice with the other neighboring tablewidgets in different pyqt versions, +forcing me to use magic numbers for adjusting, which is a bit hackish + +# Roadmap +So, after learning how to contribute, you are wondering where to start now. You can either search for `TODO` within the code or pick up any task from the roadmap below. +These are not in order, so free to pick any of them +- Refactor file naming conventions(decide on snake_case or camelCase for modules etc) +- Refactorize memory write/read functions +- - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. + Only update the visible rows to prevent this(check ```disassemble_check_viewport``` for an example) +- - Implement same system for the TrackBreakpointWidgetForm if necessary. Do performance tests +- - Consider using a class instead of primitive return types to store the raw bytes. This class should also include a method to display None type as red '??' text for Qt +- - Provide an option to cut BOM bytes when writing to memory with the types UTF-16 and UTF-32 +- - Put a warning for users about replacement bytes for non UTF-8 types +- - Extend string types with LE and BE variants of UTF-16 and UTF-32 +- - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others if necessary +- - Implement a custom combobox class for comboBox_ValueType and create a context menu for String_Others, if it gets implemented +- Implement "Investigate Registers" button to gather information about the addresses registers point to +- Implement selectionChanged signal of lineEdit_HexView +- Implement multi selection for HexView +- Add the ability to track down registers and addresses in tracer(unsure) +- Implement CE's Ultimap-like feature for tracing data, dissect code data and raw instruction list. +Search for calls and store their hit counts to filter out the functions that haven't or have executed specific number of times. +Implement a flexible input field for the execution count. For instance, 2^x only searches for hit counts 2, 4, 8 and so on, 3x only searches for 3, 6, 9 etc. +([CE#358](https://github.com/cheat-engine/cheat-engine/issues/358)) +- Extend search_referenced_strings with relative search +- Consider adding type guessing for the StackView +- Move GUI classes of PINCE.py to their own files +- Use gdb python API breakpoints instead of breakpoint commands for optimization, also find a way to eliminate output coming from stepping commands such as ```stepi&``` or ```nexti&``` +- Implement a psuedo-terminal for the inferior like edb does(idk if necessary, we don't usually target CLI games, up to debate) +- Implement libpince engine +- Implement auto-ESP&aimbot (depends on libpince engine) +- Try to optimize TrackBreakpoint and TrackWatchpoint return data structures further, adding an id field might simplify traversing of the tree, performance tests are required +- Extend tagging system to PINCE GUI functions +- Implement multi-line code injection, this will also help with previously dropped inject_with_advanced_injection +- Break on/Catch signals and syscalls +- Flowcharts based on disassembled output +- Automatic function bypassing(make it return the desired value, hook specific parts etc.) +- Implement speedhack +- Implement unrandomizer +- Implement pointer-scan +- Write at least one test for each function in libpince +- Migrate to Sphinx documentation from the custom libpince documentation +- Embedded tutorial videos +- Super-Uber-Rad credits roll with chiptune tunes(as discussed, this could be an embedded video to prevent unnecessary dependencies) +- Implement extra MemoryViewerWindow tabs(not really critical right now, up to debate) +- ~~Consider removing the command file layer of IPC system for GDB_Engine.send_command to speed up things~~ +[Update-29/04/2018 : Delaying this until GDB/MI implements a native multiline command feature or improves ```interpreter-exec``` command to cover every single multiline command type(including ```define``` commands)] +- Implement thread info widget +- Implement developer mode in settings. Developer mode will include features like dissection of GUI elements on events such as mouse-over +- Add ability to include non-absolute calls for dissect code feature(i.e call rax). Should be considered after the first version release. Might be useful for multi-breakpoint related features +- Implement toggling of arrows for easier navigation for dissected regions +- Provide information about absolute addresses in disassemble screen +- Use type hints(py 3.5) and variable annotations(py 3.6) when support drops for older systems +- All tables that hold large amount of data should only update the visible rows(check ```disassemble_check_viewport``` for an example) +- Add different kinds of themes and the ability to change between them on runtime. Implement dark theme first. Also add the ability to create a custom theme and modify the existing ones diff --git a/GUI/Notes.txt b/GUI/Notes.txt deleted file mode 100644 index a33f7e52..00000000 --- a/GUI/Notes.txt +++ /dev/null @@ -1 +0,0 @@ -6/10/2016 - HexView section of MemoryViewerWindow.ui: Changed listWidget_HexView_Address to tableWidget_HexView_Address in order to prevent possible future visual bugs. Logically, it should stay as a listwidget considering it's functionality. But it doesn't play nice with the other neighboring tablewidgets in different pyqt versions, forcing me to use magic numbers for adjusting, which is disgusting(I got the rhymes woohoo) diff --git a/Notes.txt b/Notes.txt deleted file mode 100644 index 81c99876..00000000 --- a/Notes.txt +++ /dev/null @@ -1,51 +0,0 @@ -Code Relocations: - --libpince - GuiUtils.py is used to contain GUI related utility functions - SysUtils.py is used to contain non-GDB related utility functions - GDB_Engine.py is used to contain all GDB related functions - type_defs.py is used to contain all static&shared variable definitions - All codes that'll be injected to the inferior go to the folder "Injection" - /gdb_python_script/ contains all the python scripts that'll invoked from the gdb - PINCE.py is used to interract with GUI and other utility libraries - /media/ contains all the images, icons, logos n' stuff -**Don't touch anything in GUI folder, it contains auto-generated codes created by pyuic - -27/3/2017 - All GUI classes that will be instanced multiple times must contain these code blocks to prevent getting removed by garbage collector: - - global instances - instances.append(self) - - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - -If you need to only create one instance of a GUI class, use this instead to create the instance: - - try: - self.window.show() - except AttributeError: - self.window = WindowForm(self) # self parameter is optional - self.window.show() - self.window.activateWindow() - -If you need to pass self as a parameter, please don't use 'super().__init__(parent=parent)' in the child class, it makes Qt hide the child window. Use this in the child instead: - super().__init__() - self.parent = lambda: parent # A quick hack to make other functions see the correct parent(). But Qt won't see it, so there'll be no bugs - -28/8/2018 - All QMessageBoxes that's called from outside of their classes(via parent() etc.) must use 'QApplication.focusWidget()' instead of 'self' in their first parameter. Refer to issue #57 for more information - -14/11/2018 - All logo requests should be posted in media/logo/your_username. Instead of opening a new issue, PR your logo files to that folder. Your PR must include at least one png file named pince_small, pince_medium or pince_big, according to its size -So, a minimal PR will look like this: - -/media/logo/your_username/pince_big.png - -pince_big is interchangeable with pince_medium and pince_small -A full PR will look like this: - -/media/logo/your_username/pince_big.png -/media/logo/your_username/pince_medium.png -/media/logo/your_username/pince_small.png - -23/11/2018 - Don't use get_current_item or get_current_row within currentItemChanged or currentChanged signals. Qt doesn't update selected rows on first currentChanged or currentItemChanged calls - -22/05/2023 - For QTableWidget and QTableView, disabling wordWrap and using ScrollPerPixel as the horizontal scroll mode can help the user experience. Consider doing these when creating a new QTableWidget or QTableView diff --git a/README.md b/README.md index 4c5106be..9688d297 100644 --- a/README.md +++ b/README.md @@ -76,61 +76,6 @@ If you like to uninstall PINCE, just delete this folder, almost everything is in # Running PINCE Just run ```sh PINCE.sh``` in the PINCE directory -### For developers: -``` -sudo apt-get install qt6-tools-dev (designer and pyuic6) -sudo pip3 install line_profiler (for performance testing) -``` -How to use line_profiler: Add ```@profile``` tag to the desired function and run PINCE with ```sudo kernprof -l -v PINCE.py``` - -# Current Roadmap -- Refactor file naming conventions(decide on snake_case or camelCase for modules etc) -- Create ```CONTRIBUTING.md``` and combine all non-tutorial notes within it -- Refactorize memory write/read functions -- - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. Only update the visible rows to prevent this(check ```disassemble_check_viewport``` for an example) -- - Implement same system for the TrackBreakpointWidgetForm if necessary. Do performance tests -- - Consider using a class instead of primitive return types to store the raw bytes. This class should also include a method to display None type as red '??' text for Qt -- - Provide an option to cut BOM bytes when writing to memory with the types UTF-16 and UTF-32 -- - Put a warning for users about replacement bytes for non UTF-8 types -- - Extend string types with LE and BE variants of UTF-16 and UTF-32 -- - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others -- - Implement a custom combobox class for comboBox_ValueType and create a context menu for String_Others item -- Implement "Investigate Registers" button to gather information about the addresses registers point to(independent from other steps) -- Implement selectionChanged signal of lineEdit_HexView -- Implement multi selection for HexView -- Add the ability to track down registers and addresses in tracer(unsure)(independent from other steps) -- Implement CE's Ultimap-like feature for tracing data, dissect code data and raw instruction list. Search for calls and store their hit counts to filter out the functions that haven't or have executed specific number of times. Implement a flexible input field for the execution count. For instance, 2^x only searches for hit counts 2, 4, 8 and so on, 3x only searches for 3, 6, 9 etc.(independent from other steps)([CE#358](https://github.com/cheat-engine/cheat-engine/issues/358)) -- Extend search_referenced_strings with relative search -- Consider adding type guessing for the StackView(independent from other steps) -- Move GUI classes of PINCE.py to their own files -- Use gdb python API breakpoints instead of breakpoint commands for optimization, also find a way to eliminate output coming from stepping commands such as ```stepi&``` or ```nexti&```(independent from other steps) -- Implement a psuedo-terminal for the inferior like edb does(independent from other steps) -- Implement libpince engine -- Implement auto-ESP&aimbot (depends on libpince engine) -- Try to optimize TrackBreakpoint and TrackWatchpoint return data structures further, adding an id field might simplify traversing of the tree, performance tests are required(independent from other steps) -- Extend tagging system to PINCE GUI functions -- Implement multi-line code injection, this will also help with previously dropped inject_with_advanced_injection -- Break on/Catch signals and syscalls -- Flowcharts based on disassembled output -- Automatic function bypassing(make it return the desired value, hook specific parts etc.) -- Implement speedhack(independent from other steps) -- Implement unrandomizer(independent from other steps) -- Implement pointer-scan -- Write at least one test for each function in libpince -- Migrate to Sphinx documentation from the custom libpince documentation(independent from other steps) -- Embedded tutorial videos -- Super-Uber-Rad credits roll with chiptune tunes -- Implement extra MemoryViewerWindow tabs(independent from other steps) -- ~~Consider removing the command file layer of IPC system for GDB_Engine.send_command to speed up things~~(independent from other steps)[Update-29/04/2018 : Delaying this until GDB/MI implements a native multiline command feature or improves ```interpreter-exec``` command to cover every single multiline command type(including ```define``` commands)] -- Implement thread info widget -- Implement developer mode in settings. Developer mode will include features like dissection of GUI elements on events such as mouse-over(independent from other steps) -- Add ability to include non-absolute calls for dissect code feature(i.e call rax). Should be considered after the first version release. Might be useful for multi-breakpoint related features -- Implement toggling of arrows for easier navigation for dissected regions(independent from other steps) -- Provide information about absolute addresses in disassemble screen(independent from other steps) -- Use type hints(py 3.5) and variable annotations(py 3.6) when support drops for older systems(independent from other steps) -- All tables that hold large amount of data should only update the visible rows(check ```disassemble_check_viewport``` for an example)(independent from other steps) -- Add different kinds of themes and the ability to change between them on runtime. Implement dark theme first. Also add the ability to create a custom theme and modify the existing ones(independent from other steps) - # License GPLv3+. See COPYING file for details diff --git a/libpince/Notes.txt b/libpince/Notes.txt deleted file mode 100644 index 89e10255..00000000 --- a/libpince/Notes.txt +++ /dev/null @@ -1,37 +0,0 @@ -2/5/2018 - All docstrings that has "\" character in them should start with "r" to make themselves interpreted as raw strings. Otherwise SysUtils.get_docstrings() won't be able to escape "\" by itself. Check these functions for examples: -SysUtils.get_variable_comments() -GDB_Engine.create_process() -GDB_Engine.attach() -GDB_Engine.init_gdb() - -2/9/2018 - All functions with docstrings should have their subfunctions written after their docstrings. For instance: - - def test(): - """documentation for test""" - def subtest(): - return - return - -If test is declared like above, test.__doc__ will return "documentation for test" correctly. This is the correct documentation - - def test(): - def subtest(): - return - """documentation for test""" - return - -If test is declared like above, test.__doc__ will return a null string because subtest blocks the docstring. This is the wrong documentation -All functions that has a subfunction can be found with the regex def.*:.*\s+def - -2/9/2018 - Seek methods of all file handles that read directly from the memory(/proc/pid/mem etc.) should be wrapped in a try/except block that catches both OSError and ValueError exceptions. For instance: - - try: - self.memory.seek(start_addr) - except (OSError, ValueError): - break - -OSError handles I/O related errors and ValueError handles the off_t limit error that prints "cannot fit 'int' into an offset-sized integer" - -12/9/2018 - All namedtuples must have the same field name with their variable names. This makes the namedtuple transferable via pickle. For instance: - - tuple_examine_expression = collections.namedtuple("tuple_examine_expression", "all address symbol") \ No newline at end of file From 56d8f0c41ed320c858ee34f9af848b8d08436d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 12 Aug 2023 23:39:15 +0300 Subject: [PATCH 233/487] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9688d297..8734959e 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,11 @@ If you like to uninstall PINCE, just delete this folder, almost everything is in # Running PINCE Just run ```sh PINCE.sh``` in the PINCE directory +# Contributing +Want to help? Check out [CONTRIBUTING.md](CONTRIBUTING.md) + # License -GPLv3+. See COPYING file for details +GPLv3+. See [COPYING](COPYING) file for details # Supported platforms - Ubuntu and its flavors, actively tested on Kubuntu From 1dfea6b00434c5b2d04c6f25cc7ac386201d547c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 13 Aug 2023 20:12:54 +0300 Subject: [PATCH 234/487] Remove show_messagebox_on_exception --- GUI/SettingsDialog.py | 5 ----- GUI/SettingsDialog.ui | 10 ---------- PINCE.py | 17 ++++------------- i18n/ts/it_IT.ts | 5 ----- i18n/ts/zh_CN.ts | 5 ----- 5 files changed, 4 insertions(+), 38 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index c4e8d53a..db0996d2 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -110,10 +110,6 @@ def setupUi(self, Dialog): spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_7.addItem(spacerItem) self.verticalLayout_5.addLayout(self.horizontalLayout_7) - self.checkBox_MessageBoxOnException = QtWidgets.QCheckBox(parent=self.page) - self.checkBox_MessageBoxOnException.setChecked(True) - self.checkBox_MessageBoxOnException.setObjectName("checkBox_MessageBoxOnException") - self.verticalLayout_5.addWidget(self.checkBox_MessageBoxOnException) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.label_8 = QtWidgets.QLabel(parent=self.page) @@ -356,7 +352,6 @@ def retranslateUi(self, Dialog): self.checkBox_AutoUpdateAddressTable.setText(_translate("Dialog", "Auto-update address table")) self.label.setText(_translate("Dialog", "Update Interval")) self.label_12.setText(_translate("Dialog", "Freeze Interval")) - self.checkBox_MessageBoxOnException.setText(_translate("Dialog", "Show a MessageBox on InferiorRunning and GDBInitialize exceptions")) self.label_8.setText(_translate("Dialog", "GDB output:")) self.checkBox_OutputModeAsync.setText(_translate("Dialog", "Async")) self.checkBox_OutputModeCommand.setText(_translate("Dialog", "Command")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index e8becadb..09bc7001 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -205,16 +205,6 @@
- - - - Show a MessageBox on InferiorRunning and GDBInitialize exceptions - - - true - - - diff --git a/PINCE.py b/PINCE.py index 85a41f29..1e5fceb0 100755 --- a/PINCE.py +++ b/PINCE.py @@ -119,11 +119,10 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "24" # Increase version by one if you change settings +current_settings_version = "25" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int -show_messagebox_on_exception = bool gdb_output_mode = tuple auto_attach_list = str auto_attach_regex = bool @@ -318,11 +317,9 @@ def run(self): def except_hook(exception_type, value, tb): - if show_messagebox_on_exception: - focused_widget = app.focusWidget() - if focused_widget: - if exception_type == type_defs.GDBInitializeException: - QMessageBox.information(focused_widget, tr.ERROR, tr.GDB_INIT) + focused_widget = app.focusWidget() + if focused_widget and exception_type == type_defs.GDBInitializeException: + QMessageBox.information(focused_widget, tr.ERROR, tr.GDB_INIT) traceback.print_exception(exception_type, value, tb) @@ -536,7 +533,6 @@ def set_default_settings(self): self.settings.setValue("auto_update_address_table", True) self.settings.setValue("address_table_update_interval", 500) self.settings.setValue("freeze_interval", 100) - self.settings.setValue("show_messagebox_on_exception", True) self.settings.setValue("gdb_output_mode", type_defs.gdb_output_mode(True, True, True)) self.settings.setValue("auto_attach_list", "") self.settings.setValue("auto_attach_regex", False) @@ -580,7 +576,6 @@ def apply_after_init(self): def apply_settings(self): global update_table global table_update_interval - global show_messagebox_on_exception global gdb_output_mode global auto_attach_list global auto_attach_regex @@ -595,7 +590,6 @@ def apply_settings(self): update_table = self.settings.value("General/auto_update_address_table", type=bool) table_update_interval = self.settings.value("General/address_table_update_interval", type=int) freeze_interval = self.settings.value("General/freeze_interval", type=int) - show_messagebox_on_exception = self.settings.value("General/show_messagebox_on_exception", type=bool) gdb_output_mode = self.settings.value("General/gdb_output_mode", type=tuple) auto_attach_list = self.settings.value("General/auto_attach_list", type=str) auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) @@ -2210,7 +2204,6 @@ def accept(self): if self.checkBox_AutoUpdateAddressTable.isChecked(): self.settings.setValue("General/address_table_update_interval", current_table_update_interval) self.settings.setValue("General/freeze_interval", current_freeze_interval) - self.settings.setValue("General/show_messagebox_on_exception", self.checkBox_MessageBoxOnException.isChecked()) current_gdb_output_mode = type_defs.gdb_output_mode(self.checkBox_OutputModeAsync.isChecked(), self.checkBox_OutputModeCommand.isChecked(), self.checkBox_OutputModeCommandInfo.isChecked()) @@ -2255,8 +2248,6 @@ def config_gui(self): self.lineEdit_UpdateInterval.setText( str(self.settings.value("General/address_table_update_interval", type=int))) self.lineEdit_FreezeInterval.setText(str(self.settings.value("General/freeze_interval", type=int))) - self.checkBox_MessageBoxOnException.setChecked( - self.settings.value("General/show_messagebox_on_exception", type=bool)) self.checkBox_OutputModeAsync.setChecked(self.settings.value("General/gdb_output_mode").async_output) self.checkBox_OutputModeCommand.setChecked(self.settings.value("General/gdb_output_mode").command_output) self.checkBox_OutputModeCommandInfo.setChecked(self.settings.value("General/gdb_output_mode").command_info) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index bbe8f122..e971d01c 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -226,11 +226,6 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Freeze Interval - - - Show a MessageBox on InferiorRunning and GDBInitialize exceptions - - GDB output: diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index b4046c94..ad3865f6 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -227,11 +227,6 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Freeze Interval 冻结间隔 - - - Show a MessageBox on InferiorRunning and GDBInitialize exceptions - 出现 "InferiorRunning" 和 "GDBInitialize" 异常时显示一个消息框 - GDB output: From 0b25bf0d6bcd8ea1e727cfd355e7ccde73d2cdfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 14 Aug 2023 22:11:35 +0300 Subject: [PATCH 235/487] compile_ts can now create new locale --- compile_ts.sh | 8 +++++--- fix_ts.py | 4 ++++ i18n/ts/it_IT.ts | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compile_ts.sh b/compile_ts.sh index ba6468fa..e85fabdc 100755 --- a/compile_ts.sh +++ b/compile_ts.sh @@ -2,13 +2,15 @@ file_supportlocale='/usr/share/i18n/SUPPORTED' list_ts=$(find i18n/ts -maxdepth 1 -type f -name '*.ts') +# If there's a user parameter, create a new locale based on it +if [ -n "$1" ]; then + list_ts="$list_ts i18n/ts/$1.ts" +fi + if [ -e "$file_supportlocale" ]; then for ts in $list_ts; do # Check if the locale is valid if grep -E "^$(basename "$ts" .ts)(.)?.*\s.*" "$file_supportlocale" > /dev/null 2>&1; then - # Remove empty file to prevent error - # "invalid translation file: no element found: line 1, column 0" - [ -s "$ts" ] || rm "$ts" pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts "$ts" python3 fix_ts.py "$ts" else diff --git a/fix_ts.py b/fix_ts.py index 3212307a..2a9411ac 100644 --- a/fix_ts.py +++ b/fix_ts.py @@ -1,10 +1,14 @@ import xml.etree.ElementTree as ET import sys +import os file = sys.argv[1] tree = ET.parse(file, parser=ET.XMLParser(encoding="utf-8")) root = tree.getroot() +locale = os.path.splitext(os.path.basename(file))[0] +root.set('language', locale) + # Removing line info so updating tr.py affects git history much less for location in root.findall('.//location'): location.set('line', '0') diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index e971d01c..b1a996cc 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1,6 +1,6 @@ - + Dialog From 8607c0b1cd2862b6ba270cee0d9f3d4e7fa4cf77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 14 Aug 2023 22:15:28 +0300 Subject: [PATCH 236/487] Add comment to fix_ts --- fix_ts.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fix_ts.py b/fix_ts.py index 2a9411ac..f91325cb 100644 --- a/fix_ts.py +++ b/fix_ts.py @@ -6,6 +6,7 @@ tree = ET.parse(file, parser=ET.XMLParser(encoding="utf-8")) root = tree.getroot() +# pylupdate6 doesn't set locale on creation, make sure it's there locale = os.path.splitext(os.path.basename(file))[0] root.set('language', locale) From 605c31e17e2f6699bdaf1466d8acd8b535dda0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 15 Aug 2023 17:42:18 +0300 Subject: [PATCH 237/487] Update UI Files and Translation --- CONTRIBUTING.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 97f879a4..00702734 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,21 +60,30 @@ I've quit using PyCharm eventually but I think the limit makes the code look qui So I think it's good to keep this old habit. This limit however, is not strict at all. A few characters passing the limit is ok, sometimes going for a newline messes up the readability, trust your guts and decide for yourself -# UI files -You need to have [Qt6 Designer](https://pkgs.org/search/?q=designer&on=files) and [pyuic6](https://pkgs.org/search/?q=pyuic6&on=files) installed. -Edit or create ui files with the designer and then save them. After saving the files, use pyuic6 to convert them into py files: `pyuic6 SomeDialog.ui -o SomeDialog.py`. +# UI Files +You need to have [Qt6 Designer](https://pkgs.org/search/?q=designer&on=files) and [pyuic6](https://pkgs.org/search/?q=pyuic6&on=files) installed. Here are the steps: +- Edit or create ui files with the designer and then save them +- After saving the files, use pyuic6 to convert them into py files: `pyuic6 SomeDialog.ui -o SomeDialog.py` + The py files that contains the same name with the ui files are auto-generated, please edit the ui files with designer instead of messing with the py files # Translation -You need to have [Qt6 Linguist](https://pkgs.org/search/?q=linguist&on=files) and [pylupdate6](https://pkgs.org/search/?q=pylupdate6&on=files) installed. -Edit ts files in [/i18n/ts](./i18n/ts) with the linguist and then save them. After saving the files, run the [compile_ts.sh](./compile_ts.sh) script. +You need to have [Qt6 Linguist](https://pkgs.org/search/?q=linguist&on=files) and [pylupdate6](https://pkgs.org/search/?q=pylupdate6&on=files) installed. Here are the steps: +- (Optional) To create a new translation file, use [compile_ts.sh](./compile_ts.sh) with the locale as the parameter, such as `sh compile.sh ja_JP`. This will create a ts file with the locale you entered +- Edit ts files in [/i18n/ts](./i18n/ts) with the linguist and then save them. After saving the files, run the [compile_ts.sh](./compile_ts.sh) script. This script fixes inconsistencies between Qt6 Linguist and pylupdate6, also removes line information so the git history stays cleaner +- To test your translations, use [install_pince.sh](./install_pince.sh). The last part of the installation script also compiles ts files to qm files so PINCE can process them. +When asked to recompile libscanmem, enter no Make sure that you read the comments in [tr.py](./tr/tr.py). Some of the translations have caveats that might interest you About the untranslated parts of the code, such as context menus of libpince reference widget. You'll see that some of the code serves as a placeholder that'll be removed or replaced in the future. These are not marked as translatable as translating them would be a waste of time +**ATTENTION:** Make sure you read this part even if you aren't a translator: +If you create or delete any Qt related string (for example, ui forms or translation constants in [tr.py](./tr/tr.py)), you must run [compile_ts.sh](./compile_ts.sh) so it updates the translations. +Not every string has to be translatable, if it's only printed on console, it can stay as is, in English. If it's shown to the user within a form, it should be translatable + # Logo All logo requests should be posted in `/media/logo/your_username`. Instead of opening a new issue, pull request your logo files to that folder. Your PR must include at least one png file named pince_small, pince_medium or pince_big, according to its size. So, a minimal PR will look like this: From c2df8f7f153fb5e8f38aaa09eab2f120ced3c96e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Thu, 10 Aug 2023 21:58:20 +0300 Subject: [PATCH 238/487] Update libscanmem submodule --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index df002428..729d3670 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit df002428b0ad779a5f7467911d8baf65eebae44a +Subproject commit 729d3670addd851af91008614e08b7bd4590e07e From 210151eb89eaf9d919f0aa8985f78b8d67559888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Thu, 10 Aug 2023 21:59:01 +0300 Subject: [PATCH 239/487] Change undo/redo/pid/reset commands to library function calls --- PINCE.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 1e5fceb0..34b03d6d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1044,7 +1044,7 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_UndoScan.setEnabled(True) search_scope = self.comboBox_ScanScope.currentData(Qt.ItemDataRole.UserRole) self.backend.send_command("option region_scan_level " + str(search_scope)) - self.backend.send_command("reset") + self.backend.reset() self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan self.comboBox_ScanType_init() @@ -1158,7 +1158,10 @@ def pushButton_NextScan_clicked(self, search_for=None): # ProgressBar global threadpool threadpool.start(Worker(self.update_progress_bar)) - self.backend.send_command(search_for) + if search_for == "undo": + self.backend.undo_scan() + else: + self.backend.send_command(search_for) matches = self.backend.matches() progress_running = 0 match_count = self.backend.get_match_count() @@ -1229,7 +1232,7 @@ def comboBox_ValueType_current_index_changed(self): self.lineEdit_Scan2.setValidator(validator_map[validator_str]) self.backend.send_command("option scan_data_type {}".format(scanmem_type)) # according to scanmem instructions you should always do `reset` after changing type - self.backend.send_command("reset") + self.backend.reset() def pushButton_AttachProcess_clicked(self): self.processwindow = ProcessForm(self) @@ -1268,7 +1271,7 @@ def attach_to_pid(self, pid): attach_result = GDB_Engine.attach(pid, gdb_path) if attach_result == type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL: self.apply_after_init() - self.backend.send_command("pid {}".format(pid)) + self.backend.pid(pid) self.on_new_process() # TODO: This makes PINCE call on_process_stop twice when attaching @@ -1332,7 +1335,7 @@ def copy_to_address_table(self): def reset_scan(self): self.scan_mode = type_defs.SCAN_MODE.NEW self.pushButton_NewFirstScan.setText(tr.FIRST_SCAN) - self.backend.send_command("reset") + self.backend.reset() self.tableWidget_valuesearchtable.setRowCount(0) self.comboBox_ValueType.setEnabled(True) self.comboBox_ScanScope.setEnabled(True) From 3466533766063e80e0e159a235341e2051758d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 21 Aug 2023 15:10:51 +0300 Subject: [PATCH 240/487] Optimize examine_expressions for update_address_table --- PINCE.py | 69 ++++++++++++++++++++++++++++-------------- libpince/GDB_Engine.py | 9 +++++- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/PINCE.py b/PINCE.py index 34b03d6d..38a44d75 100755 --- a/PINCE.py +++ b/PINCE.py @@ -950,8 +950,11 @@ def update_address_table(self): return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) mem_handle = GDB_Engine.memory_handle() - address_expr_list = [] rows = [] + address_list = [] + examine_indices = [] + examine_list = [] + index = 0 while True: row = it.value() if not row: @@ -959,28 +962,46 @@ def update_address_table(self): it += 1 address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) if isinstance(address_data, type_defs.PointerType): - pointer_address = GDB_Engine.read_pointer(address_data) - if pointer_address == None: - continue - address_expr_list.append(hex(pointer_address)) + address = address_data.base_address else: - address_expr_list.append(address_data) + address = address_data + # Simple addresses first, examine_expression takes much longer time, especially for larger tables + try: + int(address, 0) + except (ValueError, TypeError): + examine_list.append(address) + examine_indices.append(index) + address_list.append(address) rows.append(row) - address_list = [item.address for item in GDB_Engine.examine_expressions(address_expr_list)] + index += 1 + examine_list = [item.address for item in GDB_Engine.examine_expressions(examine_list)] + for index, address in enumerate(examine_list): + address_list[examine_indices[index]] = address for index, row in enumerate(rows): value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - address = address_list[index] - signed = True if value_type.value_repr == type_defs.VALUE_REPR.SIGNED else False - value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, - value_type.zero_terminate, signed, mem_handle=mem_handle) - address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) + current_address = address_list[index] if isinstance(address_data, type_defs.PointerType): - address_text = f'P->{address}' + # The original base could be a symbol so we have to save it + # This little hack makes it possible to call examine_expressions only once + if current_address: + old_base = address_data.base_address # save the old base + address_data.base_address = current_address + address = GDB_Engine.read_pointer(address_data) + address_data.base_address = old_base # then set it back + if address: + row.setText(ADDR_COL, f'P->{hex(address)}') + else: + row.setText(ADDR_COL, f'P->??') + else: + address = None + row.setText(ADDR_COL, f'P->??') else: - address_text = address - row.setText(ADDR_COL, address_text or address_expr_list[index]) - + address = current_address + row.setText(ADDR_COL, address or address_data) + signed = True if value_type.value_repr == type_defs.VALUE_REPR.SIGNED else False + value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, + value_type.zero_terminate, signed, mem_handle=mem_handle) if value is None: value = "" elif value_type.value_repr == type_defs.VALUE_REPR.HEX: @@ -1368,7 +1389,6 @@ def on_status_stopped(self): self.label_InferiorStatus.setText(tr.STATUS_STOPPED) self.label_InferiorStatus.setVisible(True) self.label_InferiorStatus.setStyleSheet("color: red") - self.update_address_table() def on_status_running(self): self.label_SelectedProcess.setStyleSheet("") @@ -1420,7 +1440,7 @@ def update_address_table_loop(self): try: self.update_address_table() except: - print("Update Address Table failed") + traceback.print_exc() def update_search_table_loop(self): while exiting == 0: @@ -1428,7 +1448,7 @@ def update_search_table_loop(self): try: self.update_search_table() except: - print("Update Search Table failed") + traceback.print_exc() def freeze_loop(self): while exiting == 0: @@ -1436,7 +1456,7 @@ def freeze_loop(self): try: self.freeze() except: - print("Freeze failed") + traceback.print_exc() # ---------------------------------------------------- @@ -1567,8 +1587,13 @@ def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, addre address = GDB_Engine.read_pointer(address_expr) address_text = f'P->{hex(address)}' if address != None else address_expr.get_base_address() else: - address = GDB_Engine.examine_expression(address_expr).address - address_text = address + # Simple addresses first, examine_expression takes much longer time, especially for larger tables + try: + address = int(address_expr, 0) + address_text = hex(address) + except (ValueError, TypeError): + address = GDB_Engine.examine_expression(address_expr).address + address_text = address value = '' if address: value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 6e486c31..f68fbdbd 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -736,7 +736,12 @@ def read_pointer(pointer_type): value_index = type_defs.VALUE_INDEX.INDEX_INT32 else: value_index = type_defs.VALUE_INDEX.INDEX_INT64 - start_address = examine_expression(pointer_type.base_address).address + + # Simple addresses first, examine_expression takes much longer time, especially for larger tables + try: + start_address = int(pointer_type.base_address, 0) + except (ValueError, TypeError): + start_address = examine_expression(pointer_type.base_address).address try: with memory_handle() as mem_handle: final_address = deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) @@ -944,6 +949,8 @@ def examine_expressions(expression_list): Returns: list: List of type_defs.tuple_examine_expression """ + if not expression_list: + return [] return send_command("pince-examine-expressions", send_with_file=True, file_contents_send=expression_list, recv_with_file=True) From 778f8b449cd17796bae79907c0e10c61a35bb2bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 21 Aug 2023 17:45:07 +0300 Subject: [PATCH 241/487] Fix read_pointer output on invalid symbols --- PINCE.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index 38a44d75..14a3b2b2 100755 --- a/PINCE.py +++ b/PINCE.py @@ -992,10 +992,11 @@ def update_address_table(self): if address: row.setText(ADDR_COL, f'P->{hex(address)}') else: - row.setText(ADDR_COL, f'P->??') + row.setText(ADDR_COL, 'P->??') else: + # We already know that base address is an invalid symbol, skip the read_pointer call address = None - row.setText(ADDR_COL, f'P->??') + row.setText(ADDR_COL, 'P->??') else: address = current_address row.setText(ADDR_COL, address or address_data) @@ -1585,7 +1586,7 @@ def treeWidget_AddressTable_edit_type(self): def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, address_expr="", value_type=None): if isinstance(address_expr, type_defs.PointerType): address = GDB_Engine.read_pointer(address_expr) - address_text = f'P->{hex(address)}' if address != None else address_expr.get_base_address() + address_text = f'P->{hex(address)}' if address != None else 'P->??' else: # Simple addresses first, examine_expression takes much longer time, especially for larger tables try: From a9e208962f884cce2d5ad6d403631f039faec28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 25 Aug 2023 20:10:36 +0300 Subject: [PATCH 242/487] Fix Stack and StackTrace windows when process is running --- PINCE.py | 17 +++++++++-------- .../gdb_python_scripts/GDBCommandExtensions.py | 17 ++++++++++++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/PINCE.py b/PINCE.py index 14a3b2b2..f21840a9 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3303,7 +3303,7 @@ def update_registers(self): self.FS.set_value(registers["fs"]) def update_stacktrace(self): - if GDB_Engine.currentpid == -1: + if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: return stack_trace_info = GDB_Engine.get_stacktrace_info() self.tableWidget_StackTrace.setRowCount(0) @@ -3354,7 +3354,7 @@ def copy_to_clipboard(row, column): pass def update_stack(self): - if GDB_Engine.currentpid == -1: + if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: return stack_info = GDB_Engine.get_stack_info() self.tableWidget_Stack.setRowCount(0) @@ -3389,16 +3389,17 @@ def tableWidget_Stack_key_press_event(self, event): self.tableWidget_Stack.keyPressEvent_original(event) def tableWidget_Stack_context_menu_event(self, event): - if GDB_Engine.currentpid == -1: - return - def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_Stack.item(row, column).text()) + if GDB_Engine.currentpid == -1: + return selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) - current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() - current_address = SysUtils.extract_address(current_address_text) - + if selected_row == -1: + current_address = None + else: + current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() + current_address = SysUtils.extract_address(current_address_text) menu = QMenu() switch_to_stacktrace = menu.addAction(tr.STACKTRACE) menu.addSeparator() diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 3467d93d..70a35b7b 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -126,7 +126,12 @@ def invoke(self, arg, from_tty): sp_register = "rsp" else: sp_register = "esp" - stack_pointer_int = int(ScriptUtils.examine_expression("$" + sp_register).address, 16) + stack_pointer = ScriptUtils.examine_expression(f"${sp_register}").address + if not stack_pointer: + print(f"Cannot get the value of ${sp_register}") + send_to_pince(stacktrace_info_list) + return + stack_pointer = int(stack_pointer, 16) result = gdb.execute("bt", from_tty, to_string=True) max_frame = common_regexes.max_frame_count.findall(result)[-1] @@ -134,7 +139,7 @@ def invoke(self, arg, from_tty): for item in range(int(max_frame) + 1): result = gdb.execute("info frame " + str(item), from_tty, to_string=True) frame_address = common_regexes.frame_address.search(result).group(1) - difference = hex(int(frame_address, 16) - stack_pointer_int) + difference = hex(int(frame_address, 16) - stack_pointer) frame_address_with_difference = frame_address + "(" + sp_register + "+" + difference + ")" return_address = common_regexes.return_address.search(result) if return_address: @@ -159,11 +164,17 @@ def invoke(self, arg, from_tty): chunk_size = 4 int_format = "I" sp_register = "esp" - sp_address = int(ScriptUtils.examine_expression("$" + sp_register).address, 16) + sp_address = ScriptUtils.examine_expression(f"${sp_register}").address + if not sp_address: + print(f"Cannot get the value of ${sp_register}") + send_to_pince(stack_info_list) + return + sp_address = int(sp_address, 16) with open(ScriptUtils.mem_file, "rb") as FILE: try: old_position = FILE.seek(sp_address) except (OSError, ValueError): + print(f"Cannot accesss the memory at {hex(sp_address)}") send_to_pince(stack_info_list) return for index in range(int(4096 / chunk_size)): From 7d3a604cf6001d77658252be88e4bd386635f2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 25 Aug 2023 20:20:48 +0300 Subject: [PATCH 243/487] Fix refresh for tableWidget_Stack_key_press_event --- PINCE.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/PINCE.py b/PINCE.py index f21840a9..9d1585df 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3371,17 +3371,20 @@ def tableWidget_Stack_key_press_event(self, event): return selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) if selected_row == -1: - return - current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() - current_address = SysUtils.extract_address(current_address_text) + actions = type_defs.KeyboardModifiersTupleDict([ + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack) + ]) + else: + current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() + current_address = SysUtils.extract_address(current_address_text) - actions = type_defs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), - lambda: self.disassemble_expression(current_address, append_to_travel_history=True)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), - lambda: self.hex_dump_address(int(current_address, 16))) - ]) + actions = type_defs.KeyboardModifiersTupleDict([ + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), + lambda: self.disassemble_expression(current_address, append_to_travel_history=True)), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), + lambda: self.hex_dump_address(int(current_address, 16))) + ]) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: From 162b254ba9b9c672a696129ad3fecf2ac061eaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 27 Aug 2023 12:13:09 +0300 Subject: [PATCH 244/487] Fix Stack and StackTrace exceptions --- PINCE.py | 11 +++++++++++ i18n/ts/it_IT.ts | 5 +++++ i18n/ts/zh_CN.ts | 5 +++++ libpince/gdb_python_scripts/GDBCommandExtensions.py | 10 ++++++++-- tr/tr.py | 1 + 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 9d1585df..e13a67de 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3214,6 +3214,12 @@ def on_process_stop(self): self.update_stacktrace() elif self.stackedWidget_StackScreens.currentWidget() == self.Stack: self.update_stack() + + # These tableWidgets are never emptied but initially both are empty, so this runs only once + if self.tableWidget_StackTrace.rowCount() == 0: + self.update_stacktrace() + if self.tableWidget_Stack.rowCount() == 0: + self.update_stack() self.refresh_hex_view() if bring_disassemble_to_front: self.showMaximized() @@ -4059,10 +4065,15 @@ def __init__(self, parent=None): def update_stacktrace(self): self.listWidget_ReturnAddresses.clear() + if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + return return_addresses = GDB_Engine.get_stack_frame_return_addresses() self.listWidget_ReturnAddresses.addItems(return_addresses) def update_frame_info(self, index): + if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + self.textBrowser_Info.setText(tr.PROCESS_RUNNING) + return frame_info = GDB_Engine.get_stack_frame_info(index) self.textBrowser_Info.setText(frame_info) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index b1a996cc..28a04a82 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1537,6 +1537,11 @@ To change the current GDB path, check Settings->Debug [stopped] + + + Process is running + + Enter the new value diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index ad3865f6..a31bd864 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1541,6 +1541,11 @@ To change the current GDB path, check Settings->Debug [stopped] [已停止] + + + Process is running + + Enter the new value diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 70a35b7b..697cef5d 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -137,7 +137,10 @@ def invoke(self, arg, from_tty): # +1 because frame numbers start from 0 for item in range(int(max_frame) + 1): - result = gdb.execute("info frame " + str(item), from_tty, to_string=True) + try: + result = gdb.execute(f"info frame {item}", from_tty, to_string=True) + except: + break frame_address = common_regexes.frame_address.search(result).group(1) difference = hex(int(frame_address, 16) - stack_pointer) frame_address_with_difference = frame_address + "(" + sp_register + "+" + difference + ")" @@ -215,7 +218,10 @@ def invoke(self, arg, from_tty): # +1 because frame numbers start from 0 for item in range(int(max_frame) + 1): - result = gdb.execute("info frame " + str(item), from_tty, to_string=True) + try: + result = gdb.execute(f"info frame {item}", from_tty, to_string=True) + except: + break return_address = common_regexes.return_address.search(result) if return_address: return_address_with_info = ScriptUtils.examine_expression(return_address.group(1)).all diff --git a/tr/tr.py b/tr/tr.py index a5e1522a..706eb75b 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -73,6 +73,7 @@ def translate(): NO_PROCESS_SELECTED = QT_TR_NOOP("No Process Selected") STATUS_DETACHED = QT_TR_NOOP("[detached]") STATUS_STOPPED = QT_TR_NOOP("[stopped]") + PROCESS_RUNNING = QT_TR_NOOP("Process is running") ENTER_VALUE = QT_TR_NOOP("Enter the new value") ENTER_DESCRIPTION = QT_TR_NOOP("Enter the new description") EDIT_ADDRESS = QT_TR_NOOP("Edit Address") From 52a5928ebcad075b904c833a0fa41629c1380064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 27 Aug 2023 17:22:41 +0300 Subject: [PATCH 245/487] Replace exit loop with parsing --- PINCE.py | 1 + libpince/GDB_Engine.py | 35 +++++++++++------------------------ 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/PINCE.py b/PINCE.py index e13a67de..ad4828cd 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1378,6 +1378,7 @@ def on_inferior_exit(self): self.flashAttachButton = True self.flashAttachButtonTimer.start(100) self.label_SelectedProcess.setText(tr.NO_PROCESS_SELECTED) + self.memory_view_window.setWindowTitle(tr.NO_PROCESS_SELECTED) def on_status_detached(self): self.label_SelectedProcess.setStyleSheet("color: blue") diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index f68fbdbd..3cb39522 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -253,23 +253,6 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, return output -def await_process_exit(): - """ - Checks if the current inferior is alive, uses conditions to inform other functions and threads about inferiors state - Detaches if the current inferior dies while attached - Should be called by creating a thread. Usually called in initialization process by attach function - """ - while True: - if currentpid == -1 or SysUtils.is_process_valid(currentpid): - sleep(0.1) - else: - with process_exited_condition: - print("Process terminated (PID:" + str(currentpid) + ")") - process_exited_condition.notify_all() - detach() - break - - def state_observe_thread(): """ Observes the state of gdb, uses conditions to inform other functions and threads about gdb's state @@ -283,6 +266,16 @@ def check_inferior_status(): global stop_reason global inferior_status old_status = inferior_status + for match in matches: + if match[0].startswith('stopped,reason="exited'): + with process_exited_condition: + detach() + print(f"Process terminated (PID:{currentpid})") + process_exited_condition.notify_all() + return + + # For multiline outputs, only the last async event is important + # Get the last match only to optimize parsing stop_info = matches[-1][0] if stop_info: bp_num = common_regexes.breakpoint_number.search(stop_info) @@ -319,7 +312,7 @@ def check_inferior_status(): if gdb_output_mode.async_output: print(child.before) gdb_async_output.broadcast_message(child.before) - except OSError: + except (OSError, ValueError): print("Exiting state_observe_thread") @@ -566,9 +559,6 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() - await_exit_thread = Thread(target=await_process_exit) - await_exit_thread.daemon = True - await_exit_thread.start() SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_AA_PATH)) return type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL @@ -622,9 +612,6 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() - await_exit_thread = Thread(target=await_process_exit) - await_exit_thread.daemon = True - await_exit_thread.start() SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_AA_PATH)) return True From 5041fc89de3f2742bbdf8eb27de3e328e3fe827e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 12 Sep 2023 09:49:33 +0300 Subject: [PATCH 246/487] Replace some Worker instances with QTimer --- PINCE.py | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/PINCE.py b/PINCE.py index ad4828cd..b34d9579 100755 --- a/PINCE.py +++ b/PINCE.py @@ -457,13 +457,12 @@ def __init__(self): self.check_status_thread.process_stopped.connect(self.memory_view_window.process_stopped) self.check_status_thread.process_running.connect(self.memory_view_window.process_running) self.check_status_thread.start() - self.update_address_table_thread = Worker(self.update_address_table_loop) - self.update_search_table_thread = Worker(self.update_search_table_loop) - self.freeze_thread = Worker(self.freeze_loop) - global threadpool - threadpool.start(self.update_address_table_thread) - threadpool.start(self.update_search_table_thread) - threadpool.start(self.freeze_thread) + self.address_table_timer = QTimer(timeout=self.address_table_loop, singleShot=True) + self.address_table_timer.start() + self.search_table_timer = QTimer(timeout=self.search_table_loop, singleShot=True) + self.search_table_timer.start() + self.freeze_timer = QTimer(timeout=self.freeze_loop, singleShot=True) + self.freeze_timer.start() self.shortcut_open_file = QShortcut(QKeySequence("Ctrl+O"), self) self.shortcut_open_file.activated.connect(self.pushButton_Open_clicked) GuiUtils.append_shortcut_to_tooltip(self.pushButton_Open, self.shortcut_open_file) @@ -1187,8 +1186,8 @@ def pushButton_NextScan_clicked(self, search_for=None): matches = self.backend.matches() progress_running = 0 match_count = self.backend.get_match_count() - if match_count > 10000: - self.label_MatchCount.setText(tr.MATCH_COUNT_LIMITED.format(match_count, 10000)) + if match_count > 1000: + self.label_MatchCount.setText(tr.MATCH_COUNT_LIMITED.format(match_count, 1000)) else: self.label_MatchCount.setText(tr.MATCH_COUNT.format(match_count)) self.tableWidget_valuesearchtable.setRowCount(0) @@ -1210,7 +1209,7 @@ def pushButton_NextScan_clicked(self, search_for=None): self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_ADDRESS_COL, current_item) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_VALUE_COL, QTableWidgetItem(value)) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_PREVIOUS_COL, QTableWidgetItem(value)) - if n == 10000: + if n == 1000: break def _scan_to_length(self, type_index): @@ -1435,30 +1434,30 @@ def update_progress_bar(self): value = int(round(self.backend.get_scan_progress() * 100)) self.progressBar.setValue(value) - def update_address_table_loop(self): - while exiting == 0: - sleep(table_update_interval / 1000) - if update_table: - try: - self.update_address_table() - except: - traceback.print_exc() + # Loop restarts itself to wait for function execution, same for the functions below + def address_table_loop(self): + if update_table and not exiting: + try: + self.update_address_table() + except: + traceback.print_exc() + self.address_table_timer.start(table_update_interval) - def update_search_table_loop(self): - while exiting == 0: - sleep(0.5) + def search_table_loop(self): + if not exiting: try: self.update_search_table() except: traceback.print_exc() + self.search_table_timer.start(500) def freeze_loop(self): - while exiting == 0: - sleep(freeze_interval / 1000) + if not exiting: try: self.freeze() except: traceback.print_exc() + self.freeze_timer.start(freeze_interval) # ---------------------------------------------------- From 52f0ec9476f3a2442dc5217c72c061053e1f4464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 15 Sep 2023 22:01:02 +0300 Subject: [PATCH 247/487] Implement gdb expression cache --- PINCE.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index b34d9579..c3c9fd23 100755 --- a/PINCE.py +++ b/PINCE.py @@ -294,6 +294,13 @@ def get_hotkeys(): # see UpdateAddressTableThread saved_addresses_changed_list = list() +# GDB expression cache +# TODO: Try to find a fast and non-gdb way to calculate symbols so we don't need this +# This is one of the few tricks we do to minimize examine_expressions calls +# This solution might bring problems if the symbols are changing frequently +# Currently only address_table_loop uses this so user can refresh symbols with a button press +exp_cache = {} + # vars for communication/storage with the non blocking threads exiting = 0 progress_running = 0 @@ -562,7 +569,9 @@ def set_default_settings(self): def apply_after_init(self): global gdb_logging global ignored_signals + global exp_cache + exp_cache.clear() gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) ignored_signals = self.settings.value("Debug/ignored_signals", type=str) GDB_Engine.set_logging(gdb_logging) @@ -944,7 +953,8 @@ def treeWidget_AddressTable_key_press_event(self, event): except KeyError: self.treeWidget_AddressTable.keyPressEvent_original(event) - def update_address_table(self): + def update_address_table(self, use_cache=False): + global exp_cache if GDB_Engine.currentpid == -1 or self.treeWidget_AddressTable.topLevelItemCount() == 0: return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) @@ -968,14 +978,17 @@ def update_address_table(self): try: int(address, 0) except (ValueError, TypeError): - examine_list.append(address) - examine_indices.append(index) + if use_cache and address in exp_cache: + address = exp_cache[address] + else: + examine_list.append(address) + examine_indices.append(index) address_list.append(address) rows.append(row) index += 1 - examine_list = [item.address for item in GDB_Engine.examine_expressions(examine_list)] - for index, address in enumerate(examine_list): - address_list[examine_indices[index]] = address + for index, item in enumerate(GDB_Engine.examine_expressions(examine_list)): + exp_cache[examine_list[index]] = item.address + address_list[examine_indices[index]] = item.address for index, row in enumerate(rows): value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) @@ -1438,7 +1451,7 @@ def update_progress_bar(self): def address_table_loop(self): if update_table and not exiting: try: - self.update_address_table() + self.update_address_table(use_cache=True) except: traceback.print_exc() self.address_table_timer.start(table_update_interval) From 020f3c9104f0d8557f7558e7a51b8b7f67db9fcf Mon Sep 17 00:00:00 2001 From: Berk Date: Mon, 18 Sep 2023 01:52:27 +0100 Subject: [PATCH 248/487] Fix vimspector missing modules issue --- .vimspector.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vimspector.json b/.vimspector.json index db0c78dc..8955a556 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -19,7 +19,10 @@ "justMyCode": false, "sudo": true, "console": "integratedTerminal", - "program": "${workspaceFolder}/PINCE.py" + "program": "${workspaceFolder}/PINCE.py", + "env": { + "PATH": "${PATH}" + } }, "breakpoints": { "exception": { From 3ca6424b2edfe0d320b12434231ae43798a1c17a Mon Sep 17 00:00:00 2001 From: Berk Date: Mon, 18 Sep 2023 02:21:00 +0100 Subject: [PATCH 249/487] Push scanmem fixes --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index 729d3670..f396cf54 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit 729d3670addd851af91008614e08b7bd4590e07e +Subproject commit f396cf5446ac45ca997e78f0acde46baa0f85126 From f2f7b5d45d63357a922f385f8bfd48400338a21b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 18 Sep 2023 20:16:39 +0300 Subject: [PATCH 250/487] Scan in separate thread --- PINCE.py | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/PINCE.py b/PINCE.py index c3c9fd23..1be9a2f6 100755 --- a/PINCE.py +++ b/PINCE.py @@ -32,9 +32,9 @@ from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame -from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, \ - QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QThreadPool, \ - QTranslator, QLocale, pyqtSlot +from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ + QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ + QLocale from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect @@ -301,26 +301,27 @@ def get_hotkeys(): # Currently only address_table_loop uses this so user can refresh symbols with a button press exp_cache = {} -# vars for communication/storage with the non blocking threads +# vars for communication with the non blocking threads exiting = 0 -progress_running = 0 threadpool = QThreadPool() # Placeholder number, may have to be changed in the future threadpool.setMaxThreadCount(10) +class WorkerSignals(QObject): + finished = pyqtSignal() class Worker(QRunnable): def __init__(self, fn, *args, **kwargs): super(Worker, self).__init__() - self.fn = fn self.args = args self.kwargs = kwargs + self.signals = WorkerSignals() - @pyqtSlot() def run(self): self.fn(*self.args, **self.kwargs) + self.signals.finished.emit() def except_hook(exception_type, value, tb): @@ -1183,21 +1184,25 @@ def validate_search(self, search_for, search_for2): return search_for def pushButton_NextScan_clicked(self, search_for=None): + global threadpool if GDB_Engine.currentpid == -1: return - global progress_running if not search_for: search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) - - # ProgressBar - global threadpool - threadpool.start(Worker(self.update_progress_bar)) + self.QWidget_Toolbox.setEnabled(False) + self.progressBar.setValue(0) + self.progress_bar_timer = QTimer(timeout=self.update_progress_bar) + self.progress_bar_timer.start(100) if search_for == "undo": - self.backend.undo_scan() + scan_thread = Worker(self.backend.undo_scan) else: - self.backend.send_command(search_for) + scan_thread = Worker(self.backend.send_command, search_for) + scan_thread.signals.finished.connect(self.scan_callback) + threadpool.start(scan_thread) + + def scan_callback(self): + self.progress_bar_timer.stop() matches = self.backend.matches() - progress_running = 0 match_count = self.backend.get_match_count() if match_count > 1000: self.label_MatchCount.setText(tr.MATCH_COUNT_LIMITED.format(match_count, 1000)) @@ -1224,6 +1229,7 @@ def pushButton_NextScan_clicked(self, search_for=None): self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_PREVIOUS_COL, QTableWidgetItem(value)) if n == 1000: break + self.QWidget_Toolbox.setEnabled(True) def _scan_to_length(self, type_index): if type_index == type_defs.SCAN_INDEX.INDEX_AOB: @@ -1435,17 +1441,11 @@ def treeWidget_AddressTable_item_double_clicked(self, row, column): action_for_column[column]() # ---------------------------------------------------- - # Async Functions + # QTimer loops def update_progress_bar(self): - global progress_running - global exiting - self.progressBar.setValue(0) - progress_running = 1 - while progress_running == 1 and exiting == 0: - sleep(0.1) - value = int(round(self.backend.get_scan_progress() * 100)) - self.progressBar.setValue(value) + value = int(round(self.backend.get_scan_progress() * 100)) + self.progressBar.setValue(value) # Loop restarts itself to wait for function execution, same for the functions below def address_table_loop(self): From 2f630535899d34a5be53dcfd1ea3851375f4dda4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 18 Sep 2023 20:57:59 +0300 Subject: [PATCH 251/487] Separate scanmem from MainForm --- PINCE.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/PINCE.py b/PINCE.py index 1be9a2f6..f2c0b267 100755 --- a/PINCE.py +++ b/PINCE.py @@ -304,6 +304,8 @@ def get_hotkeys(): # vars for communication with the non blocking threads exiting = 0 +scanmem = Scanmem(os.path.join(SysUtils.get_libpince_directory(), "libscanmem", "libscanmem.so")) + threadpool = QThreadPool() # Placeholder number, may have to be changed in the future threadpool.setMaxThreadCount(10) @@ -449,11 +451,6 @@ def __init__(self): InputDialogForm(item_list=[(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() else: self.apply_after_init() - - # This should be changed, only works if you use the current directory - # Fails if you for example install it to some place like bin - libscanmem_path = os.path.join(os.getcwd(), "libpince", "libscanmem", "libscanmem.so") - self.backend = Scanmem(libscanmem_path) self.memory_view_window = MemoryViewWindowForm(self) self.about_widget = AboutWidgetForm() self.await_exit_thread = AwaitProcessExit() @@ -1078,8 +1075,8 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_NextScan.setEnabled(True) self.pushButton_UndoScan.setEnabled(True) search_scope = self.comboBox_ScanScope.currentData(Qt.ItemDataRole.UserRole) - self.backend.send_command("option region_scan_level " + str(search_scope)) - self.backend.reset() + scanmem.send_command("option region_scan_level " + str(search_scope)) + scanmem.reset() self.comboBox_ScanScope.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan self.comboBox_ScanType_init() @@ -1194,16 +1191,16 @@ def pushButton_NextScan_clicked(self, search_for=None): self.progress_bar_timer = QTimer(timeout=self.update_progress_bar) self.progress_bar_timer.start(100) if search_for == "undo": - scan_thread = Worker(self.backend.undo_scan) + scan_thread = Worker(scanmem.undo_scan) else: - scan_thread = Worker(self.backend.send_command, search_for) + scan_thread = Worker(scanmem.send_command, search_for) scan_thread.signals.finished.connect(self.scan_callback) threadpool.start(scan_thread) def scan_callback(self): self.progress_bar_timer.stop() - matches = self.backend.matches() - match_count = self.backend.get_match_count() + matches = scanmem.matches() + match_count = scanmem.get_match_count() if match_count > 1000: self.label_MatchCount.setText(tr.MATCH_COUNT_LIMITED.format(match_count, 1000)) else: @@ -1270,9 +1267,9 @@ def comboBox_ValueType_current_index_changed(self): self.lineEdit_Scan.setValidator(validator_map[validator_str]) self.lineEdit_Scan2.setValidator(validator_map[validator_str]) - self.backend.send_command("option scan_data_type {}".format(scanmem_type)) + scanmem.send_command("option scan_data_type {}".format(scanmem_type)) # according to scanmem instructions you should always do `reset` after changing type - self.backend.reset() + scanmem.reset() def pushButton_AttachProcess_clicked(self): self.processwindow = ProcessForm(self) @@ -1311,7 +1308,7 @@ def attach_to_pid(self, pid): attach_result = GDB_Engine.attach(pid, gdb_path) if attach_result == type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL: self.apply_after_init() - self.backend.pid(pid) + scanmem.pid(pid) self.on_new_process() # TODO: This makes PINCE call on_process_stop twice when attaching @@ -1375,7 +1372,7 @@ def copy_to_address_table(self): def reset_scan(self): self.scan_mode = type_defs.SCAN_MODE.NEW self.pushButton_NewFirstScan.setText(tr.FIRST_SCAN) - self.backend.reset() + scanmem.reset() self.tableWidget_valuesearchtable.setRowCount(0) self.comboBox_ValueType.setEnabled(True) self.comboBox_ScanScope.setEnabled(True) @@ -1444,7 +1441,7 @@ def treeWidget_AddressTable_item_double_clicked(self, row, column): # QTimer loops def update_progress_bar(self): - value = int(round(self.backend.get_scan_progress() * 100)) + value = int(round(scanmem.get_scan_progress() * 100)) self.progressBar.setValue(value) # Loop restarts itself to wait for function execution, same for the functions below From 31e426c2029757d691be1dc3a228b78d840a6a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 19 Sep 2023 17:13:01 +0300 Subject: [PATCH 252/487] Remove KeyboardInterrupt from signal_handler --- PINCE.py | 1 - 1 file changed, 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index f2c0b267..f4fc2c30 100755 --- a/PINCE.py +++ b/PINCE.py @@ -340,7 +340,6 @@ def except_hook(exception_type, value, tb): def signal_handler(signal, frame): GDB_Engine.cancel_last_command() - raise KeyboardInterrupt signal.signal(signal.SIGINT, signal_handler) From 642076cde08dabb2d061d16facf9c0e3dbbd0a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 19 Sep 2023 17:19:53 +0300 Subject: [PATCH 253/487] Fix tableWidget_SymbolInfo_current_changed when nothing is selected --- PINCE.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index f4fc2c30..e662f5ed 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4760,14 +4760,16 @@ def apply_data(self, output): def tableWidget_SymbolInfo_current_changed(self, QModelIndex_current): self.textBrowser_AddressInfo.clear() - address = self.tableWidget_SymbolInfo.item(QModelIndex_current.row(), FUNCTIONS_INFO_ADDR_COL).text() - if SysUtils.extract_address(address): - symbol = self.tableWidget_SymbolInfo.item(QModelIndex_current.row(), FUNCTIONS_INFO_SYMBOL_COL).text() - for item in SysUtils.split_symbol(symbol): - info = GDB_Engine.get_symbol_info(item) - self.textBrowser_AddressInfo.append(info) - else: - self.textBrowser_AddressInfo.append(tr.DEFINED_SYMBOL) + current_item = self.tableWidget_SymbolInfo.item(QModelIndex_current.row(), FUNCTIONS_INFO_ADDR_COL) + if current_item: + address = current_item.text() + if SysUtils.extract_address(address): + symbol = self.tableWidget_SymbolInfo.item(QModelIndex_current.row(), FUNCTIONS_INFO_SYMBOL_COL).text() + for item in SysUtils.split_symbol(symbol): + info = GDB_Engine.get_symbol_info(item) + self.textBrowser_AddressInfo.append(info) + else: + self.textBrowser_AddressInfo.append(tr.DEFINED_SYMBOL) def tableWidget_SymbolInfo_context_menu_event(self, event): def copy_to_clipboard(row, column): From 7129559ead9ceb6d388adccf7078c855307a1a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 19 Sep 2023 17:30:46 +0300 Subject: [PATCH 254/487] Change usage of QModelIndex_current for tableWidget_SymbolInfo_current_changed This keeps the coding style a bit more consistent --- PINCE.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/PINCE.py b/PINCE.py index e662f5ed..e7025d23 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4760,16 +4760,17 @@ def apply_data(self, output): def tableWidget_SymbolInfo_current_changed(self, QModelIndex_current): self.textBrowser_AddressInfo.clear() - current_item = self.tableWidget_SymbolInfo.item(QModelIndex_current.row(), FUNCTIONS_INFO_ADDR_COL) - if current_item: - address = current_item.text() - if SysUtils.extract_address(address): - symbol = self.tableWidget_SymbolInfo.item(QModelIndex_current.row(), FUNCTIONS_INFO_SYMBOL_COL).text() - for item in SysUtils.split_symbol(symbol): - info = GDB_Engine.get_symbol_info(item) - self.textBrowser_AddressInfo.append(info) - else: - self.textBrowser_AddressInfo.append(tr.DEFINED_SYMBOL) + current_row = QModelIndex_current.row() + if current_row < 0: + return + address = self.tableWidget_SymbolInfo.item(current_row, FUNCTIONS_INFO_ADDR_COL).text() + if SysUtils.extract_address(address): + symbol = self.tableWidget_SymbolInfo.item(current_row, FUNCTIONS_INFO_SYMBOL_COL).text() + for item in SysUtils.split_symbol(symbol): + info = GDB_Engine.get_symbol_info(item) + self.textBrowser_AddressInfo.append(info) + else: + self.textBrowser_AddressInfo.append(tr.DEFINED_SYMBOL) def tableWidget_SymbolInfo_context_menu_event(self, event): def copy_to_clipboard(row, column): From 59064c07ddb39e78642f30bd5870e7c137dca33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 19 Sep 2023 18:00:28 +0300 Subject: [PATCH 255/487] Set progressBar value to 100 on callback --- PINCE.py | 1 + 1 file changed, 1 insertion(+) diff --git a/PINCE.py b/PINCE.py index e7025d23..99558d1d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1198,6 +1198,7 @@ def pushButton_NextScan_clicked(self, search_for=None): def scan_callback(self): self.progress_bar_timer.stop() + self.progressBar.setValue(100) matches = scanmem.matches() match_count = scanmem.get_match_count() if match_count > 1000: From 853400f8f2ee3c91b45da9d7d333970b736a62e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 20 Sep 2023 18:10:21 +0300 Subject: [PATCH 256/487] signal_handler can now quit PINCE --- PINCE.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 99558d1d..f6fc170a 100755 --- a/PINCE.py +++ b/PINCE.py @@ -339,7 +339,17 @@ def except_hook(exception_type, value, tb): def signal_handler(signal, frame): - GDB_Engine.cancel_last_command() + if GDB_Engine.lock_send_command.locked(): + print("\nCancelling the last GDB command") + GDB_Engine.cancel_last_command() + else: + try: + text = input("\nNo GDB command to cancel, quit PINCE? (y/n)") + if text.lower().startswith("y"): + quit() + except RuntimeError: + print() # Prints a newline so the terminal looks nicer when we quit + quit() signal.signal(signal.SIGINT, signal_handler) From 72deb40238c20dca41216323a2664991c2da26fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 22 Sep 2023 16:35:00 +0300 Subject: [PATCH 257/487] Change pointer behavior for ManualAddressDialog --- PINCE.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index f6fc170a..51e88734 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1835,7 +1835,7 @@ def addOffsetLayout(self, should_update=True): self.update_value_of_address() def removeOffsetLayout(self): - if len(self.offsetsList) == 0: + if len(self.offsetsList) == 1: return frame = self.offsetsList[-1] frame.deleteLater() @@ -1887,10 +1887,13 @@ def comboBox_ValueType_current_index_changed(self): self.checkBox_zeroterminate.hide() if self.checkBox_IsPointer.isChecked(): self.lineEdit_address.setEnabled(False) - if self.lineEdit_PtrStartAddress.text() == "": - self.lineEdit_PtrStartAddress.setText(self.lineEdit_address.text()) + self.lineEdit_PtrStartAddress.setText(self.lineEdit_address.text()) + if len(self.offsetsList) == 0: + self.addOffsetLayout(False) self.widget_Pointer.show() else: + self.lineEdit_address.setText(self.lineEdit_PtrStartAddress.text()) + self.lineEdit_PtrStartAddress.setText("") self.lineEdit_address.setEnabled(True) self.widget_Pointer.hide() self.setFixedSize(self.layout().sizeHint()) @@ -1931,8 +1934,7 @@ def get_values(self): def get_offsets_int_list(self): offsetsIntList = [] for frame in self.offsetsList: - layout = frame.layout() - offsetText = layout.itemAt(1).widget().text() + offsetText = frame.layout().itemAt(1).widget().text() try: offsetValue = int(offsetText, 16) except ValueError: @@ -1947,8 +1949,7 @@ def create_offsets_list(self, address): for offset in address.offsets_list: self.addOffsetLayout(False) frame = self.offsetsList[-1] - layout = frame.layout() - offsetText = layout.itemAt(1).widget().setText(hex(offset)) + frame.layout().itemAt(1).widget().setText(hex(offset)) def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): offsetText = offsetTextWidget.text() From f877b5ddcbcc2b7c9f986970835225533d35f986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 22 Sep 2023 19:24:57 +0300 Subject: [PATCH 258/487] Fix the parser for TrackBreakpointWidget --- PINCE.py | 21 +++++++++------------ libpince/common_regexes.py | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/PINCE.py b/PINCE.py index 51e88734..33941658 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4336,7 +4336,7 @@ def __init__(self, address, length, watchpoint_type, parent=None): instances.append(self) GuiUtils.center(self) self.setWindowFlags(Qt.WindowType.Window) - self.update_timer = QTimer() + self.update_timer = QTimer(timeout=self.update_list) if watchpoint_type == type_defs.WATCHPOINT_TYPE.WRITE_ONLY: string = tr.OPCODE_WRITING_TO.format(address) elif watchpoint_type == type_defs.WATCHPOINT_TYPE.READ_ONLY: @@ -4359,9 +4359,7 @@ def __init__(self, address, length, watchpoint_type, parent=None): self.pushButton_Refresh.clicked.connect(self.update_list) self.tableWidget_Opcodes.itemDoubleClicked.connect(self.tableWidget_Opcodes_item_double_clicked) self.tableWidget_Opcodes.selectionModel().currentChanged.connect(self.tableWidget_Opcodes_current_changed) - self.update_timer.setInterval(100) - self.update_timer.timeout.connect(self.update_list) - self.update_timer.start() + self.update_timer.start(100) def update_list(self): info = GDB_Engine.get_track_watchpoint_info(self.breakpoints) @@ -4426,6 +4424,8 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.parent = lambda: parent global instances instances.append(self) + self.update_list_timer = QTimer(timeout=self.update_list) + self.update_values_timer = QTimer(timeout=self.update_values) self.setWindowFlags(Qt.WindowType.Window) GuiUtils.center_to_parent(self) self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) @@ -4443,11 +4443,8 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.tableWidget_TrackInfo.itemDoubleClicked.connect(self.tableWidget_TrackInfo_item_double_clicked) self.tableWidget_TrackInfo.selectionModel().currentChanged.connect(self.tableWidget_TrackInfo_current_changed) self.comboBox_ValueType.currentIndexChanged.connect(self.update_values) - self.update_timer = QTimer() - self.update_timer.setInterval(100) - self.update_timer.timeout.connect(self.update_list) - self.update_timer.start() - self.parent().process_stopped.connect(self.update_values) + self.update_list_timer.start(100) + self.update_values_timer.start(500) self.parent().refresh_disassemble_view() def update_list(self): @@ -4466,8 +4463,7 @@ def update_list(self): self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_ADDR_COL, QTableWidgetItem(address)) self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_SOURCE_COL, QTableWidgetItem("[" + register_expression + "]")) - GuiUtils.resize_to_contents(self.tableWidget_TrackInfo) - self.tableWidget_TrackInfo.selectRow(self.last_selected_row) + self.update_values() def update_values(self): mem_handle = GDB_Engine.memory_handle() @@ -4503,7 +4499,8 @@ def pushButton_Stop_clicked(self): def closeEvent(self, QCloseEvent): global instances - self.update_timer.stop() + self.update_list_timer.stop() + self.update_values_timer.stop() if not self.stopped: GDB_Engine.delete_breakpoint(self.address) self.parent().refresh_disassemble_view() diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index 9a07d10d..39aa7b1b 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -32,7 +32,7 @@ hw_breakpoint_count = compile(r"(hw|read|acc)") breakpoint_size = compile(r"char\[(\d+)\]") breakpoint_created = compile(r"breakpoint-created") -breakpoint_number = compile(r"number=\"(\d+)\"") +breakpoint_number = compile(r"(?:number|bkptno)=\"(\d+)\"") convenience_variable = compile(r'"(\$\d+)\s+=\s+(.*)"') # "$26 = 3" entry_point = compile(r"Entry\s+point:\s+" + hex_number_grouped.pattern) # The command will always start with the word "source", check GDB_Engine.send_command function for the cause From ad189f6139428e75e119c682719df875533dec8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 23 Sep 2023 16:50:37 +0300 Subject: [PATCH 259/487] Fix variable assigning order for tracking widgets --- PINCE.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index 33941658..96790fd7 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4337,6 +4337,8 @@ def __init__(self, address, length, watchpoint_type, parent=None): GuiUtils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.update_timer = QTimer(timeout=self.update_list) + self.stopped = False + self.address = address if watchpoint_type == type_defs.WATCHPOINT_TYPE.WRITE_ONLY: string = tr.OPCODE_WRITING_TO.format(address) elif watchpoint_type == type_defs.WATCHPOINT_TYPE.READ_ONLY: @@ -4350,11 +4352,9 @@ def __init__(self, address, length, watchpoint_type, parent=None): if not breakpoints: QMessageBox.information(self, tr.ERROR, tr.TRACK_WATCHPOINT_FAILED.format(address)) return - self.address = address self.breakpoints = breakpoints self.info = {} self.last_selected_row = 0 - self.stopped = False self.pushButton_Stop.clicked.connect(self.pushButton_Stop_clicked) self.pushButton_Refresh.clicked.connect(self.update_list) self.tableWidget_Opcodes.itemDoubleClicked.connect(self.tableWidget_Opcodes_item_double_clicked) @@ -4426,6 +4426,8 @@ def __init__(self, address, instruction, register_expressions, parent=None): instances.append(self) self.update_list_timer = QTimer(timeout=self.update_list) self.update_values_timer = QTimer(timeout=self.update_values) + self.stopped = False + self.address = address self.setWindowFlags(Qt.WindowType.Window) GuiUtils.center_to_parent(self) self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) @@ -4433,11 +4435,9 @@ def __init__(self, address, instruction, register_expressions, parent=None): if not breakpoint: QMessageBox.information(self, tr.ERROR, tr.TRACK_BREAKPOINT_FAILED.format(address)) return - self.address = address self.breakpoint = breakpoint self.info = {} self.last_selected_row = 0 - self.stopped = False GuiUtils.fill_value_combobox(self.comboBox_ValueType) self.pushButton_Stop.clicked.connect(self.pushButton_Stop_clicked) self.tableWidget_TrackInfo.itemDoubleClicked.connect(self.tableWidget_TrackInfo_item_double_clicked) From 161758a1915f4a10effdfc6da2e4000b8bc8d8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 23 Sep 2023 17:15:03 +0300 Subject: [PATCH 260/487] Fix actionToggle_Attach trigger --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 96790fd7..56c80bef 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2591,7 +2591,7 @@ def initialize_file_context_menu(self): def initialize_debug_context_menu(self): self.actionBreak.triggered.connect(GDB_Engine.interrupt_inferior) self.actionRun.triggered.connect(GDB_Engine.continue_inferior) - self.actionToggle_Attach.triggered.connect(self.parent().toggle_attach_hotkey_pressed) + self.actionToggle_Attach.triggered.connect(lambda: self.parent().toggle_attach_hotkey_pressed()) self.actionStep.triggered.connect(self.step_instruction) self.actionStep_Over.triggered.connect(self.step_over_instruction) self.actionExecute_Till_Return.triggered.connect(self.execute_till_return) From daebbfcabaacc82d1b123c1dfb41e6c4ff72c27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 22 Oct 2023 19:46:24 +0300 Subject: [PATCH 261/487] Fix call_function_from_inferior --- libpince/GDB_Engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 3cb39522..2676b41c 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -1856,7 +1856,7 @@ def call_function_from_inferior(expression): Examples: call_function_from_inferior("printf('123')") returns ("$26","3") """ - result = send_command("call (char *) " + expression) + result = execute_func_temporary_interruption(send_command, f"call (void*(*)(char*, int)) {expression}") filtered_result = common_regexes.convenience_variable.search(result) if filtered_result: return filtered_result.group(1), filtered_result.group(2) From bef2ee4dab59ecd8be89c53755b39e322e7e8cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 31 Oct 2023 21:38:29 +0300 Subject: [PATCH 262/487] Implement endianness --- GUI/AddAddressManuallyDialog.py | 18 +++- GUI/AddAddressManuallyDialog.ui | 27 ++++++ GUI/MainWindow.py | 12 ++- GUI/MainWindow.ui | 14 ++++ PINCE.py | 144 +++++++++++++++++++------------- i18n/ts/it_IT.ts | 25 ++++++ i18n/ts/zh_CN.ts | 25 ++++++ libpince/GDB_Engine.py | 26 ++++-- libpince/type_defs.py | 23 +++-- tr/tr.py | 3 + 10 files changed, 241 insertions(+), 76 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 44874441..c2399f45 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -117,6 +117,17 @@ def setupUi(self, Dialog): self.lineEdit_length.setObjectName("lineEdit_length") self.horizontalLayout_2.addWidget(self.lineEdit_length) self.verticalLayout_3.addLayout(self.horizontalLayout_2) + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.label_3 = QtWidgets.QLabel(parent=Dialog) + self.label_3.setObjectName("label_3") + self.horizontalLayout_6.addWidget(self.label_3) + self.comboBox_Endianness = QtWidgets.QComboBox(parent=Dialog) + self.comboBox_Endianness.setObjectName("comboBox_Endianness") + self.horizontalLayout_6.addWidget(self.comboBox_Endianness) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_6.addItem(spacerItem4) + self.verticalLayout_3.addLayout(self.horizontalLayout_6) self.gridLayout.addLayout(self.verticalLayout_3, 2, 0, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") @@ -144,8 +155,8 @@ def setupUi(self, Dialog): self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_valueofaddress.setObjectName("label_valueofaddress") self.horizontalLayout.addWidget(self.label_valueofaddress) - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem4) + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem5) self.verticalLayout_2.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) self.verticalLayout = QtWidgets.QVBoxLayout() @@ -175,5 +186,6 @@ def retranslateUi(self, Dialog): self.label_5.setText(_translate("Dialog", "Type:")) self.checkBox_zeroterminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_length.setText(_translate("Dialog", "Length")) + self.label_3.setText(_translate("Dialog", "Endianness:")) self.label.setText(_translate("Dialog", "Address:")) self.label_4.setText(_translate("Dialog", "Description:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 005f42f1..ac4e9ad5 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -261,6 +261,33 @@ + + + + + + Endianness: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index c919d3de..54854527 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MainWindow.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -243,6 +243,15 @@ def setupUi(self, MainWindow): self.comboBox_ScanScope.setObjectName("comboBox_ScanScope") self.horizontalLayout_10.addWidget(self.comboBox_ScanScope) self.verticalLayout_4.addLayout(self.horizontalLayout_10) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_3 = QtWidgets.QLabel(parent=self.widget) + self.label_3.setObjectName("label_3") + self.horizontalLayout_3.addWidget(self.label_3) + self.comboBox_Endianness = QtWidgets.QComboBox(parent=self.widget) + self.comboBox_Endianness.setObjectName("comboBox_Endianness") + self.horizontalLayout_3.addWidget(self.comboBox_Endianness) + self.verticalLayout_4.addLayout(self.horizontalLayout_3) spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_4.addItem(spacerItem4) self.horizontalLayout_4.addWidget(self.widget) @@ -307,3 +316,4 @@ def retranslateUi(self, MainWindow): self.label.setText(_translate("MainWindow", "Scan Type:")) self.label_2.setText(_translate("MainWindow", "Value Type:")) self.label_ScanScope.setText(_translate("MainWindow", "Scan Scope:")) + self.label_3.setText(_translate("MainWindow", "Endianness:")) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index c9349a06..c17c900f 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -533,6 +533,20 @@ + + + + + + Endianness: + + + + + + + + diff --git a/PINCE.py b/PINCE.py index 56c80bef..0724e111 100755 --- a/PINCE.py +++ b/PINCE.py @@ -355,6 +355,24 @@ def signal_handler(signal, frame): signal.signal(signal.SIGINT, signal_handler) +def fill_endianness_combobox(QCombobox, current_index=type_defs.ENDIANNESS.HOST): + """Fills the given QCombobox with endianness strings + TODO: Carry this function to the GuiUtils.py when it gets separated from libpince + + Args: + QCombobox (QCombobox): The combobox that'll be filled + current_index (int): Can be a member of type_defs.ENDIANNESS + """ + endianness_text = [ + (type_defs.ENDIANNESS.HOST, tr.HOST), + (type_defs.ENDIANNESS.LITTLE, tr.LITTLE), + (type_defs.ENDIANNESS.BIG, tr.BIG) + ] + for endian, text in endianness_text: + QCombobox.addItem(text, endian) + QCombobox.setCurrentIndex(current_index) + + # Checks if the inferior has been terminated class AwaitProcessExit(QThread): process_exited = pyqtSignal() @@ -498,6 +516,7 @@ def __init__(self): self.pushButton_NewFirstScan_clicked() self.comboBox_ScanScope_init() self.comboBox_ValueType_init() + fill_endianness_combobox(self.comboBox_Endianness) self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.lineEdit_Scan.setValidator( @@ -997,7 +1016,7 @@ def update_address_table(self, use_cache=False): exp_cache[examine_list[index]] = item.address address_list[examine_indices[index]] = item.address for index, row in enumerate(rows): - value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) + vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) current_address = address_list[index] if isinstance(address_data, type_defs.PointerType): @@ -1019,13 +1038,10 @@ def update_address_table(self, use_cache=False): else: address = current_address row.setText(ADDR_COL, address or address_data) - signed = True if value_type.value_repr == type_defs.VALUE_REPR.SIGNED else False - value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, - value_type.zero_terminate, signed, mem_handle=mem_handle) + value = GDB_Engine.read_memory(address, vt.value_index, vt.length, vt.zero_terminate, + vt.value_repr, vt.endian, mem_handle=mem_handle) if value is None: value = "" - elif value_type.value_repr == type_defs.VALUE_REPR.HEX: - value = hex(value) else: value = str(value) row.setText(VALUE_COL, value) @@ -1037,8 +1053,8 @@ def resize_address_table(self): def pushButton_AddAddressManually_clicked(self): manual_address_dialog = ManualAddressDialogForm() if manual_address_dialog.exec(): - desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() - self.add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate) + desc, address_expr, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() + self.add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate, endian=endian) def pushButton_MemoryView_clicked(self): self.memory_view_window.showMaximized() @@ -1084,9 +1100,12 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_NextScan.setEnabled(True) self.pushButton_UndoScan.setEnabled(True) search_scope = self.comboBox_ScanScope.currentData(Qt.ItemDataRole.UserRole) - scanmem.send_command("option region_scan_level " + str(search_scope)) + endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) + scanmem.send_command(f"option region_scan_level {search_scope}") + scanmem.send_command(f"option endianness {endian}") scanmem.reset() self.comboBox_ScanScope.setEnabled(False) + self.comboBox_Endianness.setEnabled(False) self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan self.comboBox_ScanType_init() @@ -1225,11 +1244,15 @@ def scan_callback(self): current_item = QTableWidgetItem(address) result = result_type.split(" ")[0] value_index = type_defs.scanmem_result_to_index_dict[result] - signed = False - if type_defs.VALUE_INDEX.is_integer(value_index) and result.endswith("s"): - signed = True - current_item.setData(Qt.ItemDataRole.UserRole, (value_index, signed)) - value = str(GDB_Engine.read_memory(address, value_index, length, signed=signed, mem_handle=mem_handle)) + if self.checkBox_Hex.isChecked(): + value_repr = type_defs.VALUE_REPR.HEX + elif type_defs.VALUE_INDEX.is_integer(value_index) and result.endswith("s"): + value_repr = type_defs.VALUE_REPR.SIGNED + else: + value_repr = type_defs.VALUE_REPR.UNSIGNED + endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) + current_item.setData(Qt.ItemDataRole.UserRole, (value_index, value_repr, endian)) + value = str(GDB_Engine.read_memory(address, value_index, length, True, value_repr, endian, mem_handle)) self.tableWidget_valuesearchtable.insertRow(self.tableWidget_valuesearchtable.rowCount()) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_ADDRESS_COL, current_item) self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_VALUE_COL, QTableWidgetItem(value)) @@ -1247,9 +1270,10 @@ def _scan_to_length(self, type_index): def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) + value_index, value_repr, endian = current_item.data(Qt.ItemDataRole.UserRole) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) - self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), - current_item.data(Qt.ItemDataRole.UserRole)[0], length) + self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), value_index, length, + value_repr=value_repr, endian=endian) def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) @@ -1377,7 +1401,8 @@ def copy_to_address_table(self): for row in self.tableWidget_valuesearchtable.selectedItems(): i = i + 1 if i % 3 == 0: - self.add_entry_to_addresstable("", row.text(), row.data(Qt.ItemDataRole.UserRole)[0], length) + value_index, value_repr, endian = row.data(Qt.ItemDataRole.UserRole) + self.add_entry_to_addresstable("", row.text(), value_index, length, True, value_repr, endian) def reset_scan(self): self.scan_mode = type_defs.SCAN_MODE.NEW @@ -1386,6 +1411,7 @@ def reset_scan(self): self.tableWidget_valuesearchtable.setRowCount(0) self.comboBox_ValueType.setEnabled(True) self.comboBox_ScanScope.setEnabled(True) + self.comboBox_Endianness.setEnabled(True) self.pushButton_NextScan.setEnabled(False) self.pushButton_UndoScan.setEnabled(False) self.progressBar.setValue(0) @@ -1426,12 +1452,13 @@ def closeEvent(self, event): GDB_Engine.detach() app.closeAllWindows() - def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True): + def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True, + value_repr=type_defs.VALUE_REPR.UNSIGNED, endian=type_defs.ENDIANNESS.HOST): current_row = QTreeWidgetItem() current_row.setCheckState(FROZEN_COL, Qt.CheckState.Unchecked) frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) current_row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) - value_type = type_defs.ValueType(value_index, length, zero_terminate) + value_type = type_defs.ValueType(value_index, length, zero_terminate, value_repr, endian) self.treeWidget_AddressTable.addTopLevelItem(current_row) self.change_address_table_entries(current_row, description, address_expr, value_type) self.show() # In case of getting called from elsewhere @@ -1491,10 +1518,10 @@ def update_search_table(self): for row_index in range(row_count): address_item = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_ADDRESS_COL) previous_text = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_PREVIOUS_COL).text() - value_index, signed = address_item.data(Qt.ItemDataRole.UserRole) + value_index, value_repr, endian = address_item.data(Qt.ItemDataRole.UserRole) address = address_item.text() - new_value = str(GDB_Engine.read_memory(address, value_index, length, signed=signed, - mem_handle=mem_handle)) + new_value = str(GDB_Engine.read_memory(address, value_index, length, value_repr=value_repr, + endian=endian, mem_handle=mem_handle)) value_item = QTableWidgetItem(new_value) if new_value != previous_text: value_item.setForeground(QBrush(QColor(255, 0, 0))) @@ -1507,19 +1534,20 @@ def freeze(self): while it.value(): row = it.value() if row.checkState(FROZEN_COL) == Qt.CheckState.Checked: - value_index = row.data(TYPE_COL, Qt.ItemDataRole.UserRole).value_index + vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) address = row.text(ADDR_COL).strip("P->") frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) value = frozen.value freeze_type = frozen.freeze_type - if type_defs.VALUE_INDEX.is_integer(value_index): - new_value = GDB_Engine.read_memory(address, value_index) + if type_defs.VALUE_INDEX.is_integer(vt.value_index): + new_value = GDB_Engine.read_memory(address, vt.value_index, endian=vt.endian) + new_value = int(new_value, 0) if isinstance(new_value, str) else new_value if freeze_type == type_defs.FREEZE_TYPE.INCREMENT and new_value > int(value, 0) or \ freeze_type == type_defs.FREEZE_TYPE.DECREMENT and new_value < int(value, 0): frozen.value = str(new_value) - GDB_Engine.write_memory(address, value_index, frozen.value) + GDB_Engine.write_memory(address, vt.value_index, frozen.value, vt.endian) continue - GDB_Engine.write_memory(address, value_index, value) + GDB_Engine.write_memory(address, vt.value_index, value, vt.endian) it += 1 def treeWidget_AddressTable_item_clicked(self, row, column): @@ -1559,7 +1587,7 @@ def treeWidget_AddressTable_edit_value(self): frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) frozen.value = new_value row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) - GDB_Engine.write_memory(address, value_type.value_index, new_value) + GDB_Engine.write_memory(address, value_type.value_index, new_value, value_type.endian) self.update_address_table() def treeWidget_AddressTable_edit_desc(self): @@ -1577,33 +1605,32 @@ def treeWidget_AddressTable_edit_address(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not row: return - desc, address_expr, value_type = self.read_address_table_entries(row) - manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, - index=value_type.value_index, length=value_type.length, - zero_terminate=value_type.zero_terminate) + desc, address_expr, vt = self.read_address_table_entries(row) + manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, index=vt.value_index, + length=vt.length, zero_terminate=vt.zero_terminate, + endian=vt.endian) manual_address_dialog.setWindowTitle(tr.EDIT_ADDRESS) if manual_address_dialog.exec(): - desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() - value_type = type_defs.ValueType(value_index, length, zero_terminate, value_type.value_repr) - self.change_address_table_entries(row, desc, address_expr, value_type) + desc, address_expr, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() + vt = type_defs.ValueType(value_index, length, zero_terminate, vt.value_repr, endian) + self.change_address_table_entries(row, desc, address_expr, vt) def treeWidget_AddressTable_edit_type(self): row = GuiUtils.get_current_item(self.treeWidget_AddressTable) if not row: return - value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - dialog = EditTypeDialogForm(index=value_type.value_index, length=value_type.length, - zero_terminate=value_type.zero_terminate) + vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) + dialog = EditTypeDialogForm(index=vt.value_index, length=vt.length, zero_terminate=vt.zero_terminate) if dialog.exec(): value_index, length, zero_terminate = dialog.get_values() - value_type = type_defs.ValueType(value_index, length, zero_terminate, value_type.value_repr) + vt = type_defs.ValueType(value_index, length, zero_terminate, vt.value_repr, vt.endian) for row in self.treeWidget_AddressTable.selectedItems(): - row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, value_type) - row.setText(TYPE_COL, value_type.text()) + row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, vt) + row.setText(TYPE_COL, vt.text()) self.update_address_table() # Changes the column values of the given row - def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, address_expr="", value_type=None): + def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, address_expr="", vt=None): if isinstance(address_expr, type_defs.PointerType): address = GDB_Engine.read_pointer(address_expr) address_text = f'P->{hex(address)}' if address != None else 'P->??' @@ -1617,15 +1644,15 @@ def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, addre address_text = address value = '' if address: - value = GDB_Engine.read_memory(address, value_type.value_index, value_type.length, - value_type.zero_terminate) + value = GDB_Engine.read_memory(address, vt.value_index, vt.length, vt.zero_terminate, vt.value_repr, + vt.endian) assert isinstance(row, QTreeWidgetItem) row.setText(DESC_COL, description) row.setData(ADDR_COL, Qt.ItemDataRole.UserRole, address_expr) row.setText(ADDR_COL, address_text) - row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, value_type) - row.setText(TYPE_COL, value_type.text()) + row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, vt) + row.setText(TYPE_COL, vt.text()) row.setText(VALUE_COL, "" if value is None else str(value)) # Returns the column values of the given row @@ -1740,7 +1767,8 @@ def pushButton_CreateProcess_clicked(self): # Add Address Manually Dialog class ManualAddressDialogForm(QDialog, ManualAddressDialog): def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", - index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True): + index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, + endian=type_defs.ENDIANNESS.HOST): super().__init__(parent=parent) self.setupUi(self) self.adjustSize() @@ -1748,6 +1776,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.setFixedHeight(self.height()) self.lineEdit_length.setValidator(QHexValidator(999, self)) GuiUtils.fill_value_combobox(self.comboBox_ValueType, index) + fill_endianness_combobox(self.comboBox_Endianness, endian) self.lineEdit_description.setText(description) self.offsetsList = [] if not isinstance(address, type_defs.PointerType): @@ -1784,6 +1813,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.checkBox_zeroterminate.hide() self.setFixedSize(self.layout().sizeHint()) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) + self.comboBox_Endianness.currentIndexChanged.connect(self.update_value_of_address) self.lineEdit_length.textChanged.connect(self.update_value_of_address) self.checkBox_zeroterminate.stateChanged.connect(self.update_value_of_address) self.checkBox_IsPointer.stateChanged.connect(self.comboBox_ValueType_current_index_changed) @@ -1861,15 +1891,16 @@ def update_value_of_address(self): return address_type = self.comboBox_ValueType.currentIndex() + endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) if address_type == type_defs.VALUE_INDEX.INDEX_AOB: length = self.lineEdit_length.text() - value = GDB_Engine.read_memory(address, address_type, length) + value = GDB_Engine.read_memory(address, address_type, length, endian=endian) elif type_defs.VALUE_INDEX.is_string(address_type): length = self.lineEdit_length.text() is_zeroterminate = self.checkBox_zeroterminate.isChecked() - value = GDB_Engine.read_memory(address, address_type, length, is_zeroterminate) + value = GDB_Engine.read_memory(address, address_type, length, is_zeroterminate, endian=endian) else: - value = GDB_Engine.read_memory(address, address_type) + value = GDB_Engine.read_memory(address, address_type, endian=endian) self.label_valueofaddress.setText("??" if value is None else str(value)) def comboBox_ValueType_current_index_changed(self): @@ -1923,13 +1954,12 @@ def get_values(self): length = int(length, 0) except: length = 0 - zero_terminate = False - if self.checkBox_zeroterminate.isChecked(): - zero_terminate = True + zero_terminate = self.checkBox_zeroterminate.isChecked() value_index = self.comboBox_ValueType.currentIndex() + endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) if self.checkBox_IsPointer.isChecked(): address = type_defs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) - return description, address, value_index, length, zero_terminate + return description, address, value_index, length, zero_terminate, endian def get_offsets_int_list(self): offsetsIntList = [] @@ -2921,8 +2951,8 @@ def exec_hex_view_add_address_dialog(self): manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), index=type_defs.VALUE_INDEX.INDEX_AOB) if manual_address_dialog.exec(): - desc, address_expr, value_index, length, zero_terminate = manual_address_dialog.get_values() - self.parent().add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate) + desc, address, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() + self.parent().add_entry_to_addresstable(desc, address, value_index, length, zero_terminate, endian=endian) def hex_view_scroll_up(self): self.verticalScrollBar_HexView.setValue(1) @@ -4484,7 +4514,7 @@ def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() self.parent().parent().add_entry_to_addresstable(tr.ACCESSED_BY.format(self.address), address, - self.comboBox_ValueType.currentIndex(), 10, True) + self.comboBox_ValueType.currentIndex(), 10) def pushButton_Stop_clicked(self): if self.stopped: diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 28a04a82..2885c442 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -46,6 +46,11 @@ Length Lunghezza + + + Endianness: + + @@ -861,6 +866,11 @@ Patterns at former positions have higher priority if regex is off Scan Scope: + + + Endianness: + + Please select a Process @@ -2456,5 +2466,20 @@ Proceed? Full + + + Host + + + + + Little + + + + + Big + + diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index a31bd864..c72bc89d 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -46,6 +46,11 @@ Length 长度 + + + Endianness: + + @@ -863,6 +868,11 @@ Patterns at former positions have higher priority if regex is off Scan Scope: 扫描范围: + + + Endianness: + + Please select a Process @@ -2529,5 +2539,20 @@ Proceed? Full 全部 + + + Host + + + + + Little + + + + + Big + + diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index 2676b41c..ac9dce0f 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -18,11 +18,12 @@ from threading import Lock, Thread, Condition from time import sleep, time from collections import OrderedDict, defaultdict -import pexpect, os, ctypes, pickle, json, shelve, re, struct, io +import pexpect, os, sys, ctypes, pickle, json, shelve, re, struct, io from . import SysUtils, type_defs, common_regexes self_pid = os.getpid() libc = ctypes.CDLL('libc.so.6') +system_endianness = type_defs.ENDIANNESS.LITTLE if sys.byteorder == "little" else type_defs.ENDIANNESS.BIG #:tag:GDBInformation #:doc: @@ -759,7 +760,8 @@ def memory_handle(): #:tag:MemoryRW -def read_memory(address, value_index, length=None, zero_terminate=True, signed=False, mem_handle=None): +def read_memory(address, value_index, length=None, zero_terminate=True, value_repr=type_defs.VALUE_REPR.UNSIGNED, + endian=type_defs.ENDIANNESS.HOST, mem_handle=None): """Reads value from the given address Args: @@ -769,13 +771,14 @@ def read_memory(address, value_index, length=None, zero_terminate=True, signed=F INDEX_STRING or INDEX_AOB. Ignored otherwise zero_terminate (bool): If True, data will be split when a null character has been read. Only used when value_index is INDEX_STRING. Ignored otherwise - signed (bool): Casts the data as signed if True, unsigned if False. Only usable with integer types + value_repr (int): Can be a member of type_defs.VALUE_REPR. Only usable with integer types + endian (int): Can be a member of type_defs.ENDIANNESS mem_handle (BinaryIO): A file handle that points to the memory file of the current process This parameter is used for optimization, See memory_handle Don't forget to close the handle after you're done if you use this parameter manually Returns: - str: If the value_index is INDEX_STRING or INDEX_AOB + str: If the value_index is INDEX_STRING or INDEX_AOB, also when value_repr is HEX float: If the value_index is INDEX_FLOAT32 or INDEX_FLOAT64 int: If the value_index is anything else None: If an error occurs while reading the given address @@ -819,6 +822,8 @@ def read_memory(address, value_index, length=None, zero_terminate=True, signed=F mem_handle = open(mem_file, "rb") mem_handle.seek(address) data_read = mem_handle.read(expected_length) + if endian != type_defs.ENDIANNESS.HOST and system_endianness != endian: + data_read = data_read[::-1] except (OSError, ValueError): # TODO (read/write error output) # Disabled read error printing. If needed, find a way to implement error logging with this function @@ -838,13 +843,17 @@ def read_memory(address, value_index, length=None, zero_terminate=True, signed=F elif value_index is type_defs.VALUE_INDEX.INDEX_AOB: return " ".join(format(n, '02x') for n in data_read) else: - if type_defs.VALUE_INDEX.is_integer(value_index) and signed: + is_integer = type_defs.VALUE_INDEX.is_integer(value_index) + if is_integer and value_repr == type_defs.VALUE_REPR.SIGNED: data_type = data_type.lower() - return struct.unpack_from(data_type, data_read)[0] + result = struct.unpack_from(data_type, data_read)[0] + if is_integer and value_repr == type_defs.VALUE_REPR.HEX: + return hex(result) + return result #:tag:MemoryRW -def write_memory(address, value_index, value): +def write_memory(address, value_index, value, endian=type_defs.ENDIANNESS.HOST): """Sets the given value to the given address If any errors occurs while setting value to the according address, it'll be ignored but the information about @@ -854,6 +863,7 @@ def write_memory(address, value_index, value): address (str, int): Can be a hex string or an integer value_index (int): Can be a member of type_defs.VALUE_INDEX value (str): The value that'll be written to the given address + endian (int): Can be a member of type_defs.ENDIANNESS Notes: TODO: Implement a mem_handle parameter for optimization, check read_memory for an example @@ -878,6 +888,8 @@ def write_memory(address, value_index, value): write_data = struct.pack(data_type, write_data) else: write_data = write_data.encode(encoding, option) + b"\x00" # Zero-terminated by default + if endian != type_defs.ENDIANNESS.HOST and system_endianness != endian: + write_data = write_data[::-1] FILE = open(mem_file, "rb+") try: FILE.seek(address) diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 674fc068..a6fba41a 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -316,6 +316,10 @@ class SCAN_SCOPE: FULL_RW = 3 FULL = 4 +class ENDIANNESS: + HOST = 0 + LITTLE = 1 + BIG = 2 string_index_to_encoding_dict = { VALUE_INDEX.INDEX_STRING_UTF8: ["utf-8", "surrogateescape"], @@ -404,7 +408,7 @@ def __init__(self, value, freeze_type): class ValueType: - def __init__(self, value_index, length, zero_terminate, value_repr=VALUE_REPR.UNSIGNED): + def __init__(self, value_index, length, zero_terminate, value_repr=VALUE_REPR.UNSIGNED, endian=ENDIANNESS.HOST): """ Args: value_index (int): Determines the type of data. Can be a member of VALUE_INDEX @@ -412,14 +416,16 @@ def __init__(self, value_index, length, zero_terminate, value_repr=VALUE_REPR.UN zero_terminate (bool): If False, ",NZT" will be appended to the text representation Only used when value_index is INDEX_STRING. Ignored otherwise. "NZT" stands for "Not Zero Terminate" value_repr (int): Determines how the data is represented. Can be a member of VALUE_REPR + endian (int): Determines the endianness. Can be a member of ENDIANNESS """ self.value_index = value_index self.length = length self.zero_terminate = zero_terminate self.value_repr = value_repr + self.endian = endian def serialize(self): - return self.value_index, self.length, self.zero_terminate, self.value_repr + return self.value_index, self.length, self.zero_terminate, self.value_repr, self.endian def text(self): """Returns the text representation according to its members @@ -434,16 +440,20 @@ def text(self): """ returned_string = index_to_text_dict[self.value_index] if VALUE_INDEX.is_string(self.value_index): - returned_string = returned_string + "[" + str(self.length) + "]" + returned_string += f"[{self.length}]" if not self.zero_terminate: returned_string += ",NZT" elif self.value_index == VALUE_INDEX.INDEX_AOB: - returned_string += "[" + str(self.length) + "]" + returned_string += f"[{self.length}]" if VALUE_INDEX.is_integer(self.value_index): if self.value_repr == VALUE_REPR.SIGNED: returned_string += "(s)" elif self.value_repr == VALUE_REPR.HEX: returned_string += "(h)" + if self.endian == ENDIANNESS.LITTLE: + returned_string += "" + elif self.endian == ENDIANNESS.BIG: + returned_string += "" return returned_string @@ -456,10 +466,7 @@ def __init__(self, base_address, offsets_list=None): Last offset in list won't be dereferenced to emulate CE behaviour. """ self.base_address = base_address - if offsets_list == None: - self.offsets_list = [] - else: - self.offsets_list = offsets_list + self.offsets_list = [] if not offsets_list else offsets_list def serialize(self): return self.base_address, self.offsets_list diff --git a/tr/tr.py b/tr/tr.py index 706eb75b..3a86bfa4 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -315,3 +315,6 @@ def translate(): NORMAL = QT_TR_NOOP("Normal") RW = QT_TR_NOOP("Read+Write") FULL = QT_TR_NOOP("Full") + HOST = QT_TR_NOOP("Host") + LITTLE = QT_TR_NOOP("Little") + BIG = QT_TR_NOOP("Big") \ No newline at end of file From 55e8af2a3d194f039e7bdde22b3fbaaeeabd1806 Mon Sep 17 00:00:00 2001 From: detiam Date: Wed, 1 Nov 2023 14:52:31 +0800 Subject: [PATCH 263/487] Update zh_CN translation --- i18n/ts/zh_CN.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index c72bc89d..9d98e218 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -49,7 +49,7 @@ Endianness: - + 字节序: @@ -871,7 +871,7 @@ Patterns at former positions have higher priority if regex is off Endianness: - + 字节序: @@ -1554,7 +1554,7 @@ To change the current GDB path, check Settings->Debug Process is running - + 进程正在运行 @@ -2542,17 +2542,17 @@ Proceed? Host - + 主机 Little - + Big - + From 7869362f4d4144ad2a6b6d25696f405aea75e211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 6 Nov 2023 22:52:54 +0300 Subject: [PATCH 264/487] Make QDialogButtonBox.StandardButton translatable --- i18n/ts/it_IT.ts | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ i18n/ts/zh_CN.ts | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ tr/tr.py | 24 ++++++++++++- 3 files changed, 209 insertions(+), 1 deletion(-) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 2885c442..345731a2 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1153,6 +1153,99 @@ Patterns at former positions have higher priority if regex is off + + QPlatformTheme + + + OK + + + + + &Open + + + + + &Save + + + + + Cancel + Annulla + + + + Close + + + + + Discard + + + + + Apply + + + + + Reset + + + + + Restore Defaults + + + + + Help + + + + + Save All + + + + + &Yes + + + + + &No + + + + + Abort + + + + + Retry + + + + + Ignore + + + + + N&o to All + + + + + Yes to &All + + + TabWidget diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 9d98e218..f278ea6b 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1155,6 +1155,99 @@ Patterns at former positions have higher priority if regex is off 还原指令 + + QPlatformTheme + + + OK + + + + + &Open + + + + + &Save + + + + + Cancel + 取消 + + + + Close + 关闭 + + + + Discard + + + + + Apply + + + + + Reset + + + + + Restore Defaults + + + + + Help + 帮助 + + + + Save All + + + + + &Yes + + + + + &No + + + + + Abort + + + + + Retry + + + + + Ignore + 忽略 + + + + N&o to All + + + + + Yes to &All + + + TabWidget diff --git a/tr/tr.py b/tr/tr.py index 3a86bfa4..5b62c62e 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -1,4 +1,26 @@ -from PyQt6.QtCore import QObject, QT_TR_NOOP +from PyQt6.QtCore import QObject, QT_TR_NOOP, QT_TRANSLATE_NOOP + +# This handles the default translations for QDialogButtonBox.StandardButton +# Some of the standard button labels have an ampersand (&). It's used to denote an access key or keyboard shortcut +# Translate the text as you wish, then put the ampersand (&) where the shortcut should be +QT_TRANSLATE_NOOP("QPlatformTheme", "OK") +QT_TRANSLATE_NOOP("QPlatformTheme", "&Open") +QT_TRANSLATE_NOOP("QPlatformTheme", "&Save") +QT_TRANSLATE_NOOP("QPlatformTheme", "Cancel") +QT_TRANSLATE_NOOP("QPlatformTheme", "Close") +QT_TRANSLATE_NOOP("QPlatformTheme", "Discard") +QT_TRANSLATE_NOOP("QPlatformTheme", "Apply") +QT_TRANSLATE_NOOP("QPlatformTheme", "Reset") +QT_TRANSLATE_NOOP("QPlatformTheme", "Restore Defaults") +QT_TRANSLATE_NOOP("QPlatformTheme", "Help") +QT_TRANSLATE_NOOP("QPlatformTheme", "Save All") +QT_TRANSLATE_NOOP("QPlatformTheme", "&Yes") +QT_TRANSLATE_NOOP("QPlatformTheme", "&No") +QT_TRANSLATE_NOOP("QPlatformTheme", "Abort") +QT_TRANSLATE_NOOP("QPlatformTheme", "Retry") +QT_TRANSLATE_NOOP("QPlatformTheme", "Ignore") +QT_TRANSLATE_NOOP("QPlatformTheme", "N&o to All") +QT_TRANSLATE_NOOP("QPlatformTheme", "Yes to &All") class TranslationConstants(QObject): From d63d92706ca039ed07db388899c4b47675cb8380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 6 Nov 2023 23:02:58 +0300 Subject: [PATCH 265/487] Change import order --- PINCE.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 0724e111..a65bb1b7 100755 --- a/PINCE.py +++ b/PINCE.py @@ -25,7 +25,7 @@ # This line can be deleted when GTK 4.0 properly runs on all supported systems gi.require_version('Gtk', '3.0') -from typing import Final +from tr.tr import TranslationConstants as tr from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ QKeyEvent, QRegularExpressionValidator, QShortcut, QColorConstants @@ -35,12 +35,12 @@ from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ QLocale +from typing import Final from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect from libpince import GuiUtils, SysUtils, GDB_Engine, type_defs from libpince.libscanmem.scanmem import Scanmem -from tr.tr import TranslationConstants as tr from GUI.MainWindow import Ui_MainWindow as MainWindow from GUI.SelectProcess import Ui_MainWindow as ProcessWindow From 3f11a52314532a6eaa142cbdb5bdde10050493d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 12 Nov 2023 17:27:02 +0300 Subject: [PATCH 266/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00702734..7ec8e89e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,8 @@ The py files that contains the same name with the ui files are auto-generated, p # Translation You need to have [Qt6 Linguist](https://pkgs.org/search/?q=linguist&on=files) and [pylupdate6](https://pkgs.org/search/?q=pylupdate6&on=files) installed. Here are the steps: -- (Optional) To create a new translation file, use [compile_ts.sh](./compile_ts.sh) with the locale as the parameter, such as `sh compile.sh ja_JP`. This will create a ts file with the locale you entered +- To create a new translation file, use [compile_ts.sh](./compile_ts.sh) with the locale as the parameter, such as `sh compile.sh ja_JP`. This will create a ts file with the locale you entered. +You can skip this step if you only want to edit already existing files - Edit ts files in [/i18n/ts](./i18n/ts) with the linguist and then save them. After saving the files, run the [compile_ts.sh](./compile_ts.sh) script. This script fixes inconsistencies between Qt6 Linguist and pylupdate6, also removes line information so the git history stays cleaner - To test your translations, use [install_pince.sh](./install_pince.sh). The last part of the installation script also compiles ts files to qm files so PINCE can process them. From f9f5b37663985f1569bcaa73d2ecf2dd8e3354db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 15 Nov 2023 21:41:43 +0300 Subject: [PATCH 267/487] Temporary fix for bp racing conditions --- libpince/GDB_Engine.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libpince/GDB_Engine.py b/libpince/GDB_Engine.py index ac9dce0f..2d279982 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/GDB_Engine.py @@ -280,7 +280,9 @@ def check_inferior_status(): stop_info = matches[-1][0] if stop_info: bp_num = common_regexes.breakpoint_number.search(stop_info) - if bp_num and breakpoint_on_hit_dict[bp_num.group(1)] != type_defs.BREAKPOINT_ON_HIT.BREAK: + + # Return -1 for invalid breakpoints to ignore racing conditions + if bp_num and breakpoint_on_hit_dict.get(bp_num.group(1), -1) != type_defs.BREAKPOINT_ON_HIT.BREAK: return stop_reason = type_defs.STOP_REASON.DEBUG inferior_status = type_defs.INFERIOR_STATUS.INFERIOR_STOPPED From 18461fb08e1002e7d7367af153562c2b2972a4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 16 Nov 2023 14:10:20 +0300 Subject: [PATCH 268/487] Adjust float search to locale --- PINCE.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index a65bb1b7..c42a0012 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1185,10 +1185,14 @@ def validate_search(self, search_for, search_for2): # none of these should be possible to be true at the same time scan_index = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) - if scan_index == type_defs.SCAN_INDEX.INDEX_FLOAT32 or scan_index == type_defs.SCAN_INDEX.INDEX_FLOAT64: - # this is odd, since when searching for floats from command line it uses `.` and not `,` - search_for = search_for.replace(".", ",") - search_for2 = search_for2.replace(".", ",") + if scan_index >= type_defs.SCAN_INDEX.INDEX_FLOAT_ANY and scan_index <= type_defs.SCAN_INDEX.INDEX_FLOAT64: + # Adjust to locale whatever the input + if QLocale.system().decimalPoint() == ".": + search_for = search_for.replace(",", ".") + search_for2 = search_for2.replace(",", ".") + else: + search_for = search_for.replace(".", ",") + search_for2 = search_for2.replace(".", ",") elif scan_index == type_defs.SCAN_INDEX.INDEX_STRING: search_for = "\" " + search_for elif self.checkBox_Hex.isChecked(): From bd692961961c8fab6f26aab2658034b69b9bd237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 17 Nov 2023 21:19:59 +0300 Subject: [PATCH 269/487] Use locale_alias instead of SUPPORTED file --- compile_ts.sh | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/compile_ts.sh b/compile_ts.sh index e85fabdc..13e8b0f0 100755 --- a/compile_ts.sh +++ b/compile_ts.sh @@ -1,5 +1,8 @@ #!/bin/bash -file_supportlocale='/usr/share/i18n/SUPPORTED' +supported_locale_list=$(python3 -c " +import locale +print('\n'.join(value.split('.')[0] for value in locale.locale_alias.values())) +") list_ts=$(find i18n/ts -maxdepth 1 -type f -name '*.ts') # If there's a user parameter, create a new locale based on it @@ -7,20 +10,15 @@ if [ -n "$1" ]; then list_ts="$list_ts i18n/ts/$1.ts" fi -if [ -e "$file_supportlocale" ]; then - for ts in $list_ts; do - # Check if the locale is valid - if grep -E "^$(basename "$ts" .ts)(.)?.*\s.*" "$file_supportlocale" > /dev/null 2>&1; then - pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts "$ts" - python3 fix_ts.py "$ts" - else - list_invalidts="$list_invalidts $ts" - fi - done -else - echo "file $file_supportlocale not exist, aborting" - exit 2 -fi +for ts in $list_ts; do + # Check if the locale is valid + if echo "$supported_locale_list" | grep -q "$(basename "$ts" .ts)"; then + pylupdate6 GUI/*.ui tr/tr.py --no-obsolete --ts "$ts" + python3 fix_ts.py "$ts" + else + list_invalidts="$list_invalidts $ts" + fi +done if [ -n "$list_invalidts" ]; then echo From d97475233187250568f4b6aa1ad30fd6caa9b87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 17 Nov 2023 23:42:59 +0300 Subject: [PATCH 270/487] Add venv to vscode launch script --- .vscode/launch.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 2149684f..c9a2cf62 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,8 @@ "justMyCode": false, "sudo": true, "console": "integratedTerminal", - "program": "${workspaceFolder}/PINCE.py" + "program": "${workspaceFolder}/PINCE.py", + "python": "${workspaceFolder}/.venv/PINCE/bin/python3" } ] } From 7640b2e7d94ca92c2cfb9ba84e69ef2b04486dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 18 Nov 2023 17:39:07 +0300 Subject: [PATCH 271/487] Don't display unknown entries --- PINCE.py | 17 ++++++++++------- libpince/type_defs.py | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index c42a0012..c0fd55ec 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1242,11 +1242,12 @@ def scan_callback(self): current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) length = self._scan_to_length(current_type) mem_handle = GDB_Engine.memory_handle() + row = 0 # go back to using n when unknown issue gets fixed for n, address, offset, region_type, val, result_type in matches: - n = int(n) address = "0x" + address - current_item = QTableWidgetItem(address) result = result_type.split(" ")[0] + if result == "unknown": # Ignore unknown entries for now + continue value_index = type_defs.scanmem_result_to_index_dict[result] if self.checkBox_Hex.isChecked(): value_repr = type_defs.VALUE_REPR.HEX @@ -1255,13 +1256,15 @@ def scan_callback(self): else: value_repr = type_defs.VALUE_REPR.UNSIGNED endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) + current_item = QTableWidgetItem(address) current_item.setData(Qt.ItemDataRole.UserRole, (value_index, value_repr, endian)) value = str(GDB_Engine.read_memory(address, value_index, length, True, value_repr, endian, mem_handle)) - self.tableWidget_valuesearchtable.insertRow(self.tableWidget_valuesearchtable.rowCount()) - self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_ADDRESS_COL, current_item) - self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_VALUE_COL, QTableWidgetItem(value)) - self.tableWidget_valuesearchtable.setItem(n, SEARCH_TABLE_PREVIOUS_COL, QTableWidgetItem(value)) - if n == 1000: + self.tableWidget_valuesearchtable.insertRow(row) + self.tableWidget_valuesearchtable.setItem(row, SEARCH_TABLE_ADDRESS_COL, current_item) + self.tableWidget_valuesearchtable.setItem(row, SEARCH_TABLE_VALUE_COL, QTableWidgetItem(value)) + self.tableWidget_valuesearchtable.setItem(row, SEARCH_TABLE_PREVIOUS_COL, QTableWidgetItem(value)) + row += 1 + if row == 1000: break self.QWidget_Toolbox.setEnabled(True) diff --git a/libpince/type_defs.py b/libpince/type_defs.py index a6fba41a..213d7c66 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -246,7 +246,7 @@ class SCAN_INDEX: ("F32", VALUE_INDEX.INDEX_FLOAT32), ("F64", VALUE_INDEX.INDEX_FLOAT64), ("string", VALUE_INDEX.INDEX_STRING_UTF8), - ("bytearray", VALUE_INDEX.INDEX_AOB), + ("bytearray", VALUE_INDEX.INDEX_AOB) ]) # Represents the texts at indexes in scan combobox From 700bd98ed5991b90e4a54e85d52f6d400354af38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 20 Nov 2023 19:50:14 +0300 Subject: [PATCH 272/487] Move guiutils to GUI --- CONTRIBUTING.md | 3 +- GUI/CustomLabels/RegisterLabel.py | 7 +- libpince/GuiUtils.py => GUI/Utils/guiutils.py | 24 +- PINCE.py | 281 ++++++++---------- libpince/common_regexes.py | 2 +- run_tests.py | 2 +- .../{GuiUtils_tests.py => guiutils_tests.py} | 6 +- 7 files changed, 162 insertions(+), 163 deletions(-) rename libpince/GuiUtils.py => GUI/Utils/guiutils.py (91%) rename tests/{GuiUtils_tests.py => guiutils_tests.py} (86%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7ec8e89e..ebd0bb97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,14 +5,13 @@ - [compile_ts.sh](./compile_ts.sh) - Gathers translation information from various sources and compiles them into ts files - [fix_ts.py](./fix_ts.py) - Fixes line information issue, used within [compile_ts.sh](./compile_ts.sh) - [install_gdb.sh](./install_gdb.sh) - PINCE normally uses system GDB but in cases where system GDB is unavailable, this script is used to compile GDB locally -- [GUI](./GUI) - Contains Qt Designer forms and their respective codes along with some custom Qt classes +- [GUI](./GUI) - Contains Qt Designer forms and their respective codes along with utility functions and custom Qt classes - [media](./media) - Contains media files such as logos and icons - [tr](./tr) - Contains translation constants - [i18n](./i18n) - Contains translation files. `ts` files are created with Qt Linguist and [compile_ts.sh](./compile_ts.sh), `qm` files are created within the last section of [install_pince.sh](./install_pince.sh) - ### **[libpince](./libpince)** - [GDB_Engine.py](./libpince/GDB_Engine.py) - Everything related to communicating with GDB and debugging - [SysUtils.py](./libpince/SysUtils.py) - Contains generic utility functions such as parsing, file creation, documentation etc - - [GuiUtils.py](./libpince/GuiUtils.py) - Contains GUI related utility functions, it's more affiliated with Qt than libpince, could be moved in the future - [type_defs.py](./libpince/type_defs.py) - Contains all constants and variable definitions - [common_regexes.py](./libpince/common_regexes.py) - Contains regexes for parsing GDB output and other things - [Injection](./libpince/Injection) - An example for injecting .so files diff --git a/GUI/CustomLabels/RegisterLabel.py b/GUI/CustomLabels/RegisterLabel.py index 1e2c70c0..30d5495b 100644 --- a/GUI/CustomLabels/RegisterLabel.py +++ b/GUI/CustomLabels/RegisterLabel.py @@ -17,8 +17,9 @@ from PyQt6.QtWidgets import QLabel, QMenu from PyQt6.QtGui import QCursor from PyQt6.QtCore import Qt -from libpince import GDB_Engine, GuiUtils, type_defs +from libpince import GDB_Engine, type_defs from PINCE import InputDialogForm +from GUI.Utils import guiutils class QRegisterLabel(QLabel): @@ -58,13 +59,13 @@ def contextMenuEvent(self, QContextMenuEvent): menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(QContextMenuEvent.globalPos()) if action == show_in_hex_view: - parent = GuiUtils.search_parents_by_function(self, "hex_dump_address") + parent = guiutils.search_parents_by_function(self, "hex_dump_address") if parent.objectName() == "MainWindow_MemoryView": address = self.text().split("=")[-1] address_int = int(address, 16) parent.hex_dump_address(address_int) elif action == show_in_disassembler: - parent = GuiUtils.search_parents_by_function(self, "disassemble_expression") + parent = guiutils.search_parents_by_function(self, "disassemble_expression") if parent.objectName() == "MainWindow_MemoryView": address = self.text().split("=")[-1] parent.disassemble_expression(address) diff --git a/libpince/GuiUtils.py b/GUI/Utils/guiutils.py similarity index 91% rename from libpince/GuiUtils.py rename to GUI/Utils/guiutils.py index eef1dc80..1ab00fc8 100644 --- a/libpince/GuiUtils.py +++ b/GUI/Utils/guiutils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Copyright (C) 2016-2017 Korcan Karaokçu +Copyright (C) Korcan Karaokçu This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,8 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from . import SysUtils, type_defs, common_regexes - +from libpince import SysUtils, type_defs, common_regexes +from tr.tr import TranslationConstants as tr #:tag:GUI def get_icons_directory(): @@ -96,6 +96,22 @@ def fill_value_combobox(QCombobox, current_index=type_defs.VALUE_INDEX.INDEX_INT QCombobox.addItem(type_defs.index_to_text_dict[key]) QCombobox.setCurrentIndex(current_index) +#:tag:GUI +def fill_endianness_combobox(QCombobox, current_index=type_defs.ENDIANNESS.HOST): + """Fills the given QCombobox with endianness strings + + Args: + QCombobox (QCombobox): The combobox that'll be filled + current_index (int): Can be a member of type_defs.ENDIANNESS + """ + endianness_text = [ + (type_defs.ENDIANNESS.HOST, tr.HOST), + (type_defs.ENDIANNESS.LITTLE, tr.LITTLE), + (type_defs.ENDIANNESS.BIG, tr.BIG) + ] + for endian, text in endianness_text: + QCombobox.addItem(text, endian) + QCombobox.setCurrentIndex(current_index) #:tag:GUI def get_current_row(QObject): @@ -231,4 +247,4 @@ def append_shortcut_to_tooltip(QObject, QShortcut): QObject (QObject): Self-explanatory QShortcut (QShortcut): Self-explanatory """ - QObject.setToolTip(QObject.toolTip() + "[" + QShortcut.key().toString() + "]") + QObject.setToolTip(QObject.toolTip() + "[" + QShortcut.key().toString() + "]") \ No newline at end of file diff --git a/PINCE.py b/PINCE.py index c0fd55ec..df3d262f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -39,8 +39,9 @@ from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect -from libpince import GuiUtils, SysUtils, GDB_Engine, type_defs +from libpince import SysUtils, GDB_Engine, type_defs from libpince.libscanmem.scanmem import Scanmem +from GUI.Utils import guiutils from GUI.MainWindow import Ui_MainWindow as MainWindow from GUI.SelectProcess import Ui_MainWindow as ProcessWindow @@ -355,24 +356,6 @@ def signal_handler(signal, frame): signal.signal(signal.SIGINT, signal_handler) -def fill_endianness_combobox(QCombobox, current_index=type_defs.ENDIANNESS.HOST): - """Fills the given QCombobox with endianness strings - TODO: Carry this function to the GuiUtils.py when it gets separated from libpince - - Args: - QCombobox (QCombobox): The combobox that'll be filled - current_index (int): Can be a member of type_defs.ENDIANNESS - """ - endianness_text = [ - (type_defs.ENDIANNESS.HOST, tr.HOST), - (type_defs.ENDIANNESS.LITTLE, tr.LITTLE), - (type_defs.ENDIANNESS.BIG, tr.BIG) - ] - for endian, text in endianness_text: - QCombobox.addItem(text, endian) - QCombobox.setCurrentIndex(current_index) - - # Checks if the inferior has been terminated class AwaitProcessExit(QThread): process_exited = pyqtSignal() @@ -447,7 +430,7 @@ def __init__(self): } for hotkey, func in hotkey_to_func.items(): hotkey.change_func(func) - GuiUtils.center(self) + guiutils.center(self) self.treeWidget_AddressTable.setColumnWidth(FROZEN_COL, 50) self.treeWidget_AddressTable.setColumnWidth(DESC_COL, 150) self.treeWidget_AddressTable.setColumnWidth(ADDR_COL, 150) @@ -497,10 +480,10 @@ def __init__(self): self.freeze_timer.start() self.shortcut_open_file = QShortcut(QKeySequence("Ctrl+O"), self) self.shortcut_open_file.activated.connect(self.pushButton_Open_clicked) - GuiUtils.append_shortcut_to_tooltip(self.pushButton_Open, self.shortcut_open_file) + guiutils.append_shortcut_to_tooltip(self.pushButton_Open, self.shortcut_open_file) self.shortcut_save_file = QShortcut(QKeySequence("Ctrl+S"), self) self.shortcut_save_file.activated.connect(self.pushButton_Save_clicked) - GuiUtils.append_shortcut_to_tooltip(self.pushButton_Save, self.shortcut_save_file) + guiutils.append_shortcut_to_tooltip(self.pushButton_Save, self.shortcut_save_file) # Saving the original function because super() doesn't work when we override functions like this self.treeWidget_AddressTable.keyPressEvent_original = self.treeWidget_AddressTable.keyPressEvent @@ -516,7 +499,7 @@ def __init__(self): self.pushButton_NewFirstScan_clicked() self.comboBox_ScanScope_init() self.comboBox_ValueType_init() - fill_endianness_combobox(self.comboBox_Endianness) + guiutils.fill_endianness_combobox(self.comboBox_Endianness) self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.lineEdit_Scan.setValidator( @@ -540,7 +523,7 @@ def __init__(self): self.treeWidget_AddressTable.itemDoubleClicked.connect(self.treeWidget_AddressTable_item_double_clicked) self.treeWidget_AddressTable.expanded.connect(self.resize_address_table) self.treeWidget_AddressTable.collapsed.connect(self.resize_address_table) - icons_directory = GuiUtils.get_icons_directory() + icons_directory = guiutils.get_icons_directory() self.pushButton_AttachProcess.setIcon(QIcon(QPixmap(icons_directory + "/monitor.png"))) self.pushButton_Open.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) self.pushButton_Save.setIcon(QIcon(QPixmap(icons_directory + "/disk.png"))) @@ -702,7 +685,7 @@ def nextscan_hotkey_pressed(self, index): def treeWidget_AddressTable_context_menu_event(self, event): if self.treeWidget_AddressTable.topLevelItemCount() == 0: return - current_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + current_row = guiutils.get_current_item(self.treeWidget_AddressTable) header = self.treeWidget_AddressTable.headerItem() menu = QMenu() edit_menu = menu.addMenu(tr.EDIT) @@ -739,20 +722,20 @@ def treeWidget_AddressTable_context_menu_event(self, event): deletion_list = [edit_menu.menuAction(), show_hex, show_dec, show_unsigned, show_signed, toggle_record, freeze_menu.menuAction(), browse_region, disassemble, what_writes, what_reads, what_accesses] - GuiUtils.delete_menu_entries(menu, deletion_list) + guiutils.delete_menu_entries(menu, deletion_list) else: value_type = current_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) if type_defs.VALUE_INDEX.is_integer(value_type.value_index): if value_type.value_repr is type_defs.VALUE_REPR.HEX: - GuiUtils.delete_menu_entries(menu, [show_unsigned, show_signed, show_hex]) + guiutils.delete_menu_entries(menu, [show_unsigned, show_signed, show_hex]) elif value_type.value_repr is type_defs.VALUE_REPR.UNSIGNED: - GuiUtils.delete_menu_entries(menu, [show_unsigned, show_dec]) + guiutils.delete_menu_entries(menu, [show_unsigned, show_dec]) elif value_type.value_repr is type_defs.VALUE_REPR.SIGNED: - GuiUtils.delete_menu_entries(menu, [show_signed, show_dec]) + guiutils.delete_menu_entries(menu, [show_signed, show_dec]) if current_row.checkState(FROZEN_COL) == Qt.CheckState.Unchecked: - GuiUtils.delete_menu_entries(menu, [freeze_menu.menuAction()]) + guiutils.delete_menu_entries(menu, [freeze_menu.menuAction()]) else: - GuiUtils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed, + guiutils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed, freeze_menu.menuAction()]) font_size = self.treeWidget_AddressTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") @@ -790,7 +773,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): pass def exec_track_watchpoint_widget(self, watchpoint_type): - selected_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + selected_row = guiutils.get_current_item(self.treeWidget_AddressTable) if not selected_row: return address = selected_row.text(ADDR_COL).strip("P->") # @todo Maybe rework address grabbing logic in the future @@ -814,14 +797,14 @@ def exec_track_watchpoint_widget(self, watchpoint_type): TrackWatchpointWidgetForm(address, byte_len, watchpoint_type, self).show() def browse_region_for_selected_row(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + row = guiutils.get_current_item(self.treeWidget_AddressTable) if row: self.memory_view_window.hex_dump_address(int(row.text(ADDR_COL).strip("P->"), 16)) self.memory_view_window.show() self.memory_view_window.activateWindow() def disassemble_selected_row(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + row = guiutils.get_current_item(self.treeWidget_AddressTable) if row: if self.memory_view_window.disassemble_expression(row.text(ADDR_COL).strip("P->"), append_to_travel_history=True): @@ -845,7 +828,7 @@ def change_freeze_type(self, freeze_type): row.setForeground(FROZEN_COL, QBrush(QColor(255, 0, 0))) def toggle_selected_records(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + row = guiutils.get_current_item(self.treeWidget_AddressTable) if row: check_state = row.checkState(FROZEN_COL) new_check_state = Qt.CheckState.Checked if check_state == Qt.CheckState.Unchecked else Qt.CheckState.Unchecked @@ -932,7 +915,7 @@ def paste_records(self, insert_after=None, insert_inside=False): QMessageBox.information(self, tr.ERROR, tr.INVALID_CLIPBOARD) return - insert_row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + insert_row = guiutils.get_current_item(self.treeWidget_AddressTable) root = self.treeWidget_AddressTable.invisibleRootItem() if not insert_row: # this is common when the treeWidget_AddressTable is empty self.insert_records(records, root, self.treeWidget_AddressTable.topLevelItemCount()) @@ -1567,7 +1550,7 @@ def treeWidget_AddressTable_item_clicked(self, row, column): row.setForeground(FROZEN_COL, QBrush()) def treeWidget_AddressTable_change_repr(self, new_repr): - value_type = GuiUtils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) + value_type = guiutils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) value_type.value_repr = new_repr for row in self.treeWidget_AddressTable.selectedItems(): row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, value_type) @@ -1575,7 +1558,7 @@ def treeWidget_AddressTable_change_repr(self, new_repr): self.update_address_table() def treeWidget_AddressTable_edit_value(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + row = guiutils.get_current_item(self.treeWidget_AddressTable) if not row: return value = row.text(VALUE_COL) @@ -1598,7 +1581,7 @@ def treeWidget_AddressTable_edit_value(self): self.update_address_table() def treeWidget_AddressTable_edit_desc(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + row = guiutils.get_current_item(self.treeWidget_AddressTable) if not row: return description = row.text(DESC_COL) @@ -1609,7 +1592,7 @@ def treeWidget_AddressTable_edit_desc(self): row.setText(DESC_COL, description_text) def treeWidget_AddressTable_edit_address(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + row = guiutils.get_current_item(self.treeWidget_AddressTable) if not row: return desc, address_expr, vt = self.read_address_table_entries(row) @@ -1623,7 +1606,7 @@ def treeWidget_AddressTable_edit_address(self): self.change_address_table_entries(row, desc, address_expr, vt) def treeWidget_AddressTable_edit_type(self): - row = GuiUtils.get_current_item(self.treeWidget_AddressTable) + row = guiutils.get_current_item(self.treeWidget_AddressTable) if not row: return vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) @@ -1709,7 +1692,7 @@ class ProcessForm(QMainWindow, ProcessWindow): def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) - GuiUtils.center_to_parent(self) + guiutils.center_to_parent(self) self.refresh_process_table(self.tableWidget_ProcessTable, SysUtils.get_process_list()) self.pushButton_Close.clicked.connect(self.close) self.pushButton_Open.clicked.connect(self.pushButton_Open_clicked) @@ -1782,8 +1765,8 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.setMinimumWidth(300) self.setFixedHeight(self.height()) self.lineEdit_length.setValidator(QHexValidator(999, self)) - GuiUtils.fill_value_combobox(self.comboBox_ValueType, index) - fill_endianness_combobox(self.comboBox_Endianness, endian) + guiutils.fill_value_combobox(self.comboBox_ValueType, index) + guiutils.fill_endianness_combobox(self.comboBox_Endianness, endian) self.lineEdit_description.setText(description) self.offsetsList = [] if not isinstance(address, type_defs.PointerType): @@ -2005,7 +1988,7 @@ def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length= self.setupUi(self) self.setMaximumSize(100, 100) self.lineEdit_Length.setValidator(QHexValidator(999, self)) - GuiUtils.fill_value_combobox(self.comboBox_ValueType, index) + guiutils.fill_value_combobox(self.comboBox_ValueType, index) if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.label_Length.show() self.lineEdit_Length.show() @@ -2094,7 +2077,7 @@ def __init__(self, parent=None): self.setWindowFlags(self.windowFlags() | Qt.WindowType.FramelessWindowHint) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) if parent: - GuiUtils.center_to_parent(self) + guiutils.center_to_parent(self) self.keyPressEvent = QEvent.ignore # Make use of this background_thread when you spawn a LoadingDialogForm @@ -2188,7 +2171,7 @@ def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typ self.adjustSize() self.verticalLayout.removeWidget(self.buttonBox) # Pushing buttonBox to the end self.verticalLayout.addWidget(self.buttonBox) - for widget in GuiUtils.get_layout_widgets(self.verticalLayout): + for widget in guiutils.get_layout_widgets(self.verticalLayout): if isinstance(widget, QLabel): continue widget.setFocus() # Focus to the first input field @@ -2242,7 +2225,7 @@ def __init__(self, set_default_settings_func, parent=None): self.set_default_settings = set_default_settings_func self.hotkey_to_value = {} # Dict[str:str]-->Dict[Hotkey.name:settings_value] self.listWidget_Options.currentRowChanged.connect(self.change_display) - icons_directory = GuiUtils.get_icons_directory() + icons_directory = guiutils.get_icons_directory() self.pushButton_GDBPath.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) self.listWidget_Functions.currentRowChanged.connect(self.listWidget_Functions_current_row_changed) self.keySequenceEdit_Hotkey.keySequenceChanged.connect(self.keySequenceEdit_Hotkey_key_sequence_changed) @@ -2460,7 +2443,7 @@ def __init__(self, parent=None): self.setupUi(self) global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.completion_model = QStringListModel() self.completer = QCompleter() self.completer.setModel(self.completion_model) @@ -2581,7 +2564,7 @@ class AboutWidgetForm(QTabWidget, AboutWidget): def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) - GuiUtils.center(self) + guiutils.center(self) # This section has untranslated text since it's just a placeholder license_text = open("COPYING").read() @@ -2661,7 +2644,7 @@ def __init__(self, parent=None): super().__init__() self.setupUi(self) self.parent = lambda: parent - GuiUtils.center(self) + guiutils.center(self) self.updating_memoryview = False self.process_stopped.connect(self.on_process_stop) self.process_running.connect(self.on_process_running) @@ -2719,7 +2702,7 @@ def initialize_disassemble_view(self): self.verticalScrollBar_Disassemble.sliderChange = self.disassemble_scrollbar_sliderchanged - GuiUtils.center_scroll_bar(self.verticalScrollBar_Disassemble) + guiutils.center_scroll_bar(self.verticalScrollBar_Disassemble) # Format: [address1, address2, ...] self.tableWidget_Disassemble.travel_history = [] @@ -2778,7 +2761,7 @@ def initialize_hex_view(self): self.tableWidget_HexView_Address.verticalHeader().setDefaultSectionSize( self.tableView_HexView_Hex.verticalHeader().defaultSectionSize()) - GuiUtils.center_scroll_bar(self.verticalScrollBar_HexView) + guiutils.center_scroll_bar(self.verticalScrollBar_HexView) def show_trace_window(self): if GDB_Engine.currentpid == -1: @@ -2809,14 +2792,14 @@ def execute_till_return(self): def set_address(self): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) GDB_Engine.set_convenience_variable("pc", current_address) self.refresh_disassemble_view() def edit_instruction(self): - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) bytes_aob = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() @@ -2825,7 +2808,7 @@ def edit_instruction(self): def nop_instruction(self): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_address_int = int(current_address, 16) @@ -2836,7 +2819,7 @@ def nop_instruction(self): def toggle_breakpoint(self): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_address_int = int(current_address, 16) @@ -2908,9 +2891,9 @@ def widget_HexView_context_menu_event(self, event): add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) delete_breakpoint = menu.addAction(tr.DELETE_BREAKPOINT) if not GDB_Engine.check_address_in_breakpoints(selected_address): - GuiUtils.delete_menu_entries(menu, [add_condition, delete_breakpoint]) + guiutils.delete_menu_entries(menu, [add_condition, delete_breakpoint]) else: - GuiUtils.delete_menu_entries(menu, [watchpoint_menu.menuAction()]) + guiutils.delete_menu_entries(menu, [watchpoint_menu.menuAction()]) font_size = self.widget_HexView.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -2984,7 +2967,7 @@ def hex_view_scrollbar_sliderchanged(self, event): else: next_address = current_address + 0x40 self.hex_dump_address(next_address) - GuiUtils.center_scroll_bar(self.verticalScrollBar_HexView) + guiutils.center_scroll_bar(self.verticalScrollBar_HexView) self.bHexViewScrolling = False def disassemble_scroll_up(self): @@ -3008,7 +2991,7 @@ def disassemble_scrollbar_sliderchanged(self, even): self.tableWidget_Disassemble_scroll("previous", instructions_per_scroll) else: self.tableWidget_Disassemble_scroll("next", instructions_per_scroll) - GuiUtils.center_scroll_bar(self.verticalScrollBar_Disassemble) + guiutils.center_scroll_bar(self.verticalScrollBar_Disassemble) self.bDisassemblyScrolling = False def on_hex_view_current_changed(self, QModelIndex_current): @@ -3392,7 +3375,7 @@ def tableWidget_StackTrace_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_StackTrace.item(row, column).text()) - selected_row = GuiUtils.get_current_row(self.tableWidget_StackTrace) + selected_row = guiutils.get_current_row(self.tableWidget_StackTrace) menu = QMenu() switch_to_stack = menu.addAction(tr.FULL_STACK) @@ -3401,7 +3384,7 @@ def copy_to_clipboard(row, column): copy_return = clipboard_menu.addAction(tr.COPY_RETURN_ADDRESS) copy_frame = clipboard_menu.addAction(tr.COPY_FRAME_ADDRESS) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [clipboard_menu.menuAction()]) + guiutils.delete_menu_entries(menu, [clipboard_menu.menuAction()]) refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.tableWidget_StackTrace.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") @@ -3433,7 +3416,7 @@ def update_stack(self): def tableWidget_Stack_key_press_event(self, event): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) + selected_row = guiutils.get_current_row(self.tableWidget_Stack) if selected_row == -1: actions = type_defs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack) @@ -3461,7 +3444,7 @@ def copy_to_clipboard(row, column): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) + selected_row = guiutils.get_current_row(self.tableWidget_Stack) if selected_row == -1: current_address = None else: @@ -3479,7 +3462,7 @@ def copy_to_clipboard(row, column): show_in_disas = menu.addAction(f"{tr.DISASSEMBLE_VALUE_POINTER}[Ctrl+D]") show_in_hex = menu.addAction(f"{tr.HEXVIEW_VALUE_POINTER}[Ctrl+H]") if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [clipboard_menu.menuAction(), show_in_disas, show_in_hex]) + guiutils.delete_menu_entries(menu, [clipboard_menu.menuAction(), show_in_disas, show_in_hex]) font_size = self.tableWidget_Stack.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -3500,7 +3483,7 @@ def copy_to_clipboard(row, column): def tableWidget_Stack_double_click(self, index): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Stack) + selected_row = guiutils.get_current_row(self.tableWidget_Stack) if index.column() == STACK_POINTER_ADDRESS_COL: current_address_text = self.tableWidget_Stack.item(selected_row, STACK_POINTER_ADDRESS_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3517,7 +3500,7 @@ def tableWidget_Stack_double_click(self, index): def tableWidget_StackTrace_double_click(self, index): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_StackTrace) + selected_row = guiutils.get_current_row(self.tableWidget_StackTrace) if index.column() == STACKTRACE_RETURN_ADDRESS_COL: current_address_text = self.tableWidget_StackTrace.item(selected_row, STACKTRACE_RETURN_ADDRESS_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -3551,7 +3534,7 @@ def widget_Disassemble_wheel_event(self, event): def disassemble_check_viewport(self, where, instruction_count): if GDB_Engine.currentpid == -1: return - current_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + current_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_row_height = self.tableWidget_Disassemble.rowViewportPosition(current_row) row_height = self.tableWidget_Disassemble.verticalHeader().defaultSectionSize() max_height = self.tableWidget_Disassemble.maximumViewportSize().height() @@ -3611,7 +3594,7 @@ def widget_HexView_key_press_event(self, event): def tableWidget_Disassemble_key_press_event(self, event): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -3648,7 +3631,7 @@ def tableWidget_Disassemble_item_double_clicked(self, index): if GDB_Engine.currentpid == -1: return if index.column() == DISAS_COMMENT_COL: - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = int(SysUtils.extract_address(current_address_text), 16) if current_address in self.tableWidget_Disassemble.bookmarks: @@ -3660,7 +3643,7 @@ def tableWidget_Disassemble_item_selection_changed(self): if GDB_Engine.currentpid == -1: return try: - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) selected_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() self.disassemble_last_selected_address_int = int(SysUtils.extract_address(selected_address_text), 16) except (TypeError, ValueError, AttributeError): @@ -3697,7 +3680,7 @@ def copy_all_columns(row): copied_string += self.tableWidget_Disassemble.item(row, column).text() + "\t" app.clipboard().setText(copied_string) - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_address_int = int(current_address, 16) @@ -3711,18 +3694,18 @@ def copy_all_columns(row): self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text()) follow = menu.addAction(f"{tr.FOLLOW}[Space]") if not followable: - GuiUtils.delete_menu_entries(menu, [follow]) + guiutils.delete_menu_entries(menu, [follow]) examine_referrers = menu.addAction(f"{tr.EXAMINE_REFERRERS}[Ctrl+E]") - if not GuiUtils.contains_reference_mark(current_address_text): - GuiUtils.delete_menu_entries(menu, [examine_referrers]) + if not guiutils.contains_reference_mark(current_address_text): + guiutils.delete_menu_entries(menu, [examine_referrers]) bookmark = menu.addAction(f"{tr.BOOKMARK_ADDRESS}[Ctrl+B]") delete_bookmark = menu.addAction(tr.DELETE_BOOKMARK) change_comment = menu.addAction(tr.CHANGE_COMMENT) is_bookmarked = current_address_int in self.tableWidget_Disassemble.bookmarks if not is_bookmarked: - GuiUtils.delete_menu_entries(menu, [delete_bookmark, change_comment]) + guiutils.delete_menu_entries(menu, [delete_bookmark, change_comment]) else: - GuiUtils.delete_menu_entries(menu, [bookmark]) + guiutils.delete_menu_entries(menu, [bookmark]) go_to_bookmark = menu.addMenu(tr.GO_TO_BOOKMARK_ADDRESS) address_list = [hex(address) for address in self.tableWidget_Disassemble.bookmarks.keys()] bookmark_actions = [go_to_bookmark.addAction(item.all) for item in GDB_Engine.examine_expressions(address_list)] @@ -3730,12 +3713,12 @@ def copy_all_columns(row): toggle_breakpoint = menu.addAction(f"{tr.TOGGLE_BREAKPOINT}[F5]") add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) if not GDB_Engine.check_address_in_breakpoints(current_address_int): - GuiUtils.delete_menu_entries(menu, [add_condition]) + guiutils.delete_menu_entries(menu, [add_condition]) menu.addSeparator() edit_instruction = menu.addAction(tr.EDIT_INSTRUCTION) nop_instruction = menu.addAction(tr.REPLACE_WITH_NOPS) if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() == '90': - GuiUtils.delete_menu_entries(menu, [nop_instruction]) + guiutils.delete_menu_entries(menu, [nop_instruction]) menu.addSeparator() track_breakpoint = menu.addAction(tr.WHAT_ACCESSES_INSTRUCTION) trace_instructions = menu.addAction(f"{tr.TRACE_INSTRUCTION}[Ctrl+T]") @@ -3785,7 +3768,7 @@ def copy_all_columns(row): def dissect_current_region(self): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -3798,7 +3781,7 @@ def dissect_current_region(self): def exec_examine_referrers_widget(self, current_address_text): if GDB_Engine.currentpid == -1: return - if not GuiUtils.contains_reference_mark(current_address_text): + if not guiutils.contains_reference_mark(current_address_text): return current_address = SysUtils.extract_address(current_address_text) current_address_int = int(current_address, 16) @@ -3808,7 +3791,7 @@ def exec_examine_referrers_widget(self, current_address_text): def exec_trace_instructions_dialog(self): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -3818,7 +3801,7 @@ def exec_trace_instructions_dialog(self): def exec_track_breakpoint_dialog(self): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) current_instruction = self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() @@ -3831,7 +3814,7 @@ def exec_track_breakpoint_dialog(self): def exec_disassemble_go_to_dialog(self): if GDB_Engine.currentpid == -1: return - selected_row = GuiUtils.get_current_row(self.tableWidget_Disassemble) + selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -3978,7 +3961,7 @@ def pushButton_ShowFloatRegisters_clicked(self): return self.float_registers_widget = FloatRegisterWidgetForm() self.float_registers_widget.show() - GuiUtils.center_to_window(self.float_registers_widget, self.widget_Registers) + guiutils.center_to_window(self.float_registers_widget, self.widget_Registers) class BookmarkWidgetForm(QWidget, BookmarkWidget): @@ -3988,7 +3971,7 @@ def __init__(self, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.listWidget.contextMenuEvent = self.listWidget_context_menu_event self.listWidget.currentRowChanged.connect(self.change_display) @@ -4028,7 +4011,7 @@ def exec_change_comment_dialog(self, current_address): self.refresh_table() def listWidget_context_menu_event(self, event): - current_item = GuiUtils.get_current_item(self.listWidget) + current_item = guiutils.get_current_item(self.listWidget) if current_item: current_address = int(SysUtils.extract_address(current_item.text()), 16) if current_address not in self.parent().tableWidget_Disassemble.bookmarks: @@ -4042,7 +4025,7 @@ def listWidget_context_menu_event(self, event): change_comment = menu.addAction(tr.CHANGE_COMMENT) delete_record = menu.addAction(f"{tr.DELETE}[Del]") if current_item is None: - GuiUtils.delete_menu_entries(menu, [change_comment, delete_record]) + guiutils.delete_menu_entries(menu, [change_comment, delete_record]) menu.addSeparator() refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.listWidget.font().pointSize() @@ -4060,7 +4043,7 @@ def listWidget_context_menu_event(self, event): pass def delete_record(self): - current_item = GuiUtils.get_current_item(self.listWidget) + current_item = guiutils.get_current_item(self.listWidget) if not current_item: return current_address = int(SysUtils.extract_address(current_item.text()), 16) @@ -4116,7 +4099,7 @@ class StackTraceInfoWidgetForm(QWidget, StackTraceInfoWidget): def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.listWidget_ReturnAddresses.currentRowChanged.connect(self.update_frame_info) self.update_stacktrace() @@ -4143,7 +4126,7 @@ def __init__(self, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) # Saving the original function because super() doesn't work when we override functions like this @@ -4154,7 +4137,7 @@ def __init__(self, parent=None): self.refresh() def tableWidget_Instructions_context_menu_event(self, event): - selected_row = GuiUtils.get_current_row(self.tableWidget_Instructions) + selected_row = guiutils.get_current_row(self.tableWidget_Instructions) menu = QMenu() restore_instruction = menu.addAction(tr.RESTORE_INSTRUCTION) if selected_row != -1: @@ -4162,7 +4145,7 @@ def tableWidget_Instructions_context_menu_event(self, event): selected_address = SysUtils.extract_address(selected_address_text) selected_address_int = int(selected_address, 16) else: - GuiUtils.delete_menu_entries(menu, [restore_instruction]) + guiutils.delete_menu_entries(menu, [restore_instruction]) selected_address_int = None menu.addSeparator() refresh = menu.addAction(f"{tr.REFRESH}[R]") @@ -4192,7 +4175,7 @@ def refresh(self): if not instr_name: instr_name = "??" self.tableWidget_Instructions.setItem(row, INSTR_NAME_COL, QTableWidgetItem(instr_name)) - GuiUtils.resize_to_contents(self.tableWidget_Instructions) + guiutils.resize_to_contents(self.tableWidget_Instructions) def refresh_all(self): self.parent().refresh_hex_view() @@ -4226,7 +4209,7 @@ def __init__(self, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_BreakpointInfo.contextMenuEvent = self.tableWidget_BreakpointInfo_context_menu_event @@ -4250,7 +4233,7 @@ def refresh(self): self.tableWidget_BreakpointInfo.setItem(row, BREAK_ON_HIT_COL, QTableWidgetItem(item.on_hit)) self.tableWidget_BreakpointInfo.setItem(row, BREAK_HIT_COUNT_COL, QTableWidgetItem(item.hit_count)) self.tableWidget_BreakpointInfo.setItem(row, BREAK_COND_COL, QTableWidgetItem(item.condition)) - GuiUtils.resize_to_contents(self.tableWidget_BreakpointInfo) + guiutils.resize_to_contents(self.tableWidget_BreakpointInfo) self.textBrowser_BreakpointInfo.clear() self.textBrowser_BreakpointInfo.setText(GDB_Engine.send_command("info break", cli_output=True)) @@ -4260,7 +4243,7 @@ def delete_breakpoint(self, address): self.refresh_all() def tableWidget_BreakpointInfo_key_press_event(self, event): - selected_row = GuiUtils.get_current_row(self.tableWidget_BreakpointInfo) + selected_row = guiutils.get_current_row(self.tableWidget_BreakpointInfo) if selected_row != -1: current_address_text = self.tableWidget_BreakpointInfo.item(selected_row, BREAK_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -4294,7 +4277,7 @@ def exec_enable_count_dialog(self, current_address): count=count) def tableWidget_BreakpointInfo_context_menu_event(self, event): - selected_row = GuiUtils.get_current_row(self.tableWidget_BreakpointInfo) + selected_row = guiutils.get_current_row(self.tableWidget_BreakpointInfo) if selected_row != -1: current_address_text = self.tableWidget_BreakpointInfo.item(selected_row, BREAK_ADDR_COL).text() current_address = SysUtils.extract_address(current_address_text) @@ -4316,7 +4299,7 @@ def tableWidget_BreakpointInfo_context_menu_event(self, event): if current_address is None: deletion_list = [change_condition, enable, disable, enable_once, enable_count, enable_delete, delete_breakpoint] - GuiUtils.delete_menu_entries(menu, deletion_list) + guiutils.delete_menu_entries(menu, deletion_list) refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.tableWidget_BreakpointInfo.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") @@ -4371,7 +4354,7 @@ def __init__(self, address, length, watchpoint_type, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.update_timer = QTimer(timeout=self.update_list) self.stopped = False @@ -4408,7 +4391,7 @@ def update_list(self): for row, key in enumerate(info): self.tableWidget_Opcodes.setItem(row, TRACK_WATCHPOINT_COUNT_COL, QTableWidgetItem(str(info[key][0]))) self.tableWidget_Opcodes.setItem(row, TRACK_WATCHPOINT_ADDR_COL, QTableWidgetItem(info[key][1])) - GuiUtils.resize_to_contents(self.tableWidget_Opcodes) + guiutils.resize_to_contents(self.tableWidget_Opcodes) self.tableWidget_Opcodes.selectRow(self.last_selected_row) def tableWidget_Opcodes_current_changed(self, QModelIndex_current): @@ -4466,7 +4449,7 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.stopped = False self.address = address self.setWindowFlags(Qt.WindowType.Window) - GuiUtils.center_to_parent(self) + guiutils.center_to_parent(self) self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) breakpoint = GDB_Engine.track_breakpoint(address, register_expressions) if not breakpoint: @@ -4475,7 +4458,7 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.breakpoint = breakpoint self.info = {} self.last_selected_row = 0 - GuiUtils.fill_value_combobox(self.comboBox_ValueType) + guiutils.fill_value_combobox(self.comboBox_ValueType) self.pushButton_Stop.clicked.connect(self.pushButton_Stop_clicked) self.tableWidget_TrackInfo.itemDoubleClicked.connect(self.tableWidget_TrackInfo_item_double_clicked) self.tableWidget_TrackInfo.selectionModel().currentChanged.connect(self.tableWidget_TrackInfo_current_changed) @@ -4510,7 +4493,7 @@ def update_values(self): value = GDB_Engine.read_memory(address, value_type, 10, mem_handle=mem_handle) value = "" if value is None else str(value) self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_VALUE_COL, QTableWidgetItem(value)) - GuiUtils.resize_to_contents(self.tableWidget_TrackInfo) + guiutils.resize_to_contents(self.tableWidget_TrackInfo) self.tableWidget_TrackInfo.selectRow(self.last_selected_row) def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): @@ -4586,7 +4569,7 @@ def __init__(self, address, breakpoint, parent=None): type_defs.TRACE_STATUS.STATUS_FINISHED: tr.TRACING_COMPLETED } self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) - GuiUtils.center(self) + guiutils.center(self) self.address = address self.breakpoint = breakpoint media_directory = SysUtils.get_media_directory() @@ -4640,7 +4623,7 @@ def __init__(self, address="", prompt_dialog=True, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.address = address self.trace_data = None self.treeWidget_InstructionInfo.currentItemChanged.connect(self.display_collected_data) @@ -4742,7 +4725,7 @@ def treeWidget_InstructionInfo_context_menu_event(self, event): pass def treeWidget_InstructionInfo_item_double_clicked(self, index): - current_item = GuiUtils.get_current_item(self.treeWidget_InstructionInfo) + current_item = guiutils.get_current_item(self.treeWidget_InstructionInfo) if not current_item: return address = SysUtils.extract_address(current_item.trace_data[0]) @@ -4761,7 +4744,7 @@ def __init__(self, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.textBrowser_AddressInfo.setFixedHeight(100) self.pushButton_Search.clicked.connect(self.refresh_table) @@ -4770,7 +4753,7 @@ def __init__(self, parent=None): self.tableWidget_SymbolInfo.selectionModel().currentChanged.connect(self.tableWidget_SymbolInfo_current_changed) self.tableWidget_SymbolInfo.itemDoubleClicked.connect(self.tableWidget_SymbolInfo_item_double_clicked) self.tableWidget_SymbolInfo.contextMenuEvent = self.tableWidget_SymbolInfo_context_menu_event - icons_directory = GuiUtils.get_icons_directory() + icons_directory = guiutils.get_icons_directory() self.pushButton_Help.setIcon(QIcon(QPixmap(icons_directory + "/help.png"))) self.pushButton_Help.clicked.connect(self.pushButton_Help_clicked) @@ -4802,7 +4785,7 @@ def apply_data(self, output): self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_ADDR_COL, address_item) self.tableWidget_SymbolInfo.setItem(row, FUNCTIONS_INFO_SYMBOL_COL, QTableWidgetItem(item[1])) self.tableWidget_SymbolInfo.setSortingEnabled(True) - GuiUtils.resize_to_contents(self.tableWidget_SymbolInfo) + guiutils.resize_to_contents(self.tableWidget_SymbolInfo) def tableWidget_SymbolInfo_current_changed(self, QModelIndex_current): self.textBrowser_AddressInfo.clear() @@ -4822,13 +4805,13 @@ def tableWidget_SymbolInfo_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_SymbolInfo.item(row, column).text()) - selected_row = GuiUtils.get_current_row(self.tableWidget_SymbolInfo) + selected_row = guiutils.get_current_row(self.tableWidget_SymbolInfo) menu = QMenu() copy_address = menu.addAction(tr.COPY_ADDRESS) copy_symbol = menu.addAction(tr.COPY_SYMBOL) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_address, copy_symbol]) + guiutils.delete_menu_entries(menu, [copy_address, copy_symbol]) font_size = self.tableWidget_SymbolInfo.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5014,7 +4997,7 @@ def __init__(self, is_window=False, parent=None): global instances instances.append(self) if is_window: - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.show_type_defs() self.splitter.setStretchFactor(0, 1) @@ -5022,12 +5005,12 @@ def __init__(self, is_window=False, parent=None): libpince_directory = SysUtils.get_libpince_directory() self.textBrowser_TypeDefs.setText(open(libpince_directory + "/type_defs.py").read()) source_menu_items = ["(Tagged only)", "(All)"] - self.libpince_source_files = ["GDB_Engine", "SysUtils", "GuiUtils"] - source_menu_items.extend(self.libpince_source_files) + self.source_files = ["GDB_Engine", "SysUtils", "guiutils"] + source_menu_items.extend(self.source_files) self.comboBox_SourceFile.addItems(source_menu_items) self.comboBox_SourceFile.setCurrentIndex(0) self.fill_resource_tree() - icons_directory = GuiUtils.get_icons_directory() + icons_directory = guiutils.get_icons_directory() self.pushButton_TextUp.setIcon(QIcon(QPixmap(icons_directory + "/bullet_arrow_up.png"))) self.pushButton_TextDown.setIcon(QIcon(QPixmap(icons_directory + "/bullet_arrow_down.png"))) self.comboBox_SourceFile.currentIndexChanged.connect(self.comboBox_SourceFile_current_index_changed) @@ -5045,7 +5028,7 @@ def tableWidget_ResourceTable_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_ResourceTable.item(row, column).text()) - selected_row = GuiUtils.get_current_row(self.tableWidget_ResourceTable) + selected_row = guiutils.get_current_row(self.tableWidget_ResourceTable) menu = QMenu() refresh = menu.addAction("Refresh") @@ -5053,7 +5036,7 @@ def copy_to_clipboard(row, column): copy_item = menu.addAction("Copy Item") copy_value = menu.addAction("Copy Value") if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_item, copy_value]) + guiutils.delete_menu_entries(menu, [copy_item, copy_value]) font_size = self.tableWidget_ResourceTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5069,7 +5052,7 @@ def copy_to_clipboard(row, column): def treeWidget_ResourceTree_context_menu_event(self, event): def copy_to_clipboard(column): - current_item = GuiUtils.get_current_item(self.treeWidget_ResourceTree) + current_item = guiutils.get_current_item(self.treeWidget_ResourceTree) if current_item: app.clipboard().setText(current_item.text(column)) @@ -5081,7 +5064,7 @@ def collapse_all(): self.treeWidget_ResourceTree.collapseAll() self.resize_resource_tree() - selected_row = GuiUtils.get_current_row(self.treeWidget_ResourceTree) + selected_row = guiutils.get_current_row(self.treeWidget_ResourceTree) menu = QMenu() refresh = menu.addAction("Refresh") @@ -5089,7 +5072,7 @@ def collapse_all(): copy_item = menu.addAction("Copy Item") copy_value = menu.addAction("Copy Value") if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_item, copy_value]) + guiutils.delete_menu_entries(menu, [copy_item, copy_value]) menu.addSeparator() expand_all_items = menu.addAction("Expand All") collapse_all_items = menu.addAction("Collapse All") @@ -5126,7 +5109,7 @@ def fill_resource_tree(self): self.stackedWidget_Resources.setCurrentIndex(0) self.treeWidget_ResourceTree.clear() parent = self.treeWidget_ResourceTree - checked_source_files = self.convert_to_modules(self.libpince_source_files) + checked_source_files = self.convert_to_modules(self.source_files) tag_dict = SysUtils.get_tags(checked_source_files, type_defs.tag_to_string, self.lineEdit_Search.text()) docstring_dict = SysUtils.get_docstrings(checked_source_files, self.lineEdit_Search.text()) for tag in tag_dict: @@ -5152,7 +5135,7 @@ def fill_resource_table(self): self.tableWidget_ResourceTable.setSortingEnabled(False) self.tableWidget_ResourceTable.setRowCount(0) if self.comboBox_SourceFile.currentIndex() == 1: # (All) - checked_source_files = self.libpince_source_files + checked_source_files = self.source_files else: checked_source_files = [self.comboBox_SourceFile.currentText()] checked_source_files = self.convert_to_modules(checked_source_files) @@ -5168,7 +5151,7 @@ def fill_resource_table(self): self.tableWidget_ResourceTable.setItem(row, LIBPINCE_REFERENCE_VALUE_COL, table_widget_item_value) self.tableWidget_ResourceTable.setSortingEnabled(True) self.tableWidget_ResourceTable.sortByColumn(LIBPINCE_REFERENCE_ITEM_COL, Qt.SortOrder.AscendingOrder) - GuiUtils.resize_to_contents(self.tableWidget_ResourceTable) + guiutils.resize_to_contents(self.tableWidget_ResourceTable) def pushButton_TextDown_clicked(self): if self.found_count == 0: @@ -5256,7 +5239,7 @@ class LogFileWidgetForm(QWidget, LogFileWidget): def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) - GuiUtils.center(self) + guiutils.center(self) global instances instances.append(self) self.setWindowFlags(Qt.WindowType.Window) @@ -5314,12 +5297,12 @@ def __init__(self, start="", end="", parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.lineEdit_Start.setText(start) self.lineEdit_End.setText(end) self.tableWidget_Opcodes.setColumnWidth(SEARCH_OPCODE_ADDR_COL, 250) - icons_directory = GuiUtils.get_icons_directory() + icons_directory = guiutils.get_icons_directory() self.pushButton_Help.setIcon(QIcon(QPixmap(icons_directory + "/help.png"))) self.pushButton_Help.clicked.connect(self.pushButton_Help_clicked) self.pushButton_Search.clicked.connect(self.refresh_table) @@ -5369,13 +5352,13 @@ def tableWidget_Opcodes_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_Opcodes.item(row, column).text()) - selected_row = GuiUtils.get_current_row(self.tableWidget_Opcodes) + selected_row = guiutils.get_current_row(self.tableWidget_Opcodes) menu = QMenu() copy_address = menu.addAction(tr.COPY_ADDRESS) copy_opcode = menu.addAction(tr.COPY_OPCODE) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_address, copy_opcode]) + guiutils.delete_menu_entries(menu, [copy_address, copy_opcode]) font_size = self.tableWidget_Opcodes.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5400,7 +5383,7 @@ def __init__(self, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center(self) + guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.refresh_table() self.tableWidget_MemoryRegions.contextMenuEvent = self.tableWidget_MemoryRegions_context_menu_event @@ -5418,13 +5401,13 @@ def refresh_table(self): self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PERM_COL, QTableWidgetItem(perms)) self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_OFFSET_COL, QTableWidgetItem(offset)) self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PATH_COL, QTableWidgetItem(path)) - GuiUtils.resize_to_contents(self.tableWidget_MemoryRegions) + guiutils.resize_to_contents(self.tableWidget_MemoryRegions) def tableWidget_MemoryRegions_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_MemoryRegions.item(row, column).text()) - selected_row = GuiUtils.get_current_row(self.tableWidget_MemoryRegions) + selected_row = guiutils.get_current_row(self.tableWidget_MemoryRegions) menu = QMenu() refresh = menu.addAction(f"{tr.REFRESH}[R]") @@ -5433,7 +5416,7 @@ def copy_to_clipboard(row, column): copy_offset = menu.addAction(tr.COPY_OFFSET) copy_path = menu.addAction(tr.COPY_PATH) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_addresses, copy_offset, copy_path]) + guiutils.delete_menu_entries(menu, [copy_addresses, copy_offset, copy_path]) font_size = self.tableWidget_MemoryRegions.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5542,7 +5525,7 @@ def show_memory_regions(self): self.region_list.append((start, end)) self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_ADDR_COL, QTableWidgetItem(address)) self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_PATH_COL, QTableWidgetItem(path)) - GuiUtils.resize_to_contents(self.tableWidget_ExecutableMemoryRegions) + guiutils.resize_to_contents(self.tableWidget_ExecutableMemoryRegions) def scan_finished(self): self.init_pre_scan_gui() @@ -5586,11 +5569,11 @@ class ReferencedStringsWidgetForm(QWidget, ReferencedStringsWidget): def __init__(self, parent=None): super().__init__() self.setupUi(self) - GuiUtils.fill_value_combobox(self.comboBox_ValueType, type_defs.VALUE_INDEX.INDEX_STRING_UTF8) + guiutils.fill_value_combobox(self.comboBox_ValueType, type_defs.VALUE_INDEX.INDEX_STRING_UTF8) self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center_to_parent(self) + guiutils.center_to_parent(self) self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_References.setColumnWidth(REF_STR_ADDR_COL, 150) self.tableWidget_References.setColumnWidth(REF_STR_COUNT_COL, 80) @@ -5673,13 +5656,13 @@ def tableWidget_References_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_References.item(row, column).text()) - selected_row = GuiUtils.get_current_row(self.tableWidget_References) + selected_row = guiutils.get_current_row(self.tableWidget_References) menu = QMenu() copy_address = menu.addAction(tr.COPY_ADDRESS) copy_value = menu.addAction(tr.COPY_VALUE) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_address, copy_value]) + guiutils.delete_menu_entries(menu, [copy_address, copy_value]) font_size = self.tableWidget_References.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5696,12 +5679,12 @@ def listWidget_Referrers_context_menu_event(self, event): def copy_to_clipboard(row): app.clipboard().setText(self.listWidget_Referrers.item(row).text()) - selected_row = GuiUtils.get_current_row(self.listWidget_Referrers) + selected_row = guiutils.get_current_row(self.listWidget_Referrers) menu = QMenu() copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_address]) + guiutils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5725,7 +5708,7 @@ def __init__(self, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center_to_parent(self) + guiutils.center_to_parent(self) self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_References.setColumnWidth(REF_CALL_ADDR_COL, 480) self.splitter.setStretchFactor(0, 1) @@ -5802,12 +5785,12 @@ def tableWidget_References_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_References.item(row, column).text()) - selected_row = GuiUtils.get_current_row(self.tableWidget_References) + selected_row = guiutils.get_current_row(self.tableWidget_References) menu = QMenu() copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_address]) + guiutils.delete_menu_entries(menu, [copy_address]) font_size = self.tableWidget_References.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5823,12 +5806,12 @@ def listWidget_Referrers_context_menu_event(self, event): def copy_to_clipboard(row): app.clipboard().setText(self.listWidget_Referrers.item(row).text()) - selected_row = GuiUtils.get_current_row(self.listWidget_Referrers) + selected_row = guiutils.get_current_row(self.listWidget_Referrers) menu = QMenu() copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_address]) + guiutils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -5852,7 +5835,7 @@ def __init__(self, int_address, parent=None): self.parent = lambda: parent global instances instances.append(self) - GuiUtils.center_to_parent(self) + guiutils.center_to_parent(self) self.setWindowFlags(Qt.WindowType.Window) self.splitter.setStretchFactor(0, 1) self.textBrowser_DisasInfo.resize(600, self.textBrowser_DisasInfo.height()) @@ -5946,12 +5929,12 @@ def listWidget_Referrers_context_menu_event(self, event): def copy_to_clipboard(row): app.clipboard().setText(self.listWidget_Referrers.item(row).text()) - selected_row = GuiUtils.get_current_row(self.listWidget_Referrers) + selected_row = guiutils.get_current_row(self.listWidget_Referrers) menu = QMenu() copy_address = menu.addAction(tr.COPY_ADDRESS) if selected_row == -1: - GuiUtils.delete_menu_entries(menu, [copy_address]) + guiutils.delete_menu_entries(menu, [copy_address]) font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index 39aa7b1b..55b73774 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -66,7 +66,7 @@ (.*)$ # Pathname """, VERBOSE) -# --------------------------------------------GuiUtils------------------------------------------------------------------ +# --------------------------------------------guiutils------------------------------------------------------------------ reference_mark = compile(r"\{\d*\}") diff --git a/run_tests.py b/run_tests.py index 877c0bc6..ab3baaf0 100644 --- a/run_tests.py +++ b/run_tests.py @@ -53,5 +53,5 @@ parser.error("Provide at least one of these arguments: -a or -c") unittest.main(module="tests.GDB_Engine_tests", exit=False, argv=[""]) unittest.main(module="tests.SysUtils_tests", exit=False, argv=[""]) -unittest.main(module="tests.GuiUtils_tests", exit=False, argv=[""]) +unittest.main(module="tests.guiutils_tests", exit=False, argv=[""]) GDB_Engine.detach() diff --git a/tests/GuiUtils_tests.py b/tests/guiutils_tests.py similarity index 86% rename from tests/GuiUtils_tests.py rename to tests/guiutils_tests.py index 1da4e72f..6d272cb5 100644 --- a/tests/GuiUtils_tests.py +++ b/tests/guiutils_tests.py @@ -17,11 +17,11 @@ import unittest -# from libpince import GuiUtils +# from GUI.Utils import guiutils -class GuiUtils_tests(unittest.TestCase): +class guiutils_tests(unittest.TestCase): def test_change_text_length(self): self.assertEqual(True, True) # The function below was removed during refactorization, thus making this test just a placeholder for now - # self.assertEqual(GuiUtils.change_text_length("AoB[42]", 30), "AoB[30]") + # self.assertEqual(guiutils.change_text_length("AoB[42]", 30), "AoB[30]") From 086803776e284623031071ee67f97e2d9fb29f9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 20 Nov 2023 21:40:43 +0300 Subject: [PATCH 273/487] Make custom labels translatable --- GUI/CustomLabels/FlagRegisterLabel.py | 3 ++- GUI/CustomLabels/RegisterLabel.py | 8 ++++---- i18n/ts/it_IT.ts | 15 +++++++++++++++ i18n/ts/zh_CN.ts | 15 +++++++++++++++ tr/tr.py | 5 ++++- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/GUI/CustomLabels/FlagRegisterLabel.py b/GUI/CustomLabels/FlagRegisterLabel.py index 1cf6cb78..1c58c7be 100644 --- a/GUI/CustomLabels/FlagRegisterLabel.py +++ b/GUI/CustomLabels/FlagRegisterLabel.py @@ -19,6 +19,7 @@ from PyQt6.QtCore import Qt from libpince import GDB_Engine, type_defs from PINCE import InputDialogForm +from tr.tr import TranslationConstants as tr class QFlagRegisterLabel(QLabel): @@ -42,7 +43,7 @@ def mouseDoubleClickEvent(self, QMouseEvent): return registers = GDB_Engine.read_registers() current_flag = self.objectName().lower() - label_text = "Enter the new value of flag " + self.objectName() + label_text = tr.ENTER_FLAG_VALUE.format(self.objectName()) register_dialog = InputDialogForm(item_list=[(label_text, ["0", "1", int(registers[current_flag])])]) if register_dialog.exec(): GDB_Engine.set_register_flag(current_flag, register_dialog.get_values()) diff --git a/GUI/CustomLabels/RegisterLabel.py b/GUI/CustomLabels/RegisterLabel.py index 30d5495b..9cd97411 100644 --- a/GUI/CustomLabels/RegisterLabel.py +++ b/GUI/CustomLabels/RegisterLabel.py @@ -20,7 +20,7 @@ from libpince import GDB_Engine, type_defs from PINCE import InputDialogForm from GUI.Utils import guiutils - +from tr.tr import TranslationConstants as tr class QRegisterLabel(QLabel): def __init__(self, parent=None): @@ -44,7 +44,7 @@ def mouseDoubleClickEvent(self, QMouseEvent): registers = GDB_Engine.read_registers() current_register = self.objectName().lower() register_dialog = InputDialogForm( - item_list=[("Enter the new value of register " + self.objectName(), registers[current_register])]) + item_list=[(tr.ENTER_REGISTER_VALUE.format(self.objectName()), registers[current_register])]) if register_dialog.exec(): GDB_Engine.set_convenience_variable(current_register, register_dialog.get_values()) self.set_value(GDB_Engine.read_registers()[current_register]) @@ -53,8 +53,8 @@ def contextMenuEvent(self, QContextMenuEvent): if GDB_Engine.currentpid == -1: return menu = QMenu() - show_in_hex_view = menu.addAction("Show in HexView") - show_in_disassembler = menu.addAction("Show in Disassembler") + show_in_hex_view = menu.addAction(tr.SHOW_HEXVIEW) + show_in_disassembler = menu.addAction(tr.SHOW_DISASSEMBLER) font_size = self.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(QContextMenuEvent.globalPos()) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 345731a2..9a35bec9 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -2191,6 +2191,11 @@ You can use the assigned variable from the GDB Console Enter the new value of register {} + + + Enter the new value of flag {} + + Restore this instruction @@ -2574,5 +2579,15 @@ Proceed? Big + + + Show in HexView + + + + + Show in Disassembler + + diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index f278ea6b..14691992 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -2246,6 +2246,11 @@ $28 是分配的便利变量 Enter the new value of register {} 输入寄存器{}的新值 + + + Enter the new value of flag {} + + Restore this instruction @@ -2647,5 +2652,15 @@ Proceed? Big + + + Show in HexView + + + + + Show in Disassembler + + diff --git a/tr/tr.py b/tr/tr.py index 5b62c62e..0117a0fa 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -249,6 +249,7 @@ def translate(): ADD_ENTRY = QT_TR_NOOP("Add new entry") DELETE = QT_TR_NOOP("Delete") ENTER_REGISTER_VALUE = QT_TR_NOOP("Enter the new value of register {}") + ENTER_FLAG_VALUE = QT_TR_NOOP("Enter the new value of flag {}") RESTORE_INSTRUCTION = QT_TR_NOOP("Restore this instruction") ENTER_HIT_COUNT = QT_TR_NOOP("Enter the hit count({} or higher)") HIT_COUNT_ASSERT_INT = QT_TR_NOOP("Hit count must be an integer") @@ -339,4 +340,6 @@ def translate(): FULL = QT_TR_NOOP("Full") HOST = QT_TR_NOOP("Host") LITTLE = QT_TR_NOOP("Little") - BIG = QT_TR_NOOP("Big") \ No newline at end of file + BIG = QT_TR_NOOP("Big") + SHOW_HEXVIEW = QT_TR_NOOP("Show in HexView") + SHOW_DISASSEMBLER = QT_TR_NOOP("Show in Disassembler") \ No newline at end of file From f320de2f57f2c94e78bb010385a76841cf189741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 25 Nov 2023 19:10:52 +0000 Subject: [PATCH 274/487] Push libscanmem undo fixes --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index f396cf54..2bbea6fa 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit f396cf5446ac45ca997e78f0acde46baa0f85126 +Subproject commit 2bbea6fac1b33d0e06f780d72b3294d22768719e From 2ce8f43ca2b51b17c45391dfcebfe2d1f16ae820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 30 Nov 2023 21:57:05 +0300 Subject: [PATCH 275/487] Implement relative addressing --- PINCE.py | 100 +++++++++++++++++++++++-------------------------------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/PINCE.py b/PINCE.py index df3d262f..69f13a66 100755 --- a/PINCE.py +++ b/PINCE.py @@ -297,7 +297,7 @@ def get_hotkeys(): # GDB expression cache # TODO: Try to find a fast and non-gdb way to calculate symbols so we don't need this -# This is one of the few tricks we do to minimize examine_expressions calls +# This is one of the few tricks we do to minimize examine_expression calls # This solution might bring problems if the symbols are changing frequently # Currently only address_table_loop uses this so user can refresh symbols with a button press exp_cache = {} @@ -514,7 +514,7 @@ def __init__(self): self.pushButton_About.clicked.connect(self.pushButton_About_clicked) self.pushButton_AddAddressManually.clicked.connect(self.pushButton_AddAddressManually_clicked) self.pushButton_MemoryView.clicked.connect(self.pushButton_MemoryView_clicked) - self.pushButton_RefreshAdressTable.clicked.connect(self.update_address_table) + self.pushButton_RefreshAdressTable.clicked.connect(lambda: self.update_address_table(use_cache=False)) self.pushButton_CopyToAddressTable.clicked.connect(self.copy_to_address_table) self.pushButton_CleanAddressTable.clicked.connect(self.delete_address_table_contents) self.tableWidget_valuesearchtable.cellDoubleClicked.connect( @@ -936,7 +936,8 @@ def treeWidget_AddressTable_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_selected_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), self.browse_region_for_selected_row), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_address_table), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), + lambda: self.update_address_table(use_cache=False)), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_selected_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_X), self.cut_selected_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_selected_records), @@ -962,17 +963,13 @@ def treeWidget_AddressTable_key_press_event(self, event): except KeyError: self.treeWidget_AddressTable.keyPressEvent_original(event) - def update_address_table(self, use_cache=False): + def update_address_table(self, use_cache=True): global exp_cache if GDB_Engine.currentpid == -1 or self.treeWidget_AddressTable.topLevelItemCount() == 0: return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) mem_handle = GDB_Engine.memory_handle() - rows = [] - address_list = [] - examine_indices = [] - examine_list = [] - index = 0 + basic_math_exp = re.compile(r"^[0-9a-fA-F][/*+\-0-9a-fA-FxX]+$") while True: row = it.value() if not row: @@ -980,53 +977,49 @@ def update_address_table(self, use_cache=False): it += 1 address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) if isinstance(address_data, type_defs.PointerType): - address = address_data.base_address + expression = address_data.base_address else: - address = address_data - # Simple addresses first, examine_expression takes much longer time, especially for larger tables - try: - int(address, 0) - except (ValueError, TypeError): - if use_cache and address in exp_cache: - address = exp_cache[address] - else: - examine_list.append(address) - examine_indices.append(index) - address_list.append(address) - rows.append(row) - index += 1 - for index, item in enumerate(GDB_Engine.examine_expressions(examine_list)): - exp_cache[examine_list[index]] = item.address - address_list[examine_indices[index]] = item.address - for index, row in enumerate(rows): + expression = address_data + parent = row.parent() + if parent and expression.startswith(('+', '-')): + expression = parent.data(ADDR_COL, Qt.ItemDataRole.UserRole+1)+expression + if use_cache and expression in exp_cache: + address = exp_cache[expression] + elif expression.startswith(('+', '-')): # If parent has an empty address + address = expression + elif basic_math_exp.match(expression.replace(" ", "")): + try: + address = hex(eval(expression)) + except: + address = GDB_Engine.examine_expression(expression).address + exp_cache[expression] = address + else: + address = GDB_Engine.examine_expression(expression).address + exp_cache[expression] = address vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) - current_address = address_list[index] if isinstance(address_data, type_defs.PointerType): # The original base could be a symbol so we have to save it - # This little hack makes it possible to call examine_expressions only once - if current_address: + # This little hack avoids the unnecessary examine_expression call + # TODO: Consider implementing exp_cache inside libpince so we don't need this hack + if address: old_base = address_data.base_address # save the old base - address_data.base_address = current_address + address_data.base_address = address address = GDB_Engine.read_pointer(address_data) address_data.base_address = old_base # then set it back if address: - row.setText(ADDR_COL, f'P->{hex(address)}') + address = hex(address) + row.setText(ADDR_COL, f'P->{address}') else: row.setText(ADDR_COL, 'P->??') else: - # We already know that base address is an invalid symbol, skip the read_pointer call - address = None row.setText(ADDR_COL, 'P->??') else: - address = current_address row.setText(ADDR_COL, address or address_data) + address = "" if not address else address + row.setData(ADDR_COL, Qt.ItemDataRole.UserRole+1, address) value = GDB_Engine.read_memory(address, vt.value_index, vt.length, vt.zero_terminate, vt.value_repr, vt.endian, mem_handle=mem_handle) - if value is None: - value = "" - else: - value = str(value) + value = "" if value is None else str(value) row.setText(VALUE_COL, value) def resize_address_table(self): @@ -1038,6 +1031,7 @@ def pushButton_AddAddressManually_clicked(self): if manual_address_dialog.exec(): desc, address_expr, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() self.add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate, endian=endian) + self.update_address_table() def pushButton_MemoryView_clicked(self): self.memory_view_window.showMaximized() @@ -1264,6 +1258,7 @@ def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), value_index, length, value_repr=value_repr, endian=endian) + self.update_address_table() def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) @@ -1393,6 +1388,7 @@ def copy_to_address_table(self): if i % 3 == 0: value_index, value_repr, endian = row.data(Qt.ItemDataRole.UserRole) self.add_entry_to_addresstable("", row.text(), value_index, length, True, value_repr, endian) + self.update_address_table() def reset_scan(self): self.scan_mode = type_defs.SCAN_MODE.NEW @@ -1442,6 +1438,7 @@ def closeEvent(self, event): GDB_Engine.detach() app.closeAllWindows() + # Call update_address_table manually after this def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True, value_repr=type_defs.VALUE_REPR.UNSIGNED, endian=type_defs.ENDIANNESS.HOST): current_row = QTreeWidgetItem() @@ -1475,7 +1472,7 @@ def update_progress_bar(self): def address_table_loop(self): if update_table and not exiting: try: - self.update_address_table(use_cache=True) + self.update_address_table() except: traceback.print_exc() self.address_table_timer.start(table_update_interval) @@ -1604,6 +1601,7 @@ def treeWidget_AddressTable_edit_address(self): desc, address_expr, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() vt = type_defs.ValueType(value_index, length, zero_terminate, vt.value_repr, endian) self.change_address_table_entries(row, desc, address_expr, vt) + self.update_address_table() def treeWidget_AddressTable_edit_type(self): row = guiutils.get_current_item(self.treeWidget_AddressTable) @@ -1621,29 +1619,11 @@ def treeWidget_AddressTable_edit_type(self): # Changes the column values of the given row def change_address_table_entries(self, row, description=tr.NO_DESCRIPTION, address_expr="", vt=None): - if isinstance(address_expr, type_defs.PointerType): - address = GDB_Engine.read_pointer(address_expr) - address_text = f'P->{hex(address)}' if address != None else 'P->??' - else: - # Simple addresses first, examine_expression takes much longer time, especially for larger tables - try: - address = int(address_expr, 0) - address_text = hex(address) - except (ValueError, TypeError): - address = GDB_Engine.examine_expression(address_expr).address - address_text = address - value = '' - if address: - value = GDB_Engine.read_memory(address, vt.value_index, vt.length, vt.zero_terminate, vt.value_repr, - vt.endian) - assert isinstance(row, QTreeWidgetItem) row.setText(DESC_COL, description) row.setData(ADDR_COL, Qt.ItemDataRole.UserRole, address_expr) - row.setText(ADDR_COL, address_text) row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, vt) row.setText(TYPE_COL, vt.text()) - row.setText(VALUE_COL, "" if value is None else str(value)) # Returns the column values of the given row def read_address_table_entries(self, row, serialize=False): @@ -2943,6 +2923,7 @@ def exec_hex_view_add_address_dialog(self): if manual_address_dialog.exec(): desc, address, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() self.parent().add_entry_to_addresstable(desc, address, value_index, length, zero_terminate, endian=endian) + self.parent().update_address_table() def hex_view_scroll_up(self): self.verticalScrollBar_HexView.setValue(1) @@ -4505,6 +4486,7 @@ def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() self.parent().parent().add_entry_to_addresstable(tr.ACCESSED_BY.format(self.address), address, self.comboBox_ValueType.currentIndex(), 10) + self.parent().parent().update_address_table() def pushButton_Stop_clicked(self): if self.stopped: From b851d8feb2c7e9f9c248acdaf345df39a4d51f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 2 Dec 2023 21:06:10 +0300 Subject: [PATCH 276/487] Update address table on drop event --- GUI/CustomTreeWidgets/AddressTree.py | 27 +++++++++++++++++++++++++++ GUI/MainWindow.py | 3 ++- GUI/MainWindow.ui | 9 ++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 GUI/CustomTreeWidgets/AddressTree.py diff --git a/GUI/CustomTreeWidgets/AddressTree.py b/GUI/CustomTreeWidgets/AddressTree.py new file mode 100644 index 00000000..b7717476 --- /dev/null +++ b/GUI/CustomTreeWidgets/AddressTree.py @@ -0,0 +1,27 @@ +""" +Copyright (C) Korcan Karaokçu + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" +from PyQt6.QtWidgets import QTreeWidget + +class QAddressTree(QTreeWidget): + def __init__(self, parent=None): + super().__init__(parent) + + # TODO: If the auto-update is enabled, address table will be updated with a delay after a drop event + # This probably happens because of the QTimers. It's not critical but a fix would be nice + def dropEvent(self, event): + self.parent().parent().update_address_table() + super().dropEvent(event) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 54854527..15de07c3 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -18,7 +18,7 @@ def setupUi(self, MainWindow): self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.treeWidget_AddressTable = QtWidgets.QTreeWidget(parent=self.centralwidget) + self.treeWidget_AddressTable = QAddressTree(parent=self.centralwidget) self.treeWidget_AddressTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.treeWidget_AddressTable.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.DragDrop) self.treeWidget_AddressTable.setDefaultDropAction(QtCore.Qt.DropAction.MoveAction) @@ -317,3 +317,4 @@ def retranslateUi(self, MainWindow): self.label_2.setText(_translate("MainWindow", "Value Type:")) self.label_ScanScope.setText(_translate("MainWindow", "Scan Scope:")) self.label_3.setText(_translate("MainWindow", "Endianness:")) +from GUI.CustomTreeWidgets.AddressTree import QAddressTree diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index c17c900f..817600b0 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -16,7 +16,7 @@ - + QAbstractItemView::NoEditTriggers @@ -621,6 +621,13 @@ + + + QAddressTree + QTreeWidget +
GUI.CustomTreeWidgets.AddressTree
+
+
From fc8a346537fba48aed8cc153c926e56ae7a60bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 2 Dec 2023 21:51:23 +0300 Subject: [PATCH 277/487] Use requirements.txt for pip --- install_pince.sh | 3 +-- requirements.txt | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 requirements.txt diff --git a/install_pince.sh b/install_pince.sh index c8045f24..c753340e 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -123,7 +123,6 @@ PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-dev python3-venv pkg-config qt6-l10n-to PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" PKG_NAMES_ARCH="python-pip qt6-tools gdb lsb-release" # arch defaults to py3 nowadays -PKG_NAMES_PIP="pyqt6 pexpect distorm3 keystone-engine pygdbmi keyboard pygobject" INSTALL_COMMAND="install" @@ -196,7 +195,7 @@ fi . .venv/PINCE/bin/activate # shellcheck disable=SC2086 -pip3 install ${PKG_NAMES_PIP} || exit_on_error +pip3 install -r requirements.txt || exit_on_error install_libscanmem || exit_on_error diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..8f0c4ee2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +PyQt6==6.6.0 +PyQt6-Qt6==6.6.0 +pexpect==4.9.0 +distorm3==3.5.2 +keystone-engine==0.9.2 +pygdbmi==0.11.0.0 +keyboard==0.13.5 +pygobject==3.46.0 From e705f036b78b45ce6189b36d58e935d8d36af484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 3 Dec 2023 22:50:26 +0300 Subject: [PATCH 278/487] Fix checkBox_IsPointer.stateChanged logic --- PINCE.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 69f13a66..bca2b410 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1786,7 +1786,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.comboBox_Endianness.currentIndexChanged.connect(self.update_value_of_address) self.lineEdit_length.textChanged.connect(self.update_value_of_address) self.checkBox_zeroterminate.stateChanged.connect(self.update_value_of_address) - self.checkBox_IsPointer.stateChanged.connect(self.comboBox_ValueType_current_index_changed) + self.checkBox_IsPointer.stateChanged.connect(self.checkBox_IsPointer_state_changed) self.lineEdit_PtrStartAddress.textChanged.connect(self.update_value_of_address) self.lineEdit_address.textChanged.connect(self.update_value_of_address) self.addOffsetButton.clicked.connect(lambda: self.addOffsetLayout(True)) @@ -1886,6 +1886,10 @@ def comboBox_ValueType_current_index_changed(self): self.label_length.hide() self.lineEdit_length.hide() self.checkBox_zeroterminate.hide() + self.setFixedSize(self.layout().sizeHint()) + self.update_value_of_address() + + def checkBox_IsPointer_state_changed(self): if self.checkBox_IsPointer.isChecked(): self.lineEdit_address.setEnabled(False) self.lineEdit_PtrStartAddress.setText(self.lineEdit_address.text()) From 78559aa57b284f89ae01c4a7abae973b14cf6fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 3 Dec 2023 23:15:08 +0300 Subject: [PATCH 279/487] Fix object names for consistency --- GUI/AddAddressManuallyDialog.py | 82 +++++++++++++------------- GUI/AddAddressManuallyDialog.ui | 16 ++--- PINCE.py | 100 ++++++++++++++++---------------- 3 files changed, 99 insertions(+), 99 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index c2399f45..90ac012c 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -50,12 +50,12 @@ def setupUi(self, Dialog): self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") - self.addOffsetButton = QtWidgets.QPushButton(parent=self.widget_Pointer) - self.addOffsetButton.setObjectName("addOffsetButton") - self.horizontalLayout_5.addWidget(self.addOffsetButton) - self.removeOffsetButton = QtWidgets.QPushButton(parent=self.widget_Pointer) - self.removeOffsetButton.setObjectName("removeOffsetButton") - self.horizontalLayout_5.addWidget(self.removeOffsetButton) + self.pushButton_AddOffset = QtWidgets.QPushButton(parent=self.widget_Pointer) + self.pushButton_AddOffset.setObjectName("pushButton_AddOffset") + self.horizontalLayout_5.addWidget(self.pushButton_AddOffset) + self.pushButton_RemoveOffset = QtWidgets.QPushButton(parent=self.widget_Pointer) + self.pushButton_RemoveOffset.setObjectName("pushButton_RemoveOffset") + self.horizontalLayout_5.addWidget(self.pushButton_RemoveOffset) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_5) self.verticalLayout_4.addLayout(self.verticalLayout_Pointers) self.gridLayout.addWidget(self.widget_Pointer, 7, 0, 1, 1) @@ -84,10 +84,10 @@ def setupUi(self, Dialog): self.horizontalLayout_3.addWidget(self.label_5) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_3.addItem(spacerItem2) - self.checkBox_zeroterminate = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_zeroterminate.setChecked(True) - self.checkBox_zeroterminate.setObjectName("checkBox_zeroterminate") - self.horizontalLayout_3.addWidget(self.checkBox_zeroterminate) + self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(parent=Dialog) + self.checkBox_ZeroTerminate.setChecked(True) + self.checkBox_ZeroTerminate.setObjectName("checkBox_ZeroTerminate") + self.horizontalLayout_3.addWidget(self.checkBox_ZeroTerminate) self.verticalLayout_3.addLayout(self.horizontalLayout_3) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") @@ -102,20 +102,20 @@ def setupUi(self, Dialog): self.horizontalLayout_2.addWidget(self.comboBox_ValueType) spacerItem3 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem3) - self.label_length = QtWidgets.QLabel(parent=Dialog) - self.label_length.setObjectName("label_length") - self.horizontalLayout_2.addWidget(self.label_length) - self.lineEdit_length = QtWidgets.QLineEdit(parent=Dialog) + self.label_Length = QtWidgets.QLabel(parent=Dialog) + self.label_Length.setObjectName("label_Length") + self.horizontalLayout_2.addWidget(self.label_Length) + self.lineEdit_Length = QtWidgets.QLineEdit(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_length.sizePolicy().hasHeightForWidth()) - self.lineEdit_length.setSizePolicy(sizePolicy) - self.lineEdit_length.setMaximumSize(QtCore.QSize(60, 16777215)) - self.lineEdit_length.setInputMask("") - self.lineEdit_length.setText("10") - self.lineEdit_length.setObjectName("lineEdit_length") - self.horizontalLayout_2.addWidget(self.lineEdit_length) + sizePolicy.setHeightForWidth(self.lineEdit_Length.sizePolicy().hasHeightForWidth()) + self.lineEdit_Length.setSizePolicy(sizePolicy) + self.lineEdit_Length.setMaximumSize(QtCore.QSize(60, 16777215)) + self.lineEdit_Length.setInputMask("") + self.lineEdit_Length.setText("10") + self.lineEdit_Length.setObjectName("lineEdit_Length") + self.horizontalLayout_2.addWidget(self.lineEdit_Length) self.verticalLayout_3.addLayout(self.horizontalLayout_2) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") @@ -136,25 +136,25 @@ def setupUi(self, Dialog): self.verticalLayout_2.addWidget(self.label) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.lineEdit_address = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Address = QtWidgets.QLineEdit(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_address.sizePolicy().hasHeightForWidth()) - self.lineEdit_address.setSizePolicy(sizePolicy) - self.lineEdit_address.setMinimumSize(QtCore.QSize(100, 0)) - self.lineEdit_address.setText("") - self.lineEdit_address.setObjectName("lineEdit_address") - self.horizontalLayout.addWidget(self.lineEdit_address) + sizePolicy.setHeightForWidth(self.lineEdit_Address.sizePolicy().hasHeightForWidth()) + self.lineEdit_Address.setSizePolicy(sizePolicy) + self.lineEdit_Address.setMinimumSize(QtCore.QSize(100, 0)) + self.lineEdit_Address.setText("") + self.lineEdit_Address.setObjectName("lineEdit_Address") + self.horizontalLayout.addWidget(self.lineEdit_Address) self.label_2 = QtWidgets.QLabel(parent=Dialog) self.label_2.setText("=") self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) - self.label_valueofaddress = QtWidgets.QLabel(parent=Dialog) - self.label_valueofaddress.setText("") - self.label_valueofaddress.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) - self.label_valueofaddress.setObjectName("label_valueofaddress") - self.horizontalLayout.addWidget(self.label_valueofaddress) + self.label_Value = QtWidgets.QLabel(parent=Dialog) + self.label_Value.setText("") + self.label_Value.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) + self.label_Value.setObjectName("label_Value") + self.horizontalLayout.addWidget(self.label_Value) spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem5) self.verticalLayout_2.addLayout(self.horizontalLayout) @@ -164,10 +164,10 @@ def setupUi(self, Dialog): self.label_4 = QtWidgets.QLabel(parent=Dialog) self.label_4.setObjectName("label_4") self.verticalLayout.addWidget(self.label_4) - self.lineEdit_description = QtWidgets.QLineEdit(parent=Dialog) - self.lineEdit_description.setText("") - self.lineEdit_description.setObjectName("lineEdit_description") - self.verticalLayout.addWidget(self.lineEdit_description) + self.lineEdit_Description = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Description.setText("") + self.lineEdit_Description.setObjectName("lineEdit_Description") + self.verticalLayout.addWidget(self.lineEdit_Description) self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) self.retranslateUi(Dialog) @@ -180,12 +180,12 @@ def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Add Address Manually")) self.label_BaseAddress.setText(_translate("Dialog", "Base Address:")) - self.addOffsetButton.setText(_translate("Dialog", "Add Offset")) - self.removeOffsetButton.setText(_translate("Dialog", "Remove Offset")) + self.pushButton_AddOffset.setText(_translate("Dialog", "Add Offset")) + self.pushButton_RemoveOffset.setText(_translate("Dialog", "Remove Offset")) self.checkBox_IsPointer.setText(_translate("Dialog", "Pointer")) self.label_5.setText(_translate("Dialog", "Type:")) - self.checkBox_zeroterminate.setText(_translate("Dialog", "Zero-Terminated")) - self.label_length.setText(_translate("Dialog", "Length")) + self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) + self.label_Length.setText(_translate("Dialog", "Length")) self.label_3.setText(_translate("Dialog", "Endianness:")) self.label.setText(_translate("Dialog", "Address:")) self.label_4.setText(_translate("Dialog", "Description:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index ac4e9ad5..639cb1a6 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -98,14 +98,14 @@ - + Add Offset - + Remove Offset @@ -188,7 +188,7 @@
- + Zero-Terminated @@ -231,14 +231,14 @@ - + Length - + 0 @@ -302,7 +302,7 @@ - + 0 @@ -328,7 +328,7 @@ - + @@ -367,7 +367,7 @@ - + diff --git a/PINCE.py b/PINCE.py index bca2b410..85f4e2c6 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1744,60 +1744,60 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.adjustSize() self.setMinimumWidth(300) self.setFixedHeight(self.height()) - self.lineEdit_length.setValidator(QHexValidator(999, self)) + self.lineEdit_Length.setValidator(QHexValidator(999, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, index) guiutils.fill_endianness_combobox(self.comboBox_Endianness, endian) - self.lineEdit_description.setText(description) + self.lineEdit_Description.setText(description) self.offsetsList = [] if not isinstance(address, type_defs.PointerType): - self.lineEdit_address.setText(address) + self.lineEdit_Address.setText(address) self.widget_Pointer.hide() else: self.checkBox_IsPointer.setChecked(True) - self.lineEdit_address.setEnabled(False) + self.lineEdit_Address.setEnabled(False) self.lineEdit_PtrStartAddress.setText(address.get_base_address()) self.create_offsets_list(address) self.widget_Pointer.show() if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): - self.label_length.show() - self.lineEdit_length.show() + self.label_Length.show() + self.lineEdit_Length.show() try: length = str(length) except: length = "10" - self.lineEdit_length.setText(length) - self.checkBox_zeroterminate.show() - self.checkBox_zeroterminate.setChecked(zero_terminate) + self.lineEdit_Length.setText(length) + self.checkBox_ZeroTerminate.show() + self.checkBox_ZeroTerminate.setChecked(zero_terminate) elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: - self.label_length.show() - self.lineEdit_length.show() + self.label_Length.show() + self.lineEdit_Length.show() try: length = str(length) except: length = "10" - self.lineEdit_length.setText(length) - self.checkBox_zeroterminate.hide() + self.lineEdit_Length.setText(length) + self.checkBox_ZeroTerminate.hide() else: - self.label_length.hide() - self.lineEdit_length.hide() - self.checkBox_zeroterminate.hide() + self.label_Length.hide() + self.lineEdit_Length.hide() + self.checkBox_ZeroTerminate.hide() self.setFixedSize(self.layout().sizeHint()) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.comboBox_Endianness.currentIndexChanged.connect(self.update_value_of_address) - self.lineEdit_length.textChanged.connect(self.update_value_of_address) - self.checkBox_zeroterminate.stateChanged.connect(self.update_value_of_address) + self.lineEdit_Length.textChanged.connect(self.update_value_of_address) + self.checkBox_ZeroTerminate.stateChanged.connect(self.update_value_of_address) self.checkBox_IsPointer.stateChanged.connect(self.checkBox_IsPointer_state_changed) self.lineEdit_PtrStartAddress.textChanged.connect(self.update_value_of_address) - self.lineEdit_address.textChanged.connect(self.update_value_of_address) - self.addOffsetButton.clicked.connect(lambda: self.addOffsetLayout(True)) - self.removeOffsetButton.clicked.connect(self.removeOffsetLayout) - self.label_valueofaddress.contextMenuEvent = self.label_valueofaddress_context_menu_event + self.lineEdit_Address.textChanged.connect(self.update_value_of_address) + self.pushButton_AddOffset.clicked.connect(lambda: self.addOffsetLayout(True)) + self.pushButton_RemoveOffset.clicked.connect(self.removeOffsetLayout) + self.label_Value.contextMenuEvent = self.label_Value_context_menu_event self.update_value_of_address() - def label_valueofaddress_context_menu_event(self, event): + def label_Value_context_menu_event(self, event): menu = QMenu() refresh = menu.addAction(tr.REFRESH) - font_size = self.label_valueofaddress.font().pointSize() + font_size = self.label_Value.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) actions = { @@ -1853,53 +1853,53 @@ def update_value_of_address(self): address_text = hex(address) else: address_text = "??" - self.lineEdit_address.setText(address_text) + self.lineEdit_Address.setText(address_text) else: - address = GDB_Engine.examine_expression(self.lineEdit_address.text()).address + address = GDB_Engine.examine_expression(self.lineEdit_Address.text()).address if not address: - self.label_valueofaddress.setText("??") + self.label_Value.setText("??") return address_type = self.comboBox_ValueType.currentIndex() endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) if address_type == type_defs.VALUE_INDEX.INDEX_AOB: - length = self.lineEdit_length.text() + length = self.lineEdit_Length.text() value = GDB_Engine.read_memory(address, address_type, length, endian=endian) elif type_defs.VALUE_INDEX.is_string(address_type): - length = self.lineEdit_length.text() - is_zeroterminate = self.checkBox_zeroterminate.isChecked() + length = self.lineEdit_Length.text() + is_zeroterminate = self.checkBox_ZeroTerminate.isChecked() value = GDB_Engine.read_memory(address, address_type, length, is_zeroterminate, endian=endian) else: value = GDB_Engine.read_memory(address, address_type, endian=endian) - self.label_valueofaddress.setText("??" if value is None else str(value)) + self.label_Value.setText("??" if value is None else str(value)) def comboBox_ValueType_current_index_changed(self): if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): - self.label_length.show() - self.lineEdit_length.show() - self.checkBox_zeroterminate.show() + self.label_Length.show() + self.lineEdit_Length.show() + self.checkBox_ZeroTerminate.show() elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: - self.label_length.show() - self.lineEdit_length.show() - self.checkBox_zeroterminate.hide() + self.label_Length.show() + self.lineEdit_Length.show() + self.checkBox_ZeroTerminate.hide() else: - self.label_length.hide() - self.lineEdit_length.hide() - self.checkBox_zeroterminate.hide() + self.label_Length.hide() + self.lineEdit_Length.hide() + self.checkBox_ZeroTerminate.hide() self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() def checkBox_IsPointer_state_changed(self): if self.checkBox_IsPointer.isChecked(): - self.lineEdit_address.setEnabled(False) - self.lineEdit_PtrStartAddress.setText(self.lineEdit_address.text()) + self.lineEdit_Address.setEnabled(False) + self.lineEdit_PtrStartAddress.setText(self.lineEdit_Address.text()) if len(self.offsetsList) == 0: self.addOffsetLayout(False) self.widget_Pointer.show() else: - self.lineEdit_address.setText(self.lineEdit_PtrStartAddress.text()) + self.lineEdit_Address.setText(self.lineEdit_PtrStartAddress.text()) self.lineEdit_PtrStartAddress.setText("") - self.lineEdit_address.setEnabled(True) + self.lineEdit_Address.setEnabled(True) self.widget_Pointer.hide() self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() @@ -1908,8 +1908,8 @@ def reject(self): super(ManualAddressDialogForm, self).reject() def accept(self): - if self.label_length.isVisible(): - length = self.lineEdit_length.text() + if self.label_Length.isVisible(): + length = self.lineEdit_Length.text() try: length = int(length, 0) except: @@ -1921,14 +1921,14 @@ def accept(self): super(ManualAddressDialogForm, self).accept() def get_values(self): - description = self.lineEdit_description.text() - address = self.lineEdit_address.text() - length = self.lineEdit_length.text() + description = self.lineEdit_Description.text() + address = self.lineEdit_Address.text() + length = self.lineEdit_Length.text() try: length = int(length, 0) except: length = 0 - zero_terminate = self.checkBox_zeroterminate.isChecked() + zero_terminate = self.checkBox_ZeroTerminate.isChecked() value_index = self.comboBox_ValueType.currentIndex() endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) if self.checkBox_IsPointer.isChecked(): From e1af83c3a492c7612a793757800e3c6a014e60ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 4 Dec 2023 17:39:35 +0300 Subject: [PATCH 280/487] Remove redundant name custom --- .../AsciiModel.py | 2 +- .../HexModel.py | 0 GUI/{CustomLabels => Labels}/FlagRegisterLabel.py | 0 GUI/{CustomLabels => Labels}/RegisterLabel.py | 0 GUI/MainWindow.py | 2 +- GUI/MainWindow.ui | 2 +- GUI/MemoryViewerWindow.py | 10 +++++----- GUI/MemoryViewerWindow.ui | 8 ++++---- GUI/{CustomTableViews => TableViews}/AsciiView.py | 2 +- GUI/{CustomTableViews => TableViews}/HexView.py | 0 GUI/{CustomTreeWidgets => TreeWidgets}/AddressTree.py | 0 GUI/{CustomValidators => Validators}/HexValidator.py | 0 PINCE.py | 8 ++++---- 13 files changed, 17 insertions(+), 17 deletions(-) rename GUI/{CustomAbstractTableModels => AbstractTableModels}/AsciiModel.py (96%) rename GUI/{CustomAbstractTableModels => AbstractTableModels}/HexModel.py (100%) rename GUI/{CustomLabels => Labels}/FlagRegisterLabel.py (100%) rename GUI/{CustomLabels => Labels}/RegisterLabel.py (100%) rename GUI/{CustomTableViews => TableViews}/AsciiView.py (95%) rename GUI/{CustomTableViews => TableViews}/HexView.py (100%) rename GUI/{CustomTreeWidgets => TreeWidgets}/AddressTree.py (100%) rename GUI/{CustomValidators => Validators}/HexValidator.py (100%) diff --git a/GUI/CustomAbstractTableModels/AsciiModel.py b/GUI/AbstractTableModels/AsciiModel.py similarity index 96% rename from GUI/CustomAbstractTableModels/AsciiModel.py rename to GUI/AbstractTableModels/AsciiModel.py index 9dde25bd..fc860ad0 100644 --- a/GUI/CustomAbstractTableModels/AsciiModel.py +++ b/GUI/AbstractTableModels/AsciiModel.py @@ -16,7 +16,7 @@ """ from PyQt6.QtCore import QVariant, Qt from PyQt6.QtGui import QColor, QColorConstants -from GUI.CustomAbstractTableModels.HexModel import QHexModel +from GUI.AbstractTableModels.HexModel import QHexModel from libpince import SysUtils, GDB_Engine diff --git a/GUI/CustomAbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py similarity index 100% rename from GUI/CustomAbstractTableModels/HexModel.py rename to GUI/AbstractTableModels/HexModel.py diff --git a/GUI/CustomLabels/FlagRegisterLabel.py b/GUI/Labels/FlagRegisterLabel.py similarity index 100% rename from GUI/CustomLabels/FlagRegisterLabel.py rename to GUI/Labels/FlagRegisterLabel.py diff --git a/GUI/CustomLabels/RegisterLabel.py b/GUI/Labels/RegisterLabel.py similarity index 100% rename from GUI/CustomLabels/RegisterLabel.py rename to GUI/Labels/RegisterLabel.py diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 15de07c3..f141bfaa 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -317,4 +317,4 @@ def retranslateUi(self, MainWindow): self.label_2.setText(_translate("MainWindow", "Value Type:")) self.label_ScanScope.setText(_translate("MainWindow", "Scan Scope:")) self.label_3.setText(_translate("MainWindow", "Endianness:")) -from GUI.CustomTreeWidgets.AddressTree import QAddressTree +from GUI.TreeWidgets.AddressTree import QAddressTree diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 817600b0..dd297348 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -625,7 +625,7 @@ QAddressTree QTreeWidget -
GUI.CustomTreeWidgets.AddressTree
+
GUI.TreeWidgets.AddressTree
diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 410db446..412cb2b3 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MemoryViewerWindow.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -912,7 +912,7 @@ def retranslateUi(self, MainWindow_MemoryView): self.actionReferenced_Calls.setText(_translate("MainWindow_MemoryView", "Referenced &Calls")) self.actionToggle_Attach.setText(_translate("MainWindow_MemoryView", "To&ggle Attach")) self.actionRestore_Instructions.setText(_translate("MainWindow_MemoryView", "Restore Instructions")) -from GUI.CustomLabels.FlagRegisterLabel import QFlagRegisterLabel -from GUI.CustomLabels.RegisterLabel import QRegisterLabel -from GUI.CustomTableViews.AsciiView import QAsciiView -from GUI.CustomTableViews.HexView import QHexView +from GUI.Labels.FlagRegisterLabel import QFlagRegisterLabel +from GUI.Labels.RegisterLabel import QRegisterLabel +from GUI.TableViews.AsciiView import QAsciiView +from GUI.TableViews.HexView import QHexView diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 1334b6ce..7c788a15 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -1737,22 +1737,22 @@ QRegisterLabel QLabel -
GUI.CustomLabels.RegisterLabel
+
GUI.Labels.RegisterLabel
QFlagRegisterLabel QLabel -
GUI.CustomLabels.FlagRegisterLabel
+
GUI.Labels.FlagRegisterLabel
QHexView QTableView -
GUI.CustomTableViews.HexView
+
GUI.TableViews.HexView
QAsciiView QTableView -
GUI.CustomTableViews.AsciiView
+
GUI.TableViews.AsciiView
diff --git a/GUI/CustomTableViews/AsciiView.py b/GUI/TableViews/AsciiView.py similarity index 95% rename from GUI/CustomTableViews/AsciiView.py rename to GUI/TableViews/AsciiView.py index 120c5914..cf2f6a4a 100644 --- a/GUI/CustomTableViews/AsciiView.py +++ b/GUI/TableViews/AsciiView.py @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from GUI.CustomTableViews.HexView import QHexView +from GUI.TableViews.HexView import QHexView class QAsciiView(QHexView): diff --git a/GUI/CustomTableViews/HexView.py b/GUI/TableViews/HexView.py similarity index 100% rename from GUI/CustomTableViews/HexView.py rename to GUI/TableViews/HexView.py diff --git a/GUI/CustomTreeWidgets/AddressTree.py b/GUI/TreeWidgets/AddressTree.py similarity index 100% rename from GUI/CustomTreeWidgets/AddressTree.py rename to GUI/TreeWidgets/AddressTree.py diff --git a/GUI/CustomValidators/HexValidator.py b/GUI/Validators/HexValidator.py similarity index 100% rename from GUI/CustomValidators/HexValidator.py rename to GUI/Validators/HexValidator.py diff --git a/PINCE.py b/PINCE.py index 85f4e2c6..35abadc5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -56,7 +56,7 @@ from GUI.ConsoleWidget import Ui_Form as ConsoleWidget from GUI.AboutWidget import Ui_TabWidget as AboutWidget -# If you are going to change the name "Ui_MainWindow_MemoryView", review GUI/CustomLabels/RegisterLabel.py as well +# If you are going to change the name "Ui_MainWindow_MemoryView", review GUI/Labels/RegisterLabel.py as well from GUI.MemoryViewerWindow import Ui_MainWindow_MemoryView as MemoryViewWindow from GUI.BookmarkWidget import Ui_Form as BookmarkWidget from GUI.FloatRegisterWidget import Ui_TabWidget as FloatRegisterWidget @@ -80,9 +80,9 @@ from GUI.ExamineReferrersWidget import Ui_Form as ExamineReferrersWidget from GUI.RestoreInstructionsWidget import Ui_Form as RestoreInstructionsWidget -from GUI.CustomAbstractTableModels.HexModel import QHexModel -from GUI.CustomAbstractTableModels.AsciiModel import QAsciiModel -from GUI.CustomValidators.HexValidator import QHexValidator +from GUI.AbstractTableModels.HexModel import QHexModel +from GUI.AbstractTableModels.AsciiModel import QAsciiModel +from GUI.Validators.HexValidator import QHexValidator from keyboard import add_hotkey, remove_hotkey from operator import add as opAdd, sub as opSub From 7f22fea6e95ecb1559945491b9727d3b8d0c6bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 5 Dec 2023 16:37:04 +0300 Subject: [PATCH 281/487] Detach before emergency quit --- PINCE.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PINCE.py b/PINCE.py index 35abadc5..b5aaa95d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -347,9 +347,11 @@ def signal_handler(signal, frame): try: text = input("\nNo GDB command to cancel, quit PINCE? (y/n)") if text.lower().startswith("y"): + GDB_Engine.detach() quit() except RuntimeError: print() # Prints a newline so the terminal looks nicer when we quit + GDB_Engine.detach() quit() From a0f99b57c7e1da8f19ff7ef28017642a845cf18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 7 Dec 2023 11:54:25 +0300 Subject: [PATCH 282/487] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8734959e..f3418bf7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ TODO: Include build status with the title when test coverage increases and Travis is maintained [![Build Status](https://travis-ci.org/korcankaraokcu/PINCE.svg?branch=master)](https://travis-ci.org/korcankaraokcu/PINCE) --> -PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB), focused on games. However, it can be used for any reverse-engineering related stuff. PINCE is an abbreviation for "PINCE is not Cheat Engine". PINCE is in development right now, read [Features](#features) part of the project to see what is done and [Roadmap](#current-roadmap) part to see what is currently planned. Also, please read [Wiki Page](https://github.com/korcankaraokcu/PINCE/wiki) of the project to understand how PINCE works. +PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB), focused on games. However, it can be used for any reverse-engineering related stuff. PINCE is an abbreviation for "PINCE is not Cheat Engine". PINCE is in development right now, read [Features](#features) part of the project to see what is done and [Roadmap](CONTRIBUTING.md#roadmap) part to see what is currently planned. Also, please read [Wiki Page](https://github.com/korcankaraokcu/PINCE/wiki) of the project to understand how PINCE works. ### [Feel free to join our discord server!](https://discord.gg/jVt3BzTSpz) From 6f4431a451e34c2a810a447613978ef6db6cc1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 12 Dec 2023 21:02:48 +0300 Subject: [PATCH 283/487] Implement groups --- PINCE.py | 35 +++++++++++++++++++++++++++++++---- tr/tr.py | 3 +++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index b5aaa95d..5fde28c7 100755 --- a/PINCE.py +++ b/PINCE.py @@ -685,8 +685,6 @@ def nextscan_hotkey_pressed(self, index): self.pushButton_NextScan.clicked.emit() def treeWidget_AddressTable_context_menu_event(self, event): - if self.treeWidget_AddressTable.topLevelItemCount() == 0: - return current_row = guiutils.get_current_item(self.treeWidget_AddressTable) header = self.treeWidget_AddressTable.headerItem() menu = QMenu() @@ -720,10 +718,13 @@ def treeWidget_AddressTable_context_menu_event(self, event): what_writes = menu.addAction(tr.WHAT_WRITES) what_reads = menu.addAction(tr.WHAT_READS) what_accesses = menu.addAction(tr.WHAT_ACCESSES) + menu.addSeparator() + add_group = menu.addAction(tr.ADD_GROUP) + create_group = menu.addAction(tr.CREATE_GROUP) if current_row is None: deletion_list = [edit_menu.menuAction(), show_hex, show_dec, show_unsigned, show_signed, toggle_record, freeze_menu.menuAction(), browse_region, disassemble, what_writes, what_reads, - what_accesses] + what_accesses, add_group] guiutils.delete_menu_entries(menu, deletion_list) else: value_type = current_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) @@ -767,7 +768,9 @@ def treeWidget_AddressTable_context_menu_event(self, event): delete_record: self.delete_selected_records, what_writes: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.WRITE_ONLY), what_reads: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.READ_ONLY), - what_accesses: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.BOTH) + what_accesses: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.BOTH), + add_group: self.group_records, + create_group: self.create_group } try: actions[action]() @@ -928,6 +931,30 @@ def paste_records(self, insert_after=None, insert_inside=False): self.insert_records(records, parent, parent.indexOfChild(insert_row) + insert_after) self.update_address_table() + def group_records(self): + selected_items = self.treeWidget_AddressTable.selectedItems() + if self.create_group(): + item_count = self.treeWidget_AddressTable.topLevelItemCount() + last_item = self.treeWidget_AddressTable.topLevelItem(item_count - 1) + for item in selected_items: + parent = item.parent() + if parent: + parent.removeChild(item) + else: + index = self.treeWidget_AddressTable.indexOfTopLevelItem(item) + self.treeWidget_AddressTable.takeTopLevelItem(index) + last_item.addChild(item) + self.treeWidget_AddressTable.setCurrentItem(last_item) + last_item.setExpanded(True) + + def create_group(self): + dialog = InputDialogForm(item_list=[(tr.ENTER_DESCRIPTION, tr.GROUP)]) + if dialog.exec(): + desc = dialog.get_values() + self.add_entry_to_addresstable(desc, "0x0", type_defs.VALUE_INDEX.INDEX_INT8) + return True + return False + def delete_selected_records(self): root = self.treeWidget_AddressTable.invisibleRootItem() for item in self.treeWidget_AddressTable.selectedItems(): diff --git a/tr/tr.py b/tr/tr.py index 0117a0fa..a2968676 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -69,6 +69,9 @@ def translate(): WHAT_WRITES = QT_TR_NOOP("Find out what writes to this address") WHAT_READS = QT_TR_NOOP("Find out what reads this address") WHAT_ACCESSES = QT_TR_NOOP("Find out what accesses this address") + ADD_GROUP = QT_TR_NOOP("Add to a new group") + CREATE_GROUP = QT_TR_NOOP("Create a new group") + GROUP = QT_TR_NOOP("Group") INVALID_CLIPBOARD = QT_TR_NOOP("Invalid clipboard content") NEW_SCAN = QT_TR_NOOP("New Scan") MATCH_COUNT_LIMITED = QT_TR_NOOP("Match count: {} ({} shown)") From faf0eca92f55236b290cc887f8309da60508284f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 14 Dec 2023 20:16:01 +0300 Subject: [PATCH 284/487] Shorten context menu of MainWindow --- PINCE.py | 89 +++++++++++++++++------------------------------- i18n/ts/it_IT.ts | 29 +++++++--------- i18n/ts/zh_CN.ts | 53 +++++++++++++--------------- tr/tr.py | 16 ++++----- 4 files changed, 74 insertions(+), 113 deletions(-) diff --git a/PINCE.py b/PINCE.py index 5fde28c7..7bf9e56b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -518,7 +518,7 @@ def __init__(self): self.pushButton_MemoryView.clicked.connect(self.pushButton_MemoryView_clicked) self.pushButton_RefreshAdressTable.clicked.connect(lambda: self.update_address_table(use_cache=False)) self.pushButton_CopyToAddressTable.clicked.connect(self.copy_to_address_table) - self.pushButton_CleanAddressTable.clicked.connect(self.delete_address_table_contents) + self.pushButton_CleanAddressTable.clicked.connect(self.clear_address_table) self.tableWidget_valuesearchtable.cellDoubleClicked.connect( self.tableWidget_valuesearchtable_cell_double_clicked) self.treeWidget_AddressTable.itemClicked.connect(self.treeWidget_AddressTable_item_clicked) @@ -688,6 +688,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): current_row = guiutils.get_current_item(self.treeWidget_AddressTable) header = self.treeWidget_AddressTable.headerItem() menu = QMenu() + delete_record = menu.addAction(f"{tr.DELETE}[Del]") edit_menu = menu.addMenu(tr.EDIT) edit_desc = edit_menu.addAction(f"{header.text(DESC_COL)}[Ctrl+Enter]") edit_address = edit_menu.addAction(f"{header.text(ADDR_COL)}[Ctrl+Alt+Enter]") @@ -697,7 +698,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): show_dec = menu.addAction(tr.SHOW_DEC) show_unsigned = menu.addAction(tr.SHOW_UNSIGNED) show_signed = menu.addAction(tr.SHOW_SIGNED) - toggle_record = menu.addAction(f"{tr.TOGGLE_RECORDS}[Space]") + toggle_record = menu.addAction(f"{tr.TOGGLE}[Space]") freeze_menu = menu.addMenu(tr.FREEZE) freeze_default = freeze_menu.addAction(tr.DEFAULT) freeze_inc = freeze_menu.addAction(tr.INCREMENTAL) @@ -706,25 +707,21 @@ def treeWidget_AddressTable_context_menu_event(self, event): browse_region = menu.addAction(f"{tr.BROWSE_MEMORY_REGION}[Ctrl+B]") disassemble = menu.addAction(f"{tr.DISASSEMBLE_ADDRESS}[Ctrl+D]") menu.addSeparator() - cut_record = menu.addAction(f"{tr.CUT_RECORDS}[Ctrl+X]") - copy_record = menu.addAction(f"{tr.COPY_RECORDS}[Ctrl+C]") - cut_record_recursively = menu.addAction(f"{tr.CUT_RECORDS_RECURSIVE}[X]") - copy_record_recursively = menu.addAction(f"{tr.COPY_RECORDS_RECURSIVE}[C]") - paste_record_before = menu.addAction(f"{tr.PASTE_BEFORE}[Ctrl+V]") - paste_record_after = menu.addAction(f"{tr.PASTE_AFTER}[V]") - paste_record_inside = menu.addAction(f"{tr.PASTE_INSIDE}[I]") - delete_record = menu.addAction(f"{tr.DELETE_RECORDS}[Del]") - menu.addSeparator() what_writes = menu.addAction(tr.WHAT_WRITES) what_reads = menu.addAction(tr.WHAT_READS) what_accesses = menu.addAction(tr.WHAT_ACCESSES) menu.addSeparator() + cut_record = menu.addAction(f"{tr.CUT}[Ctrl+X]") + copy_record = menu.addAction(f"{tr.COPY}[Ctrl+C]") + paste_record = menu.addAction(f"{tr.PASTE}[Ctrl+V]") + paste_inside = menu.addAction(f"{tr.PASTE_INSIDE}[V]") + menu.addSeparator() add_group = menu.addAction(tr.ADD_GROUP) create_group = menu.addAction(tr.CREATE_GROUP) if current_row is None: deletion_list = [edit_menu.menuAction(), show_hex, show_dec, show_unsigned, show_signed, toggle_record, freeze_menu.menuAction(), browse_region, disassemble, what_writes, what_reads, - what_accesses, add_group] + what_accesses, cut_record, copy_record, paste_inside, delete_record, add_group] guiutils.delete_menu_entries(menu, deletion_list) else: value_type = current_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) @@ -744,6 +741,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) actions = { + delete_record: self.delete_records, edit_desc: self.treeWidget_AddressTable_edit_desc, edit_address: self.treeWidget_AddressTable_edit_address, edit_type: self.treeWidget_AddressTable_edit_type, @@ -752,23 +750,19 @@ def treeWidget_AddressTable_context_menu_event(self, event): show_dec: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.UNSIGNED), show_unsigned: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.UNSIGNED), show_signed: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.SIGNED), - toggle_record: self.toggle_selected_records, + toggle_record: self.toggle_records, freeze_default: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.DEFAULT), freeze_inc: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.INCREMENT), freeze_dec: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.DECREMENT), browse_region: self.browse_region_for_selected_row, disassemble: self.disassemble_selected_row, - cut_record: self.cut_selected_records, - copy_record: self.copy_selected_records, - cut_record_recursively: self.cut_selected_records_recursively, - copy_record_recursively: self.copy_selected_records_recursively, - paste_record_before: lambda: self.paste_records(insert_after=False), - paste_record_after: lambda: self.paste_records(insert_after=True), - paste_record_inside: lambda: self.paste_records(insert_inside=True), - delete_record: self.delete_selected_records, what_writes: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.WRITE_ONLY), what_reads: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.READ_ONLY), what_accesses: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.BOTH), + cut_record: self.cut_records, + copy_record: self.copy_records, + paste_record: self.paste_records, + paste_inside: lambda: self.paste_records(True), add_group: self.group_records, create_group: self.create_group } @@ -832,7 +826,7 @@ def change_freeze_type(self, freeze_type): row.setText(FROZEN_COL, "▼") row.setForeground(FROZEN_COL, QBrush(QColor(255, 0, 0))) - def toggle_selected_records(self): + def toggle_records(self): row = guiutils.get_current_item(self.treeWidget_AddressTable) if row: check_state = row.checkState(FROZEN_COL) @@ -841,22 +835,11 @@ def toggle_selected_records(self): row.setCheckState(FROZEN_COL, new_check_state) self.treeWidget_AddressTable_item_clicked(row, FROZEN_COL) - def cut_selected_records(self): - # Flat cut, does not preserve structure - self.copy_selected_records() - self.delete_selected_records() + def cut_records(self): + self.copy_records() + self.delete_records() - def copy_selected_records(self): - # Flat copy, does not preserve structure - app.clipboard().setText(repr([self.read_address_table_entries(selected_row, True) + ((),) for selected_row in - self.treeWidget_AddressTable.selectedItems()])) - # each element in the list has no children - - def cut_selected_records_recursively(self): - self.copy_selected_records_recursively() - self.delete_selected_records() - - def copy_selected_records_recursively(self): + def copy_records(self): # Recursive copy items = self.treeWidget_AddressTable.selectedItems() @@ -912,8 +895,9 @@ def insert_records(self, records, parent_row, insert_index): rows.append(row) parent_row.insertChildren(insert_index, rows) + parent_row.setExpanded(True) - def paste_records(self, insert_after=None, insert_inside=False): + def paste_records(self, insert_inside=False): try: records = ast.literal_eval(app.clipboard().text()) except (SyntaxError, ValueError): @@ -928,7 +912,7 @@ def paste_records(self, insert_after=None, insert_inside=False): self.insert_records(records, insert_row, 0) else: parent = insert_row.parent() or root - self.insert_records(records, parent, parent.indexOfChild(insert_row) + insert_after) + self.insert_records(records, parent, parent.indexOfChild(insert_row) + 1) self.update_address_table() def group_records(self): @@ -955,29 +939,23 @@ def create_group(self): return True return False - def delete_selected_records(self): + def delete_records(self): root = self.treeWidget_AddressTable.invisibleRootItem() for item in self.treeWidget_AddressTable.selectedItems(): (item.parent() or root).removeChild(item) def treeWidget_AddressTable_key_press_event(self, event): actions = type_defs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_selected_records), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), self.browse_region_for_selected_row), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), lambda: self.update_address_table(use_cache=False)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_selected_records), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_X), self.cut_selected_records), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_selected_records), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_X), self.cut_selected_records_recursively), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_C), self.copy_selected_records_recursively), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), - lambda: self.paste_records(insert_after=False)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), - lambda: self.paste_records(insert_after=True)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_I), - lambda: self.paste_records(insert_inside=True)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_X), self.cut_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), self.paste_records), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), lambda: self.paste_records(True)), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_value), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), @@ -1328,10 +1306,7 @@ def pushButton_Open_clicked(self): file_paths = QFileDialog.getOpenFileNames(self, tr.OPEN_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_paths: return - if self.treeWidget_AddressTable.topLevelItemCount() > 0: - if InputDialogForm(item_list=[(tr.CLEAR_TABLE,)]).exec(): - self.treeWidget_AddressTable.clear() - + self.clear_address_table() for file_path in file_paths: content = SysUtils.load_file(file_path) if content is None: @@ -1402,7 +1377,7 @@ def on_new_process(self): # stop flashing attach button, timer will stop automatically on false value self.flashAttachButton = False - def delete_address_table_contents(self): + def clear_address_table(self): if self.treeWidget_AddressTable.topLevelItemCount() == 0: return confirm_dialog = InputDialogForm(item_list=[(tr.CLEAR_TABLE,)]) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 9a35bec9..9a3bbf1a 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1442,7 +1442,7 @@ To change the current GDB path, check Settings->Debug - Toggle selected records + Toggle @@ -1477,57 +1477,57 @@ To change the current GDB path, check Settings->Debug - Cut selected records + Delete - Copy selected records + Cut - Cut selected records (recursive) + Copy - Copy selected records (recursive) + Paste - Paste selected records before + Paste inside - Paste selected records after + Find out what writes to this address - Paste selected records inside + Find out what reads this address - Delete selected records + Find out what accesses this address - Find out what writes to this address + Add to a new group - Find out what reads this address + Create a new group - Find out what accesses this address + Group @@ -2181,11 +2181,6 @@ You can use the assigned variable from the GDB Console Add new entry - - - Delete - - Enter the new value of register {} diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 14691992..fb80ca44 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1446,8 +1446,8 @@ To change the current GDB path, check Settings->Debug - Toggle selected records - 切换选定的记录 + Toggle + @@ -1481,58 +1481,58 @@ To change the current GDB path, check Settings->Debug - Cut selected records - 剪切选定的记录 + Delete + 删除 - Copy selected records - 复制选定的记录 + Cut + - Cut selected records (recursive) - 剪切选定的记录(递归) + Copy + - Copy selected records (recursive) - 复制选定的记录(递归) + Paste + - Paste selected records before - 在之前粘贴选定的记录 + Paste inside + - Paste selected records after - 在之后粘贴选定的记录 + Find out what writes to this address + 找出是什么写入了这个地址 - Paste selected records inside - 在之中粘贴选定的记录 + Find out what reads this address + 找出是什么读取了这个地址 - Delete selected records - 删除选定的记录 + Find out what accesses this address + 找出是什么访问了这个地址 - Find out what writes to this address - 找出是什么写入了这个地址 + Add to a new group + - Find out what reads this address - 找出是什么读取了这个地址 + Create a new group + - Find out what accesses this address - 找出是什么访问了这个地址 + Group + @@ -2236,11 +2236,6 @@ $28 是分配的便利变量 Add new entry 添加新条目 - - - Delete - 删除 - Enter the new value of register {} diff --git a/tr/tr.py b/tr/tr.py index a2968676..428c965e 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -51,21 +51,18 @@ def translate(): SHOW_DEC = QT_TR_NOOP("Show as decimal") SHOW_UNSIGNED = QT_TR_NOOP("Show as unsigned") SHOW_SIGNED = QT_TR_NOOP("Show as signed") - TOGGLE_RECORDS = QT_TR_NOOP("Toggle selected records") + TOGGLE = QT_TR_NOOP("Toggle") FREEZE = QT_TR_NOOP("Freeze") DEFAULT = QT_TR_NOOP("Default") INCREMENTAL = QT_TR_NOOP("Incremental") DECREMENTAL = QT_TR_NOOP("Decremental") BROWSE_MEMORY_REGION = QT_TR_NOOP("Browse this memory region") DISASSEMBLE_ADDRESS = QT_TR_NOOP("Disassemble this address") - CUT_RECORDS = QT_TR_NOOP("Cut selected records") - COPY_RECORDS = QT_TR_NOOP("Copy selected records") - CUT_RECORDS_RECURSIVE = QT_TR_NOOP("Cut selected records (recursive)") - COPY_RECORDS_RECURSIVE = QT_TR_NOOP("Copy selected records (recursive)") - PASTE_BEFORE = QT_TR_NOOP("Paste selected records before") - PASTE_AFTER = QT_TR_NOOP("Paste selected records after") - PASTE_INSIDE = QT_TR_NOOP("Paste selected records inside") - DELETE_RECORDS = QT_TR_NOOP("Delete selected records") + DELETE = QT_TR_NOOP("Delete") + CUT = QT_TR_NOOP("Cut") + COPY = QT_TR_NOOP("Copy") + PASTE = QT_TR_NOOP("Paste") + PASTE_INSIDE = QT_TR_NOOP("Paste inside") WHAT_WRITES = QT_TR_NOOP("Find out what writes to this address") WHAT_READS = QT_TR_NOOP("Find out what reads this address") WHAT_ACCESSES = QT_TR_NOOP("Find out what accesses this address") @@ -250,7 +247,6 @@ def translate(): INVALID_EXPRESSION = QT_TR_NOOP("Invalid expression or address") INVALID_ENTRY = QT_TR_NOOP("Invalid entries detected, refreshing the page") ADD_ENTRY = QT_TR_NOOP("Add new entry") - DELETE = QT_TR_NOOP("Delete") ENTER_REGISTER_VALUE = QT_TR_NOOP("Enter the new value of register {}") ENTER_FLAG_VALUE = QT_TR_NOOP("Enter the new value of flag {}") RESTORE_INSTRUCTION = QT_TR_NOOP("Restore this instruction") From 9f91060c827cc71592e48b4f1a5e449f1fd1da69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 15 Dec 2023 15:22:23 +0300 Subject: [PATCH 285/487] Move length and ZT to their own widget --- GUI/AddAddressManuallyDialog.py | 157 ++++++++-------- GUI/AddAddressManuallyDialog.ui | 316 +++++++++++++++++--------------- PINCE.py | 19 +- 3 files changed, 250 insertions(+), 242 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 90ac012c..10899d58 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -22,6 +22,63 @@ def setupUi(self, Dialog): Dialog.setMaximumSize(QtCore.QSize(224, 16777215)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_5 = QtWidgets.QLabel(parent=Dialog) + self.label_5.setObjectName("label_5") + self.horizontalLayout_3.addWidget(self.label_5) + self.comboBox_ValueType = QtWidgets.QComboBox(parent=Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.comboBox_ValueType.sizePolicy().hasHeightForWidth()) + self.comboBox_ValueType.setSizePolicy(sizePolicy) + self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) + self.comboBox_ValueType.setObjectName("comboBox_ValueType") + self.horizontalLayout_3.addWidget(self.comboBox_ValueType) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_3.addItem(spacerItem) + self.verticalLayout_3.addLayout(self.horizontalLayout_3) + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.label_3 = QtWidgets.QLabel(parent=Dialog) + self.label_3.setObjectName("label_3") + self.horizontalLayout_6.addWidget(self.label_3) + self.comboBox_Endianness = QtWidgets.QComboBox(parent=Dialog) + self.comboBox_Endianness.setObjectName("comboBox_Endianness") + self.horizontalLayout_6.addWidget(self.comboBox_Endianness) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_6.addItem(spacerItem1) + self.verticalLayout_3.addLayout(self.horizontalLayout_6) + self.widget_Length = QtWidgets.QWidget(parent=Dialog) + self.widget_Length.setObjectName("widget_Length") + self.horizontalLayout_Length = QtWidgets.QHBoxLayout(self.widget_Length) + self.horizontalLayout_Length.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_Length.setObjectName("horizontalLayout_Length") + self.label_Length = QtWidgets.QLabel(parent=self.widget_Length) + self.label_Length.setObjectName("label_Length") + self.horizontalLayout_Length.addWidget(self.label_Length) + self.lineEdit_Length = QtWidgets.QLineEdit(parent=self.widget_Length) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_Length.sizePolicy().hasHeightForWidth()) + self.lineEdit_Length.setSizePolicy(sizePolicy) + self.lineEdit_Length.setMaximumSize(QtCore.QSize(60, 16777215)) + self.lineEdit_Length.setInputMask("") + self.lineEdit_Length.setText("10") + self.lineEdit_Length.setObjectName("lineEdit_Length") + self.horizontalLayout_Length.addWidget(self.lineEdit_Length) + self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(parent=self.widget_Length) + self.checkBox_ZeroTerminate.setChecked(True) + self.checkBox_ZeroTerminate.setObjectName("checkBox_ZeroTerminate") + self.horizontalLayout_Length.addWidget(self.checkBox_ZeroTerminate) + spacerItem2 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_Length.addItem(spacerItem2) + self.verticalLayout_3.addWidget(self.widget_Length) + self.gridLayout.addLayout(self.verticalLayout_3, 2, 0, 1, 1) self.widget_Pointer = QtWidgets.QWidget(parent=Dialog) self.widget_Pointer.setEnabled(True) self.widget_Pointer.setMinimumSize(QtCore.QSize(0, 0)) @@ -45,8 +102,8 @@ def setupUi(self, Dialog): self.lineEdit_PtrStartAddress.setSizePolicy(sizePolicy) self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem3) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") @@ -59,6 +116,16 @@ def setupUi(self, Dialog): self.verticalLayout_Pointers.addLayout(self.horizontalLayout_5) self.verticalLayout_4.addLayout(self.verticalLayout_Pointers) self.gridLayout.addWidget(self.widget_Pointer, 7, 0, 1, 1) + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.label_4 = QtWidgets.QLabel(parent=Dialog) + self.label_4.setObjectName("label_4") + self.verticalLayout.addWidget(self.label_4) + self.lineEdit_Description = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Description.setText("") + self.lineEdit_Description.setObjectName("lineEdit_Description") + self.verticalLayout.addWidget(self.lineEdit_Description) + self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -70,65 +137,8 @@ def setupUi(self, Dialog): self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) - self.checkBox_IsPointer = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") - self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.gridLayout.addItem(spacerItem1, 8, 0, 1, 1) - self.verticalLayout_3 = QtWidgets.QVBoxLayout() - self.verticalLayout_3.setObjectName("verticalLayout_3") - self.horizontalLayout_3 = QtWidgets.QHBoxLayout() - self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.label_5 = QtWidgets.QLabel(parent=Dialog) - self.label_5.setObjectName("label_5") - self.horizontalLayout_3.addWidget(self.label_5) - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_3.addItem(spacerItem2) - self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_ZeroTerminate.setChecked(True) - self.checkBox_ZeroTerminate.setObjectName("checkBox_ZeroTerminate") - self.horizontalLayout_3.addWidget(self.checkBox_ZeroTerminate) - self.verticalLayout_3.addLayout(self.horizontalLayout_3) - self.horizontalLayout_2 = QtWidgets.QHBoxLayout() - self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.comboBox_ValueType = QtWidgets.QComboBox(parent=Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBox_ValueType.sizePolicy().hasHeightForWidth()) - self.comboBox_ValueType.setSizePolicy(sizePolicy) - self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) - self.comboBox_ValueType.setObjectName("comboBox_ValueType") - self.horizontalLayout_2.addWidget(self.comboBox_ValueType) - spacerItem3 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_2.addItem(spacerItem3) - self.label_Length = QtWidgets.QLabel(parent=Dialog) - self.label_Length.setObjectName("label_Length") - self.horizontalLayout_2.addWidget(self.label_Length) - self.lineEdit_Length = QtWidgets.QLineEdit(parent=Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_Length.sizePolicy().hasHeightForWidth()) - self.lineEdit_Length.setSizePolicy(sizePolicy) - self.lineEdit_Length.setMaximumSize(QtCore.QSize(60, 16777215)) - self.lineEdit_Length.setInputMask("") - self.lineEdit_Length.setText("10") - self.lineEdit_Length.setObjectName("lineEdit_Length") - self.horizontalLayout_2.addWidget(self.lineEdit_Length) - self.verticalLayout_3.addLayout(self.horizontalLayout_2) - self.horizontalLayout_6 = QtWidgets.QHBoxLayout() - self.horizontalLayout_6.setObjectName("horizontalLayout_6") - self.label_3 = QtWidgets.QLabel(parent=Dialog) - self.label_3.setObjectName("label_3") - self.horizontalLayout_6.addWidget(self.label_3) - self.comboBox_Endianness = QtWidgets.QComboBox(parent=Dialog) - self.comboBox_Endianness.setObjectName("comboBox_Endianness") - self.horizontalLayout_6.addWidget(self.comboBox_Endianness) - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_6.addItem(spacerItem4) - self.verticalLayout_3.addLayout(self.horizontalLayout_6) - self.gridLayout.addLayout(self.verticalLayout_3, 2, 0, 1, 1) + spacerItem4 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) + self.gridLayout.addItem(spacerItem4, 8, 0, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") self.label = QtWidgets.QLabel(parent=Dialog) @@ -159,16 +169,9 @@ def setupUi(self, Dialog): self.horizontalLayout.addItem(spacerItem5) self.verticalLayout_2.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) - self.verticalLayout = QtWidgets.QVBoxLayout() - self.verticalLayout.setObjectName("verticalLayout") - self.label_4 = QtWidgets.QLabel(parent=Dialog) - self.label_4.setObjectName("label_4") - self.verticalLayout.addWidget(self.label_4) - self.lineEdit_Description = QtWidgets.QLineEdit(parent=Dialog) - self.lineEdit_Description.setText("") - self.lineEdit_Description.setObjectName("lineEdit_Description") - self.verticalLayout.addWidget(self.lineEdit_Description) - self.gridLayout.addLayout(self.verticalLayout, 1, 0, 1, 1) + self.checkBox_IsPointer = QtWidgets.QCheckBox(parent=Dialog) + self.checkBox_IsPointer.setObjectName("checkBox_IsPointer") + self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) self.retranslateUi(Dialog) self.comboBox_ValueType.setCurrentIndex(-1) @@ -179,13 +182,13 @@ def setupUi(self, Dialog): def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Add Address Manually")) + self.label_5.setText(_translate("Dialog", "Type:")) + self.label_3.setText(_translate("Dialog", "Endianness:")) + self.label_Length.setText(_translate("Dialog", "Length:")) + self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_BaseAddress.setText(_translate("Dialog", "Base Address:")) self.pushButton_AddOffset.setText(_translate("Dialog", "Add Offset")) self.pushButton_RemoveOffset.setText(_translate("Dialog", "Remove Offset")) - self.checkBox_IsPointer.setText(_translate("Dialog", "Pointer")) - self.label_5.setText(_translate("Dialog", "Type:")) - self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) - self.label_Length.setText(_translate("Dialog", "Length")) - self.label_3.setText(_translate("Dialog", "Endianness:")) - self.label.setText(_translate("Dialog", "Address:")) self.label_4.setText(_translate("Dialog", "Description:")) + self.label.setText(_translate("Dialog", "Address:")) + self.checkBox_IsPointer.setText(_translate("Dialog", "Pointer")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 639cb1a6..97e51e8d 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -32,6 +32,147 @@ Add Address Manually + + + + + + + + Type: + + + + + + + + 0 + 0 + + + + -1 + + + QComboBox::AdjustToContents + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Endianness: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Length: + + + + + + + + 0 + 0 + + + + + 60 + 16777215 + + + + + + + 10 + + + + + + + Zero-Terminated + + + true + + + + + + + Qt::Horizontal + + + + 13 + 20 + + + + + + + + + @@ -118,6 +259,24 @@ + + + + + + Description: + + + + + + + + + + + + @@ -140,13 +299,6 @@ - - - - Pointer - - - @@ -163,133 +315,6 @@ - - - - - - - - Type: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Zero-Terminated - - - true - - - - - - - - - - - - 0 - 0 - - - - -1 - - - QComboBox::AdjustToContents - - - - - - - Qt::Horizontal - - - - 13 - 20 - - - - - - - - Length - - - - - - - - 0 - 0 - - - - - 60 - 16777215 - - - - - - - 10 - - - - - - - - - - - Endianness: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - @@ -357,23 +382,12 @@ - - - - - - Description: - - - - - - - - - - - + + + + Pointer + + diff --git a/PINCE.py b/PINCE.py index 7bf9e56b..269c24b0 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1763,8 +1763,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.create_offsets_list(address) self.widget_Pointer.show() if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): - self.label_Length.show() - self.lineEdit_Length.show() + self.widget_Length.show() try: length = str(length) except: @@ -1773,8 +1772,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.checkBox_ZeroTerminate.show() self.checkBox_ZeroTerminate.setChecked(zero_terminate) elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: - self.label_Length.show() - self.lineEdit_Length.show() + self.widget_Length.show() try: length = str(length) except: @@ -1782,9 +1780,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.hide() else: - self.label_Length.hide() - self.lineEdit_Length.hide() - self.checkBox_ZeroTerminate.hide() + self.widget_Length.hide() self.setFixedSize(self.layout().sizeHint()) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.comboBox_Endianness.currentIndexChanged.connect(self.update_value_of_address) @@ -1879,17 +1875,12 @@ def update_value_of_address(self): def comboBox_ValueType_current_index_changed(self): if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): - self.label_Length.show() - self.lineEdit_Length.show() + self.widget_Length.show() self.checkBox_ZeroTerminate.show() elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: - self.label_Length.show() - self.lineEdit_Length.show() self.checkBox_ZeroTerminate.hide() else: - self.label_Length.hide() - self.lineEdit_Length.hide() - self.checkBox_ZeroTerminate.hide() + self.widget_Length.hide() self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() From 4c4dbdaaef8147495afd9db8bcf07ca7f46d113d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 15 Dec 2023 19:35:07 +0300 Subject: [PATCH 286/487] Fix sizing issues of AddAddressManuallyDialog --- GUI/AddAddressManuallyDialog.py | 10 +--------- GUI/AddAddressManuallyDialog.ui | 31 +------------------------------ PINCE.py | 21 +++++++++++---------- 3 files changed, 13 insertions(+), 49 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 10899d58..d32f73a1 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -12,14 +12,6 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(224, 410) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) - Dialog.setSizePolicy(sizePolicy) - Dialog.setMinimumSize(QtCore.QSize(0, 0)) - Dialog.setMaximumSize(QtCore.QSize(224, 16777215)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.verticalLayout_3 = QtWidgets.QVBoxLayout() @@ -136,7 +128,7 @@ def setupUi(self, Dialog): self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") - self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1) + self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1, QtCore.Qt.AlignmentFlag.AlignLeft) spacerItem4 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout.addItem(spacerItem4, 8, 0, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 97e51e8d..780fe231 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -2,32 +2,6 @@ Dialog - - - 0 - 0 - 224 - 410 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 224 - 16777215 - - Add Address Manually @@ -277,7 +251,7 @@ - + @@ -367,9 +341,6 @@ Qt::Horizontal - - QSizePolicy::Expanding - 40 diff --git a/PINCE.py b/PINCE.py index 269c24b0..8af64c93 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1745,9 +1745,6 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", endian=type_defs.ENDIANNESS.HOST): super().__init__(parent=parent) self.setupUi(self) - self.adjustSize() - self.setMinimumWidth(300) - self.setFixedHeight(self.height()) self.lineEdit_Length.setValidator(QHexValidator(999, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, index) guiutils.fill_endianness_combobox(self.comboBox_Endianness, endian) @@ -1781,7 +1778,6 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.checkBox_ZeroTerminate.hide() else: self.widget_Length.hide() - self.setFixedSize(self.layout().sizeHint()) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.comboBox_Endianness.currentIndexChanged.connect(self.update_value_of_address) self.lineEdit_Length.textChanged.connect(self.update_value_of_address) @@ -1793,6 +1789,8 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.pushButton_RemoveOffset.clicked.connect(self.removeOffsetLayout) self.label_Value.contextMenuEvent = self.label_Value_context_menu_event self.update_value_of_address() + app.processEvents() + self.adjustSize() def label_Value_context_menu_event(self, event): menu = QMenu() @@ -1830,9 +1828,9 @@ def addOffsetLayout(self, should_update=True): self.offsetsList.append(offsetFrame) self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) if should_update: - app.processEvents() # @todo should probably change this once we can properly resize right after creation - self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() + app.processEvents() # @todo should probably change this once we can properly resize right after creation + self.adjustSize() def removeOffsetLayout(self): if len(self.offsetsList) == 1: @@ -1841,9 +1839,9 @@ def removeOffsetLayout(self): frame.deleteLater() self.verticalLayout_Pointers.removeWidget(frame) del self.offsetsList[-1] - app.processEvents() # @todo should probably change this once we can properly resize right after delete - self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() + app.processEvents() # @todo should probably change this once we can properly resize right after delete + self.adjustSize() def update_value_of_address(self): if self.checkBox_IsPointer.isChecked(): @@ -1878,11 +1876,13 @@ def comboBox_ValueType_current_index_changed(self): self.widget_Length.show() self.checkBox_ZeroTerminate.show() elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: + self.widget_Length.show() self.checkBox_ZeroTerminate.hide() else: self.widget_Length.hide() - self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() + app.processEvents() + self.adjustSize() def checkBox_IsPointer_state_changed(self): if self.checkBox_IsPointer.isChecked(): @@ -1896,8 +1896,9 @@ def checkBox_IsPointer_state_changed(self): self.lineEdit_PtrStartAddress.setText("") self.lineEdit_Address.setEnabled(True) self.widget_Pointer.hide() - self.setFixedSize(self.layout().sizeHint()) self.update_value_of_address() + app.processEvents() + self.adjustSize() def reject(self): super(ManualAddressDialogForm, self).reject() From 3dd58d165fc7e6607f1666fee1ae9c37c40693fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 18 Dec 2023 15:05:22 +0300 Subject: [PATCH 287/487] Implement repr and endian for value type dialogs --- GUI/AddAddressManuallyDialog.py | 33 ++++-- GUI/AddAddressManuallyDialog.ui | 53 +++++++++ GUI/EditTypeDialog.py | 77 +++++++------ GUI/EditTypeDialog.ui | 184 ++++++++++++++++++-------------- PINCE.py | 184 +++++++++++++++++++------------- libpince/type_defs.py | 3 +- 6 files changed, 334 insertions(+), 200 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index d32f73a1..2388232f 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -12,6 +12,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") + Dialog.resize(273, 431) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.verticalLayout_3 = QtWidgets.QVBoxLayout() @@ -44,6 +45,20 @@ def setupUi(self, Dialog): spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_6.addItem(spacerItem1) self.verticalLayout_3.addLayout(self.horizontalLayout_6) + self.widget_Repr = QtWidgets.QWidget(parent=Dialog) + self.widget_Repr.setObjectName("widget_Repr") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget_Repr) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.checkBox_Hex = QtWidgets.QCheckBox(parent=self.widget_Repr) + self.checkBox_Hex.setObjectName("checkBox_Hex") + self.horizontalLayout_2.addWidget(self.checkBox_Hex) + self.checkBox_Signed = QtWidgets.QCheckBox(parent=self.widget_Repr) + self.checkBox_Signed.setObjectName("checkBox_Signed") + self.horizontalLayout_2.addWidget(self.checkBox_Signed) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_2.addItem(spacerItem2) + self.verticalLayout_3.addWidget(self.widget_Repr) self.widget_Length = QtWidgets.QWidget(parent=Dialog) self.widget_Length.setObjectName("widget_Length") self.horizontalLayout_Length = QtWidgets.QHBoxLayout(self.widget_Length) @@ -67,8 +82,8 @@ def setupUi(self, Dialog): self.checkBox_ZeroTerminate.setChecked(True) self.checkBox_ZeroTerminate.setObjectName("checkBox_ZeroTerminate") self.horizontalLayout_Length.addWidget(self.checkBox_ZeroTerminate) - spacerItem2 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_Length.addItem(spacerItem2) + spacerItem3 = QtWidgets.QSpacerItem(13, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_Length.addItem(spacerItem3) self.verticalLayout_3.addWidget(self.widget_Length) self.gridLayout.addLayout(self.verticalLayout_3, 2, 0, 1, 1) self.widget_Pointer = QtWidgets.QWidget(parent=Dialog) @@ -94,8 +109,8 @@ def setupUi(self, Dialog): self.lineEdit_PtrStartAddress.setSizePolicy(sizePolicy) self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem3) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem4) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") @@ -129,8 +144,8 @@ def setupUi(self, Dialog): self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 9, 0, 1, 1, QtCore.Qt.AlignmentFlag.AlignLeft) - spacerItem4 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.gridLayout.addItem(spacerItem4, 8, 0, 1, 1) + spacerItem5 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) + self.gridLayout.addItem(spacerItem5, 8, 0, 1, 1) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") self.label = QtWidgets.QLabel(parent=Dialog) @@ -157,8 +172,8 @@ def setupUi(self, Dialog): self.label_Value.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_Value.setObjectName("label_Value") self.horizontalLayout.addWidget(self.label_Value) - spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem5) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem6) self.verticalLayout_2.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) self.checkBox_IsPointer = QtWidgets.QCheckBox(parent=Dialog) @@ -176,6 +191,8 @@ def retranslateUi(self, Dialog): Dialog.setWindowTitle(_translate("Dialog", "Add Address Manually")) self.label_5.setText(_translate("Dialog", "Type:")) self.label_3.setText(_translate("Dialog", "Endianness:")) + self.checkBox_Hex.setText(_translate("Dialog", "Hex")) + self.checkBox_Signed.setText(_translate("Dialog", "Signed")) self.label_Length.setText(_translate("Dialog", "Length:")) self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_BaseAddress.setText(_translate("Dialog", "Base Address:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 780fe231..cf9ba47b 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -2,6 +2,14 @@ Dialog + + + 0 + 0 + 273 + 431 + + Add Address Manually @@ -75,6 +83,51 @@ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Hex + + + + + + + Signed + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + diff --git a/GUI/EditTypeDialog.py b/GUI/EditTypeDialog.py index 747f1971..10bc1a1b 100644 --- a/GUI/EditTypeDialog.py +++ b/GUI/EditTypeDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'EditTypeDialog.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,8 +12,6 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(345, 119) - Dialog.setMaximumSize(QtCore.QSize(345, 119)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_3 = QtWidgets.QHBoxLayout() @@ -29,48 +27,63 @@ def setupUi(self, Dialog): self.horizontalLayout_3.addLayout(self.verticalLayout) self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") - self.label_Length = QtWidgets.QLabel(parent=Dialog) - self.label_Length.setObjectName("label_Length") - self.verticalLayout_3.addWidget(self.label_Length) - self.horizontalLayout_2 = QtWidgets.QHBoxLayout() - self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lineEdit_Length = QtWidgets.QLineEdit(parent=Dialog) - self.lineEdit_Length.setText("10") - self.lineEdit_Length.setObjectName("lineEdit_Length") - self.horizontalLayout_2.addWidget(self.lineEdit_Length) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_2.addItem(spacerItem) - self.verticalLayout_3.addLayout(self.horizontalLayout_2) + self.label_2 = QtWidgets.QLabel(parent=Dialog) + self.label_2.setObjectName("label_2") + self.verticalLayout_3.addWidget(self.label_2) + self.comboBox_Endianness = QtWidgets.QComboBox(parent=Dialog) + self.comboBox_Endianness.setObjectName("comboBox_Endianness") + self.verticalLayout_3.addWidget(self.comboBox_Endianness) self.horizontalLayout_3.addLayout(self.verticalLayout_3) - self.verticalLayout_2 = QtWidgets.QVBoxLayout() - self.verticalLayout_2.setObjectName("verticalLayout_2") - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_2.addItem(spacerItem1) - self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_ZeroTerminate.setChecked(True) - self.checkBox_ZeroTerminate.setObjectName("checkBox_ZeroTerminate") - self.verticalLayout_2.addWidget(self.checkBox_ZeroTerminate) - self.horizontalLayout_3.addLayout(self.verticalLayout_2) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_3.addItem(spacerItem) self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1) - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.checkBox_Hex = QtWidgets.QCheckBox(parent=Dialog) + self.checkBox_Hex.setObjectName("checkBox_Hex") + self.horizontalLayout_2.addWidget(self.checkBox_Hex) + self.checkBox_Signed = QtWidgets.QCheckBox(parent=Dialog) + self.checkBox_Signed.setObjectName("checkBox_Signed") + self.horizontalLayout_2.addWidget(self.checkBox_Signed) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_2.addItem(spacerItem1) + self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") - self.horizontalLayout.addWidget(self.buttonBox) - spacerItem2 = QtWidgets.QSpacerItem(37, 17, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem2) - self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) + self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 1, QtCore.Qt.AlignmentFlag.AlignLeft) + self.widget_Length = QtWidgets.QWidget(parent=Dialog) + self.widget_Length.setObjectName("widget_Length") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget_Length) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.label_Length = QtWidgets.QLabel(parent=self.widget_Length) + self.label_Length.setObjectName("label_Length") + self.horizontalLayout_4.addWidget(self.label_Length) + self.lineEdit_Length = QtWidgets.QLineEdit(parent=self.widget_Length) + self.lineEdit_Length.setText("10") + self.lineEdit_Length.setObjectName("lineEdit_Length") + self.horizontalLayout_4.addWidget(self.lineEdit_Length) + self.checkBox_ZeroTerminate = QtWidgets.QCheckBox(parent=self.widget_Length) + self.checkBox_ZeroTerminate.setChecked(True) + self.checkBox_ZeroTerminate.setObjectName("checkBox_ZeroTerminate") + self.horizontalLayout_4.addWidget(self.checkBox_ZeroTerminate) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem2) + self.gridLayout.addWidget(self.widget_Length, 2, 0, 1, 1) self.retranslateUi(Dialog) - self.buttonBox.accepted.connect(Dialog.accept) # type: ignore self.buttonBox.rejected.connect(Dialog.reject) # type: ignore + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Type")) - self.label.setText(_translate("Dialog", "Select the new type")) + self.label.setText(_translate("Dialog", "Type")) + self.label_2.setText(_translate("Dialog", "Endianness")) + self.checkBox_Hex.setText(_translate("Dialog", "Hex")) + self.checkBox_Signed.setText(_translate("Dialog", "Signed")) self.label_Length.setText(_translate("Dialog", "Length")) self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) diff --git a/GUI/EditTypeDialog.ui b/GUI/EditTypeDialog.ui index 226d9d46..34a88392 100644 --- a/GUI/EditTypeDialog.ui +++ b/GUI/EditTypeDialog.ui @@ -2,20 +2,6 @@ Dialog - - - 0 - 0 - 345 - 119 - - - - - 345 - 119 - - Type @@ -27,7 +13,7 @@ - Select the new type + Type @@ -39,76 +25,45 @@ - + - Length + Endianness - - - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Zero-Terminated - - - true - - - - + + + Qt::Horizontal + + + + 40 + 20 + + + - + - - - Qt::Horizontal + + + Hex - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + Signed @@ -119,46 +74,111 @@ - 37 - 17 + 40 + 20 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Length + + + + + + + 10 + + + + + + + Zero-Terminated + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + buttonBox - accepted() + rejected() Dialog - accept() + reject() - 248 - 254 + 316 + 260 - 157 + 286 274 buttonBox - rejected() + accepted() Dialog - reject() + accept() - 316 - 260 + 248 + 254 - 286 + 157 274 diff --git a/PINCE.py b/PINCE.py index 8af64c93..4a8025f4 100755 --- a/PINCE.py +++ b/PINCE.py @@ -935,7 +935,7 @@ def create_group(self): dialog = InputDialogForm(item_list=[(tr.ENTER_DESCRIPTION, tr.GROUP)]) if dialog.exec(): desc = dialog.get_values() - self.add_entry_to_addresstable(desc, "0x0", type_defs.VALUE_INDEX.INDEX_INT8) + self.add_entry_to_addresstable(desc, "0x0") return True return False @@ -1036,8 +1036,8 @@ def resize_address_table(self): def pushButton_AddAddressManually_clicked(self): manual_address_dialog = ManualAddressDialogForm() if manual_address_dialog.exec(): - desc, address_expr, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() - self.add_entry_to_addresstable(desc, address_expr, value_index, length, zero_terminate, endian=endian) + desc, address_expr, vt = manual_address_dialog.get_values() + self.add_entry_to_addresstable(desc, address_expr, vt) self.update_address_table() def pushButton_MemoryView_clicked(self): @@ -1263,8 +1263,8 @@ def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) value_index, value_repr, endian = current_item.data(Qt.ItemDataRole.UserRole) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) - self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), value_index, length, - value_repr=value_repr, endian=endian) + vt = type_defs.ValueType(value_index, length, True, value_repr, endian) + self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), vt) self.update_address_table() def comboBox_ValueType_current_index_changed(self): @@ -1391,7 +1391,8 @@ def copy_to_address_table(self): i = i + 1 if i % 3 == 0: value_index, value_repr, endian = row.data(Qt.ItemDataRole.UserRole) - self.add_entry_to_addresstable("", row.text(), value_index, length, True, value_repr, endian) + vt = type_defs.ValueType(value_index, length, True, value_repr, endian) + self.add_entry_to_addresstable(tr.NO_DESCRIPTION, row.text(), vt) self.update_address_table() def reset_scan(self): @@ -1443,13 +1444,12 @@ def closeEvent(self, event): app.closeAllWindows() # Call update_address_table manually after this - def add_entry_to_addresstable(self, description, address_expr, value_index, length=0, zero_terminate=True, - value_repr=type_defs.VALUE_REPR.UNSIGNED, endian=type_defs.ENDIANNESS.HOST): + def add_entry_to_addresstable(self, description, address_expr, value_type=None): current_row = QTreeWidgetItem() current_row.setCheckState(FROZEN_COL, Qt.CheckState.Unchecked) frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) current_row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) - value_type = type_defs.ValueType(value_index, length, zero_terminate, value_repr, endian) + value_type = type_defs.ValueType() if not value_type else value_type self.treeWidget_AddressTable.addTopLevelItem(current_row) self.change_address_table_entries(current_row, description, address_expr, value_type) self.show() # In case of getting called from elsewhere @@ -1597,13 +1597,10 @@ def treeWidget_AddressTable_edit_address(self): if not row: return desc, address_expr, vt = self.read_address_table_entries(row) - manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, index=vt.value_index, - length=vt.length, zero_terminate=vt.zero_terminate, - endian=vt.endian) + manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, value_type=vt) manual_address_dialog.setWindowTitle(tr.EDIT_ADDRESS) if manual_address_dialog.exec(): - desc, address_expr, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() - vt = type_defs.ValueType(value_index, length, zero_terminate, vt.value_repr, endian) + desc, address_expr, vt = manual_address_dialog.get_values() self.change_address_table_entries(row, desc, address_expr, vt) self.update_address_table() @@ -1612,10 +1609,9 @@ def treeWidget_AddressTable_edit_type(self): if not row: return vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - dialog = EditTypeDialogForm(index=vt.value_index, length=vt.length, zero_terminate=vt.zero_terminate) + dialog = EditTypeDialogForm(value_type=vt) if dialog.exec(): - value_index, length, zero_terminate = dialog.get_values() - vt = type_defs.ValueType(value_index, length, zero_terminate, vt.value_repr, vt.endian) + vt = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): row.setData(TYPE_COL, Qt.ItemDataRole.UserRole, vt) row.setText(TYPE_COL, vt.text()) @@ -1740,14 +1736,13 @@ def pushButton_CreateProcess_clicked(self): # Add Address Manually Dialog class ManualAddressDialogForm(QDialog, ManualAddressDialog): - def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", - index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, - endian=type_defs.ENDIANNESS.HOST): + def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", value_type=None): super().__init__(parent=parent) self.setupUi(self) - self.lineEdit_Length.setValidator(QHexValidator(999, self)) - guiutils.fill_value_combobox(self.comboBox_ValueType, index) - guiutils.fill_endianness_combobox(self.comboBox_Endianness, endian) + vt = type_defs.ValueType() if not value_type else value_type + self.lineEdit_Length.setValidator(QHexValidator(99, self)) + guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) + guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) self.lineEdit_Description.setText(description) self.offsetsList = [] if not isinstance(address, type_defs.PointerType): @@ -1767,7 +1762,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", length = "10" self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.show() - self.checkBox_ZeroTerminate.setChecked(zero_terminate) + self.checkBox_ZeroTerminate.setChecked(vt.zero_terminate) elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: self.widget_Length.show() try: @@ -1778,17 +1773,26 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", self.checkBox_ZeroTerminate.hide() else: self.widget_Length.hide() + if vt.value_repr == type_defs.VALUE_REPR.HEX: + self.checkBox_Hex.setChecked(True) + self.checkBox_Signed.setEnabled(False) + elif vt.value_repr == type_defs.VALUE_REPR.SIGNED: + self.checkBox_Signed.setChecked(True) + else: + self.checkBox_Signed.setChecked(False) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) - self.comboBox_Endianness.currentIndexChanged.connect(self.update_value_of_address) - self.lineEdit_Length.textChanged.connect(self.update_value_of_address) - self.checkBox_ZeroTerminate.stateChanged.connect(self.update_value_of_address) + self.comboBox_Endianness.currentIndexChanged.connect(self.update_value) + self.lineEdit_Length.textChanged.connect(self.update_value) + self.checkBox_Hex.stateChanged.connect(self.repr_changed) + self.checkBox_Signed.stateChanged.connect(self.repr_changed) + self.checkBox_ZeroTerminate.stateChanged.connect(self.update_value) self.checkBox_IsPointer.stateChanged.connect(self.checkBox_IsPointer_state_changed) - self.lineEdit_PtrStartAddress.textChanged.connect(self.update_value_of_address) - self.lineEdit_Address.textChanged.connect(self.update_value_of_address) + self.lineEdit_PtrStartAddress.textChanged.connect(self.update_value) + self.lineEdit_Address.textChanged.connect(self.update_value) self.pushButton_AddOffset.clicked.connect(lambda: self.addOffsetLayout(True)) self.pushButton_RemoveOffset.clicked.connect(self.removeOffsetLayout) self.label_Value.contextMenuEvent = self.label_Value_context_menu_event - self.update_value_of_address() + self.update_value() app.processEvents() self.adjustSize() @@ -1799,7 +1803,7 @@ def label_Value_context_menu_event(self, event): menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) actions = { - refresh: self.update_value_of_address + refresh: self.update_value } try: actions[action]() @@ -1817,7 +1821,7 @@ def addOffsetLayout(self, should_update=True): offsetText = QLineEdit(offsetFrame) offsetText.setFixedSize(70, 30) offsetText.setText(hex(0)) - offsetText.textChanged.connect(self.update_value_of_address) + offsetText.textChanged.connect(self.update_value) offsetLayout.addWidget(offsetText) buttonRight = QPushButton(">", offsetFrame) buttonRight.setFixedSize(70, 30) @@ -1828,7 +1832,7 @@ def addOffsetLayout(self, should_update=True): self.offsetsList.append(offsetFrame) self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) if should_update: - self.update_value_of_address() + self.update_value() app.processEvents() # @todo should probably change this once we can properly resize right after creation self.adjustSize() @@ -1839,11 +1843,11 @@ def removeOffsetLayout(self): frame.deleteLater() self.verticalLayout_Pointers.removeWidget(frame) del self.offsetsList[-1] - self.update_value_of_address() + self.update_value() app.processEvents() # @todo should probably change this once we can properly resize right after delete self.adjustSize() - def update_value_of_address(self): + def update_value(self): if self.checkBox_IsPointer.isChecked(): pointer_type = type_defs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) address = GDB_Engine.read_pointer(pointer_type) @@ -1857,18 +1861,17 @@ def update_value_of_address(self): if not address: self.label_Value.setText("??") return - + if self.checkBox_Hex.isChecked(): + value_repr = type_defs.VALUE_REPR.HEX + elif self.checkBox_Signed.isChecked(): + value_repr = type_defs.VALUE_REPR.SIGNED + else: + value_repr = type_defs.VALUE_REPR.UNSIGNED address_type = self.comboBox_ValueType.currentIndex() + length = self.lineEdit_Length.text() + zero_terminate = self.checkBox_ZeroTerminate.isChecked() endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) - if address_type == type_defs.VALUE_INDEX.INDEX_AOB: - length = self.lineEdit_Length.text() - value = GDB_Engine.read_memory(address, address_type, length, endian=endian) - elif type_defs.VALUE_INDEX.is_string(address_type): - length = self.lineEdit_Length.text() - is_zeroterminate = self.checkBox_ZeroTerminate.isChecked() - value = GDB_Engine.read_memory(address, address_type, length, is_zeroterminate, endian=endian) - else: - value = GDB_Engine.read_memory(address, address_type, endian=endian) + value = GDB_Engine.read_memory(address, address_type, length, zero_terminate, value_repr, endian) self.label_Value.setText("??" if value is None else str(value)) def comboBox_ValueType_current_index_changed(self): @@ -1880,10 +1883,17 @@ def comboBox_ValueType_current_index_changed(self): self.checkBox_ZeroTerminate.hide() else: self.widget_Length.hide() - self.update_value_of_address() + self.update_value() app.processEvents() self.adjustSize() + def repr_changed(self): + if self.checkBox_Hex.isChecked(): + self.checkBox_Signed.setEnabled(False) + else: + self.checkBox_Signed.setEnabled(True) + self.update_value() + def checkBox_IsPointer_state_changed(self): if self.checkBox_IsPointer.isChecked(): self.lineEdit_Address.setEnabled(False) @@ -1896,7 +1906,7 @@ def checkBox_IsPointer_state_changed(self): self.lineEdit_PtrStartAddress.setText("") self.lineEdit_Address.setEnabled(True) self.widget_Pointer.hide() - self.update_value_of_address() + self.update_value() app.processEvents() self.adjustSize() @@ -1926,10 +1936,17 @@ def get_values(self): length = 0 zero_terminate = self.checkBox_ZeroTerminate.isChecked() value_index = self.comboBox_ValueType.currentIndex() + if self.checkBox_Hex.isChecked(): + value_repr = type_defs.VALUE_REPR.HEX + elif self.checkBox_Signed.isChecked(): + value_repr = type_defs.VALUE_REPR.SIGNED + else: + value_repr = type_defs.VALUE_REPR.UNSIGNED endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) + vt = type_defs.ValueType(value_index, length, zero_terminate, value_repr, endian) if self.checkBox_IsPointer.isChecked(): address = type_defs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) - return description, address, value_index, length, zero_terminate, endian + return description, address, vt def get_offsets_int_list(self): offsetsIntList = [] @@ -1963,25 +1980,25 @@ def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): class EditTypeDialogForm(QDialog, EditTypeDialog): - def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True): + def __init__(self, parent=None, value_type=None): super().__init__(parent=parent) self.setupUi(self) + vt = type_defs.ValueType() if not value_type else value_type self.setMaximumSize(100, 100) - self.lineEdit_Length.setValidator(QHexValidator(999, self)) - guiutils.fill_value_combobox(self.comboBox_ValueType, index) + self.lineEdit_Length.setValidator(QHexValidator(99, self)) + guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) + guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): - self.label_Length.show() - self.lineEdit_Length.show() + self.widget_Length.show() try: length = str(length) except: length = "10" self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.show() - self.checkBox_ZeroTerminate.setChecked(zero_terminate) + self.checkBox_ZeroTerminate.setChecked(vt.zero_terminate) elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: - self.label_Length.show() - self.lineEdit_Length.show() + self.widget_Length.show() try: length = str(length) except: @@ -1989,24 +2006,32 @@ def __init__(self, parent=None, index=type_defs.VALUE_INDEX.INDEX_INT32, length= self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.hide() else: - self.label_Length.hide() - self.lineEdit_Length.hide() - self.checkBox_ZeroTerminate.hide() + self.widget_Length.hide() + if vt.value_repr == type_defs.VALUE_REPR.HEX: + self.checkBox_Hex.setChecked(True) + self.checkBox_Signed.setEnabled(False) + elif vt.value_repr == type_defs.VALUE_REPR.SIGNED: + self.checkBox_Signed.setChecked(True) + else: + self.checkBox_Signed.setChecked(False) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) + self.checkBox_Hex.stateChanged.connect(self.repr_changed) def comboBox_ValueType_current_index_changed(self): if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): - self.label_Length.show() - self.lineEdit_Length.show() + self.widget_Length.show() self.checkBox_ZeroTerminate.show() elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: - self.label_Length.show() - self.lineEdit_Length.show() + self.widget_Length.show() self.checkBox_ZeroTerminate.hide() else: - self.label_Length.hide() - self.lineEdit_Length.hide() - self.checkBox_ZeroTerminate.hide() + self.widget_Length.hide() + + def repr_changed(self): + if self.checkBox_Hex.isChecked(): + self.checkBox_Signed.setEnabled(False) + else: + self.checkBox_Signed.setEnabled(True) def reject(self): super(EditTypeDialogForm, self).reject() @@ -2025,16 +2050,21 @@ def accept(self): super(EditTypeDialogForm, self).accept() def get_values(self): + value_index = self.comboBox_ValueType.currentIndex() length = self.lineEdit_Length.text() try: length = int(length, 0) except: length = 0 - zero_terminate = False - if self.checkBox_ZeroTerminate.isChecked(): - zero_terminate = True - address_type = self.comboBox_ValueType.currentIndex() - return address_type, length, zero_terminate + zero_terminate = self.checkBox_ZeroTerminate.isChecked() + if self.checkBox_Hex.isChecked(): + value_repr = type_defs.VALUE_REPR.HEX + elif self.checkBox_Signed.isChecked(): + value_repr = type_defs.VALUE_REPR.SIGNED + else: + value_repr = type_defs.VALUE_REPR.UNSIGNED + endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) + return type_defs.ValueType(value_index, length, zero_terminate, value_repr, endian) class TrackSelectorDialogForm(QDialog, TrackSelectorDialog): @@ -2918,11 +2948,11 @@ def exec_hex_view_add_address_dialog(self): if GDB_Engine.currentpid == -1: return selected_address = self.tableView_HexView_Hex.get_selected_address() - manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), - index=type_defs.VALUE_INDEX.INDEX_AOB) + vt = type_defs.ValueType(type_defs.VALUE_INDEX.INDEX_AOB) + manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), value_type=vt) if manual_address_dialog.exec(): - desc, address, value_index, length, zero_terminate, endian = manual_address_dialog.get_values() - self.parent().add_entry_to_addresstable(desc, address, value_index, length, zero_terminate, endian=endian) + desc, address, vt = manual_address_dialog.get_values() + self.parent().add_entry_to_addresstable(desc, address, vt) self.parent().update_address_table() def hex_view_scroll_up(self): @@ -4484,8 +4514,8 @@ def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() - self.parent().parent().add_entry_to_addresstable(tr.ACCESSED_BY.format(self.address), address, - self.comboBox_ValueType.currentIndex(), 10) + vt = type_defs.ValueType(self.comboBox_ValueType.currentIndex()) + self.parent().parent().add_entry_to_addresstable(tr.ACCESSED_BY.format(self.address), address, vt) self.parent().parent().update_address_table() def pushButton_Stop_clicked(self): diff --git a/libpince/type_defs.py b/libpince/type_defs.py index 213d7c66..19fd087e 100644 --- a/libpince/type_defs.py +++ b/libpince/type_defs.py @@ -408,7 +408,8 @@ def __init__(self, value, freeze_type): class ValueType: - def __init__(self, value_index, length, zero_terminate, value_repr=VALUE_REPR.UNSIGNED, endian=ENDIANNESS.HOST): + def __init__(self, value_index=VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, + value_repr=VALUE_REPR.UNSIGNED, endian=ENDIANNESS.HOST): """ Args: value_index (int): Determines the type of data. Can be a member of VALUE_INDEX From e4b4041dac1dcce5bee773a1cf5bf80ee28bc7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 18 Dec 2023 15:14:36 +0300 Subject: [PATCH 288/487] Use setMaximumSize instead of adjustSize to fix resizing issue --- PINCE.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/PINCE.py b/PINCE.py index 4a8025f4..caefcdce 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1739,6 +1739,7 @@ class ManualAddressDialogForm(QDialog, ManualAddressDialog): def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", value_type=None): super().__init__(parent=parent) self.setupUi(self) + self.setMaximumSize(100, 100) vt = type_defs.ValueType() if not value_type else value_type self.lineEdit_Length.setValidator(QHexValidator(99, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) @@ -1793,8 +1794,6 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val self.pushButton_RemoveOffset.clicked.connect(self.removeOffsetLayout) self.label_Value.contextMenuEvent = self.label_Value_context_menu_event self.update_value() - app.processEvents() - self.adjustSize() def label_Value_context_menu_event(self, event): menu = QMenu() @@ -1833,8 +1832,6 @@ def addOffsetLayout(self, should_update=True): self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) if should_update: self.update_value() - app.processEvents() # @todo should probably change this once we can properly resize right after creation - self.adjustSize() def removeOffsetLayout(self): if len(self.offsetsList) == 1: @@ -1844,8 +1841,6 @@ def removeOffsetLayout(self): self.verticalLayout_Pointers.removeWidget(frame) del self.offsetsList[-1] self.update_value() - app.processEvents() # @todo should probably change this once we can properly resize right after delete - self.adjustSize() def update_value(self): if self.checkBox_IsPointer.isChecked(): @@ -1884,8 +1879,6 @@ def comboBox_ValueType_current_index_changed(self): else: self.widget_Length.hide() self.update_value() - app.processEvents() - self.adjustSize() def repr_changed(self): if self.checkBox_Hex.isChecked(): @@ -1907,8 +1900,6 @@ def checkBox_IsPointer_state_changed(self): self.lineEdit_Address.setEnabled(True) self.widget_Pointer.hide() self.update_value() - app.processEvents() - self.adjustSize() def reject(self): super(ManualAddressDialogForm, self).reject() From 96576602260afcd46e307247876c102caec955e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 19 Dec 2023 22:24:36 +0300 Subject: [PATCH 289/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ebd0bb97..3f7a4666 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -174,8 +174,24 @@ forcing me to use magic numbers for adjusting, which is a bit hackish # Roadmap So, after learning how to contribute, you are wondering where to start now. You can either search for `TODO` within the code or pick up any task from the roadmap below. -These are not in order, so free to pick any of them -- Refactor file naming conventions(decide on snake_case or camelCase for modules etc) +These tasks are ordered by importance but feel free to pick any of them. Further details can be discussed in the PINCE discord server +- Implement libpince engine +- Implement multi-line code injection, this will also help with previously dropped inject_with_advanced_injection +- Migrate to Sphinx documentation from the custom libpince documentation +- Move GUI classes of PINCE.py to their own files +- Extend documentation to GUI parts. Libpince has 100% documentation coverage but GUI doesn't +- Use type hints(py 3.5) and variable annotations(py 3.6) when support drops for older systems +- Arrows for jump instructions based on disassembled output +- Flowcharts based on disassembled output +- Consider implementing a GUI for catching signals and syscalls. This is currently done via GDB Console +- Implement speedhack +- Implement unrandomizer +- Implement pointer-scan +- Automatic function bypassing(make it return the desired value, hook specific parts etc.) +- Implement auto-ESP&aimbot +- Implement thread info widget +- Implement multi selection for HexView +- Write at least one test for each function in libpince - Refactorize memory write/read functions - - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. Only update the visible rows to prevent this(check ```disassemble_check_viewport``` for an example) @@ -187,8 +203,6 @@ These are not in order, so free to pick any of them - - Change comboBox_ValueType string order to be ... String_UTF-8 String_Others if necessary - - Implement a custom combobox class for comboBox_ValueType and create a context menu for String_Others, if it gets implemented - Implement "Investigate Registers" button to gather information about the addresses registers point to -- Implement selectionChanged signal of lineEdit_HexView -- Implement multi selection for HexView - Add the ability to track down registers and addresses in tracer(unsure) - Implement CE's Ultimap-like feature for tracing data, dissect code data and raw instruction list. Search for calls and store their hit counts to filter out the functions that haven't or have executed specific number of times. @@ -196,32 +210,13 @@ Implement a flexible input field for the execution count. For instance, 2^x only ([CE#358](https://github.com/cheat-engine/cheat-engine/issues/358)) - Extend search_referenced_strings with relative search - Consider adding type guessing for the StackView -- Move GUI classes of PINCE.py to their own files -- Use gdb python API breakpoints instead of breakpoint commands for optimization, also find a way to eliminate output coming from stepping commands such as ```stepi&``` or ```nexti&``` - Implement a psuedo-terminal for the inferior like edb does(idk if necessary, we don't usually target CLI games, up to debate) -- Implement libpince engine -- Implement auto-ESP&aimbot (depends on libpince engine) - Try to optimize TrackBreakpoint and TrackWatchpoint return data structures further, adding an id field might simplify traversing of the tree, performance tests are required -- Extend tagging system to PINCE GUI functions -- Implement multi-line code injection, this will also help with previously dropped inject_with_advanced_injection -- Break on/Catch signals and syscalls -- Flowcharts based on disassembled output -- Automatic function bypassing(make it return the desired value, hook specific parts etc.) -- Implement speedhack -- Implement unrandomizer -- Implement pointer-scan -- Write at least one test for each function in libpince -- Migrate to Sphinx documentation from the custom libpince documentation -- Embedded tutorial videos -- Super-Uber-Rad credits roll with chiptune tunes(as discussed, this could be an embedded video to prevent unnecessary dependencies) - Implement extra MemoryViewerWindow tabs(not really critical right now, up to debate) - ~~Consider removing the command file layer of IPC system for GDB_Engine.send_command to speed up things~~ [Update-29/04/2018 : Delaying this until GDB/MI implements a native multiline command feature or improves ```interpreter-exec``` command to cover every single multiline command type(including ```define``` commands)] -- Implement thread info widget - Implement developer mode in settings. Developer mode will include features like dissection of GUI elements on events such as mouse-over - Add ability to include non-absolute calls for dissect code feature(i.e call rax). Should be considered after the first version release. Might be useful for multi-breakpoint related features -- Implement toggling of arrows for easier navigation for dissected regions - Provide information about absolute addresses in disassemble screen -- Use type hints(py 3.5) and variable annotations(py 3.6) when support drops for older systems - All tables that hold large amount of data should only update the visible rows(check ```disassemble_check_viewport``` for an example) - Add different kinds of themes and the ability to change between them on runtime. Implement dark theme first. Also add the ability to create a custom theme and modify the existing ones From a119eaa764d9d0687615b3992c47c20f7ae8b560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 20 Dec 2023 12:17:16 +0300 Subject: [PATCH 290/487] Add ability to index regions for examine_expression --- libpince/common_regexes.py | 3 +- .../GDBCommandExtensions.py | 2 +- libpince/gdb_python_scripts/ScriptUtils.py | 28 +++++++++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/libpince/common_regexes.py b/libpince/common_regexes.py index 55b73774..866e696e 100644 --- a/libpince/common_regexes.py +++ b/libpince/common_regexes.py @@ -80,4 +80,5 @@ dissect_code_valid_address = compile(r"(\s+|\[|,)" + hex_number.pattern + "(\s+|\]|,|$)") alphanumerics = compile(r"\w+") file_with_extension = compile(r".+\.\w+") -offset_expression = compile("[/*+\-][0-9a-fA-FxX/*+\-]+$") +offset_expression = compile(r"[/*+\-][0-9a-fA-FxX/*+\-\[\]]+$") +index = compile(r"\[(\d+)\]$") diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/GDBCommandExtensions.py index 697cef5d..69076f49 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/GDBCommandExtensions.py @@ -594,7 +594,7 @@ def invoke(self, arg, from_tty): contents_recv = receive_from_pince() # contents_recv format: [expression1, expression2, ...] - regions = SysUtils.get_region_set(pid) + regions = SysUtils.get_regions(pid) for expression in contents_recv: result_tuple = ScriptUtils.examine_expression(expression, regions) data_read_list.append(result_tuple) diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/ScriptUtils.py index d2ba1429..6eb5c990 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/ScriptUtils.py @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import gdb, sys, traceback, functools +import gdb, sys, os, traceback, functools from collections import OrderedDict # This is some retarded hack @@ -125,15 +125,27 @@ def examine_expression(expression, regions=None): expression = expression.split(offset[0])[0] else: offset = "+0" + index = common_regexes.index.search(expression) + if index: + expression = expression[:index.start()] + index = int(index.group(1)) + else: + index = 0 + count = 0 if expression == inferior_name or common_regexes.file_with_extension.search(expression): - for address, file_name in regions: + for address, _, _, _, _, _, path in regions: + file_name = os.path.split(path)[1] if expression in file_name: - try: - address = hex(eval(address+offset)) - except Exception as e: - print(e) - return type_defs.tuple_examine_expression(None, None, None) - return type_defs.tuple_examine_expression(address+file_name, address, file_name) + if index == count: + address = "0x"+address + try: + address = hex(eval(address+offset)) + except Exception as e: + print(e) + return type_defs.tuple_examine_expression(None, None, None) + return type_defs.tuple_examine_expression(address+file_name, address, file_name) + else: + count += 1 print(e) return type_defs.tuple_examine_expression(None, None, None) result = common_regexes.address_with_symbol.search(str(value)) From 6703badd756e1b2f5d8e8b608bd70162dd2d0636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 25 Dec 2023 20:51:20 +0300 Subject: [PATCH 291/487] Rename modules to nibcase --- CONTRIBUTING.md | 16 +- GUI/AbstractTableModels/AsciiModel.py | 6 +- GUI/AbstractTableModels/HexModel.py | 12 +- GUI/Labels/FlagRegisterLabel.py | 10 +- GUI/Labels/RegisterLabel.py | 12 +- GUI/LibpinceReferenceWidget.py | 4 +- GUI/LibpinceReferenceWidget.ui | 4 +- GUI/TableViews/AsciiView.py | 2 +- GUI/TableViews/HexView.py | 4 +- GUI/Utils/guiutils.py | 24 +- PINCE.py | 1021 +++++++++-------- README.md | 2 +- i18n/ts/it_IT.ts | 4 +- i18n/ts/zh_CN.ts | 8 +- libpince/{GDB_Engine.py => debugcore.py} | 362 +++--- ...BCommandExtensions.py => gdbextensions.py} | 130 +-- .../{ScriptUtils.py => gdbutils.py} | 36 +- libpince/{Injection => injection}/.gitignore | 0 libpince/{Injection => injection}/Notes.txt | 0 libpince/{Injection => injection}/example.c | 0 libpince/{common_regexes.py => regexes.py} | 8 +- libpince/{type_defs.py => typedefs.py} | 12 +- libpince/{SysUtils.py => utils.py} | 88 +- run_tests.py | 16 +- tests/common_defs.py | 17 - ...GDB_Engine_tests.py => debugcore_tests.py} | 10 +- tests/{SysUtils_tests.py => utils_tests.py} | 6 +- 27 files changed, 899 insertions(+), 915 deletions(-) rename libpince/{GDB_Engine.py => debugcore.py} (84%) rename libpince/gdb_python_scripts/{GDBCommandExtensions.py => gdbextensions.py} (82%) rename libpince/gdb_python_scripts/{ScriptUtils.py => gdbutils.py} (80%) rename libpince/{Injection => injection}/.gitignore (100%) rename libpince/{Injection => injection}/Notes.txt (100%) rename libpince/{Injection => injection}/example.c (100%) rename libpince/{common_regexes.py => regexes.py} (89%) rename libpince/{type_defs.py => typedefs.py} (97%) rename libpince/{SysUtils.py => utils.py} (91%) delete mode 100644 tests/common_defs.py rename tests/{GDB_Engine_tests.py => debugcore_tests.py} (72%) rename tests/{SysUtils_tests.py => utils_tests.py} (79%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f7a4666..133c74e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,14 +10,14 @@ - [tr](./tr) - Contains translation constants - [i18n](./i18n) - Contains translation files. `ts` files are created with Qt Linguist and [compile_ts.sh](./compile_ts.sh), `qm` files are created within the last section of [install_pince.sh](./install_pince.sh) - ### **[libpince](./libpince)** - - [GDB_Engine.py](./libpince/GDB_Engine.py) - Everything related to communicating with GDB and debugging - - [SysUtils.py](./libpince/SysUtils.py) - Contains generic utility functions such as parsing, file creation, documentation etc - - [type_defs.py](./libpince/type_defs.py) - Contains all constants and variable definitions - - [common_regexes.py](./libpince/common_regexes.py) - Contains regexes for parsing GDB output and other things - - [Injection](./libpince/Injection) - An example for injecting .so files + - [debugcore.py](./libpince/debugcore.py) - Everything related to communicating with GDB and debugging + - [utils.py](./libpince/utils.py) - Contains generic utility functions such as parsing, file creation, documentation etc + - [typedefs.py](./libpince/typedefs.py) - Contains all constants and variable definitions + - [regexes.py](./libpince/regexes.py) - Contains regexes for parsing GDB output and other things + - [injection](./libpince/injection) - An example for injecting .so files - ### **[gdb_python_scripts](./libpince/gdb_python_scripts)** - - [GDBCommandExtensions.py](./libpince/gdb_python_scripts/GDBCommandExtensions.py) - Contains custom GDB commands - - [ScriptUtils.py](./libpince/gdb_python_scripts/ScriptUtils.py) - Contains utility functions for GDB commands + - [gdbextensions.py](./libpince/gdb_python_scripts/gdbextensions.py) - Contains custom GDB commands + - [gdbutils.py](./libpince/gdb_python_scripts/gdbutils.py) - Contains utility functions for GDB commands - [tests](./libpince/gdb_python_scripts/tests) - An example for .so extension, read more [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) # Code Style @@ -213,7 +213,7 @@ Implement a flexible input field for the execution count. For instance, 2^x only - Implement a psuedo-terminal for the inferior like edb does(idk if necessary, we don't usually target CLI games, up to debate) - Try to optimize TrackBreakpoint and TrackWatchpoint return data structures further, adding an id field might simplify traversing of the tree, performance tests are required - Implement extra MemoryViewerWindow tabs(not really critical right now, up to debate) -- ~~Consider removing the command file layer of IPC system for GDB_Engine.send_command to speed up things~~ +- ~~Consider removing the command file layer of IPC system for debugcore.send_command to speed up things~~ [Update-29/04/2018 : Delaying this until GDB/MI implements a native multiline command feature or improves ```interpreter-exec``` command to cover every single multiline command type(including ```define``` commands)] - Implement developer mode in settings. Developer mode will include features like dissection of GUI elements on events such as mouse-over - Add ability to include non-absolute calls for dissect code feature(i.e call rax). Should be considered after the first version release. Might be useful for multi-breakpoint related features diff --git a/GUI/AbstractTableModels/AsciiModel.py b/GUI/AbstractTableModels/AsciiModel.py index fc860ad0..0b47b923 100644 --- a/GUI/AbstractTableModels/AsciiModel.py +++ b/GUI/AbstractTableModels/AsciiModel.py @@ -18,7 +18,7 @@ from PyQt6.QtGui import QColor, QColorConstants from GUI.AbstractTableModels.HexModel import QHexModel -from libpince import SysUtils, GDB_Engine +from libpince import utils, debugcore breakpoint_red = QColor(QColorConstants.Red) breakpoint_red.setAlpha(96) @@ -31,8 +31,8 @@ def data(self, QModelIndex, int_role=None): if self.data_array and QModelIndex.isValid(): if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() - if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: + if utils.modulo_address(address, debugcore.inferior_arch) in self.breakpoint_list: return QVariant(breakpoint_red) elif int_role == Qt.ItemDataRole.DisplayRole: - return QVariant(SysUtils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()])) + return QVariant(utils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()])) return QVariant() diff --git a/GUI/AbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py index 02a0ccba..10d45a7f 100644 --- a/GUI/AbstractTableModels/HexModel.py +++ b/GUI/AbstractTableModels/HexModel.py @@ -17,7 +17,7 @@ from PyQt6.QtCore import QAbstractTableModel, QVariant, Qt from PyQt6.QtGui import QColor, QColorConstants -from libpince import SysUtils, GDB_Engine +from libpince import utils, debugcore breakpoint_red = QColor(QColorConstants.Red) breakpoint_red.setAlpha(96) @@ -41,7 +41,7 @@ def data(self, QModelIndex, int_role=None): if self.data_array and QModelIndex.isValid(): if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() - if SysUtils.modulo_address(address, GDB_Engine.inferior_arch) in self.breakpoint_list: + if utils.modulo_address(address, debugcore.inferior_arch) in self.breakpoint_list: return QVariant(breakpoint_red) elif int_role == Qt.ItemDataRole.DisplayRole: return QVariant(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]) @@ -49,17 +49,17 @@ def data(self, QModelIndex, int_role=None): return QVariant() def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): - int_address = SysUtils.modulo_address(int_address, GDB_Engine.inferior_arch) + int_address = utils.modulo_address(int_address, debugcore.inferior_arch) self.breakpoint_list.clear() if data_array is None: - self.data_array = GDB_Engine.hex_dump(int_address, offset) + self.data_array = debugcore.hex_dump(int_address, offset) else: self.data_array = data_array if breakpoint_info is None: - breakpoint_info = GDB_Engine.get_breakpoint_info() + breakpoint_info = debugcore.get_breakpoint_info() for bp in breakpoint_info: breakpoint_address = int(bp.address, 16) for i in range(bp.size): - self.breakpoint_list.add(SysUtils.modulo_address(breakpoint_address + i, GDB_Engine.inferior_arch)) + self.breakpoint_list.add(utils.modulo_address(breakpoint_address + i, debugcore.inferior_arch)) self.current_address = int_address self.layoutChanged.emit() diff --git a/GUI/Labels/FlagRegisterLabel.py b/GUI/Labels/FlagRegisterLabel.py index 1c58c7be..333d811e 100644 --- a/GUI/Labels/FlagRegisterLabel.py +++ b/GUI/Labels/FlagRegisterLabel.py @@ -17,7 +17,7 @@ from PyQt6.QtWidgets import QLabel from PyQt6.QtGui import QCursor from PyQt6.QtCore import Qt -from libpince import GDB_Engine, type_defs +from libpince import debugcore, typedefs from PINCE import InputDialogForm from tr.tr import TranslationConstants as tr @@ -39,12 +39,12 @@ def enterEvent(self, QEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): - if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: return - registers = GDB_Engine.read_registers() + registers = debugcore.read_registers() current_flag = self.objectName().lower() label_text = tr.ENTER_FLAG_VALUE.format(self.objectName()) register_dialog = InputDialogForm(item_list=[(label_text, ["0", "1", int(registers[current_flag])])]) if register_dialog.exec(): - GDB_Engine.set_register_flag(current_flag, register_dialog.get_values()) - self.set_value(GDB_Engine.read_registers()[current_flag]) + debugcore.set_register_flag(current_flag, register_dialog.get_values()) + self.set_value(debugcore.read_registers()[current_flag]) diff --git a/GUI/Labels/RegisterLabel.py b/GUI/Labels/RegisterLabel.py index 9cd97411..a808e5b5 100644 --- a/GUI/Labels/RegisterLabel.py +++ b/GUI/Labels/RegisterLabel.py @@ -17,7 +17,7 @@ from PyQt6.QtWidgets import QLabel, QMenu from PyQt6.QtGui import QCursor from PyQt6.QtCore import Qt -from libpince import GDB_Engine, type_defs +from libpince import debugcore, typedefs from PINCE import InputDialogForm from GUI.Utils import guiutils from tr.tr import TranslationConstants as tr @@ -39,18 +39,18 @@ def enterEvent(self, QEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): - if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: return - registers = GDB_Engine.read_registers() + registers = debugcore.read_registers() current_register = self.objectName().lower() register_dialog = InputDialogForm( item_list=[(tr.ENTER_REGISTER_VALUE.format(self.objectName()), registers[current_register])]) if register_dialog.exec(): - GDB_Engine.set_convenience_variable(current_register, register_dialog.get_values()) - self.set_value(GDB_Engine.read_registers()[current_register]) + debugcore.set_convenience_variable(current_register, register_dialog.get_values()) + self.set_value(debugcore.read_registers()[current_register]) def contextMenuEvent(self, QContextMenuEvent): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return menu = QMenu() show_in_hex_view = menu.addAction(tr.SHOW_HEXVIEW) diff --git a/GUI/LibpinceReferenceWidget.py b/GUI/LibpinceReferenceWidget.py index 0a777d0c..e3048e40 100644 --- a/GUI/LibpinceReferenceWidget.py +++ b/GUI/LibpinceReferenceWidget.py @@ -148,7 +148,7 @@ def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "libpince Reference")) self.label_5.setText(_translate("Form", "Search")) - self.label_3.setText(_translate("Form", "type_defs(Type Definitions)")) + self.label_3.setText(_translate("Form", "typedefs(Type Definitions)")) self.treeWidget_ResourceTree.headerItem().setText(1, _translate("Form", "Value")) self.tableWidget_ResourceTable.setSortingEnabled(True) item = self.tableWidget_ResourceTable.horizontalHeaderItem(0) @@ -158,4 +158,4 @@ def retranslateUi(self, Form): self.label_4.setText(_translate("Form", "Search")) self.label.setText(_translate("Form", "Source File")) self.label_2.setText(_translate("Form", "Resources(Mouse-over items to see docstrings)")) - self.pushButton_ShowTypeDefs.setText(_translate("Form", "Hide type_defs")) + self.pushButton_ShowTypeDefs.setText(_translate("Form", "Hide typedefs")) diff --git a/GUI/LibpinceReferenceWidget.ui b/GUI/LibpinceReferenceWidget.ui index 5838b5a0..60275013 100644 --- a/GUI/LibpinceReferenceWidget.ui +++ b/GUI/LibpinceReferenceWidget.ui @@ -61,7 +61,7 @@ - type_defs(Type Definitions) + typedefs(Type Definitions) @@ -275,7 +275,7 @@ - Hide type_defs + Hide typedefs diff --git a/GUI/TableViews/AsciiView.py b/GUI/TableViews/AsciiView.py index cf2f6a4a..ba81803a 100644 --- a/GUI/TableViews/AsciiView.py +++ b/GUI/TableViews/AsciiView.py @@ -18,7 +18,7 @@ class QAsciiView(QHexView): - # data_array is returned from GDB_Engine.hex_dump() + # data_array is returned from debugcore.hex_dump() def __init__(self, parent=None): super().__init__(parent) self.horizontalHeader().setMinimumSectionSize(15) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index d123cd74..98194904 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -16,7 +16,7 @@ """ from PyQt6.QtWidgets import QTableView, QAbstractItemView from PyQt6.QtCore import Qt -from libpince import SysUtils, GDB_Engine +from libpince import utils, debugcore class QHexView(QTableView): @@ -49,4 +49,4 @@ def get_selected_address(self): if index_list: cell = index_list[0] current_address = current_address + cell.row() * self.model().columnCount() + cell.column() - return SysUtils.modulo_address(current_address, GDB_Engine.inferior_arch) + return utils.modulo_address(current_address, debugcore.inferior_arch) diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index 1ab00fc8..6ecf9bbc 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from libpince import SysUtils, type_defs, common_regexes +from libpince import utils, typedefs, regexes from tr.tr import TranslationConstants as tr #:tag:GUI @@ -25,7 +25,7 @@ def get_icons_directory(): Returns: str: Path to the icons directory """ - return SysUtils.get_script_directory() + "/media/icons" + return utils.get_script_directory() + "/media/icons" #:tag:GUI @@ -85,29 +85,29 @@ def resize_to_contents(QTableWidget): #:tag:GUI -def fill_value_combobox(QCombobox, current_index=type_defs.VALUE_INDEX.INDEX_INT32): +def fill_value_combobox(QCombobox, current_index=typedefs.VALUE_INDEX.INDEX_INT32): """Fills the given QCombobox with value_index strings Args: QCombobox (QCombobox): The combobox that'll be filled - current_index (int): Can be a member of type_defs.VALUE_INDEX + current_index (int): Can be a member of typedefs.VALUE_INDEX """ - for key in type_defs.index_to_text_dict: - QCombobox.addItem(type_defs.index_to_text_dict[key]) + for key in typedefs.index_to_text_dict: + QCombobox.addItem(typedefs.index_to_text_dict[key]) QCombobox.setCurrentIndex(current_index) #:tag:GUI -def fill_endianness_combobox(QCombobox, current_index=type_defs.ENDIANNESS.HOST): +def fill_endianness_combobox(QCombobox, current_index=typedefs.ENDIANNESS.HOST): """Fills the given QCombobox with endianness strings Args: QCombobox (QCombobox): The combobox that'll be filled - current_index (int): Can be a member of type_defs.ENDIANNESS + current_index (int): Can be a member of typedefs.ENDIANNESS """ endianness_text = [ - (type_defs.ENDIANNESS.HOST, tr.HOST), - (type_defs.ENDIANNESS.LITTLE, tr.LITTLE), - (type_defs.ENDIANNESS.BIG, tr.BIG) + (typedefs.ENDIANNESS.HOST, tr.HOST), + (typedefs.ENDIANNESS.LITTLE, tr.LITTLE), + (typedefs.ENDIANNESS.BIG, tr.BIG) ] for endian, text in endianness_text: QCombobox.addItem(text, endian) @@ -236,7 +236,7 @@ def contains_reference_mark(string): Returns: bool: True if given string contains the reference mark, False otherwise """ - return True if common_regexes.reference_mark.search(string) else False + return True if regexes.reference_mark.search(string) else False #:tag:GUI diff --git a/PINCE.py b/PINCE.py index caefcdce..325709e2 100755 --- a/PINCE.py +++ b/PINCE.py @@ -39,7 +39,7 @@ from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect -from libpince import SysUtils, GDB_Engine, type_defs +from libpince import utils, debugcore, typedefs from libpince.libscanmem.scanmem import Scanmem from GUI.Utils import guiutils @@ -107,7 +107,7 @@ def get_locale(): app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") app.setApplicationName("PINCE") QSettings.setPath(QSettings.Format.NativeFormat, QSettings.Scope.UserScope, - SysUtils.get_user_path(type_defs.USER_PATHS.CONFIG_PATH)) + utils.get_user_path(typedefs.USER_PATHS.CONFIG_PATH)) settings = QSettings() translator = QTranslator() locale = settings.value("General/locale", type=str) @@ -120,7 +120,7 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "25" # Increase version by one if you change settings +current_settings_version = "26" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -305,7 +305,7 @@ def get_hotkeys(): # vars for communication with the non blocking threads exiting = 0 -scanmem = Scanmem(os.path.join(SysUtils.get_libpince_directory(), "libscanmem", "libscanmem.so")) +scanmem = Scanmem(os.path.join(utils.get_libpince_directory(), "libscanmem", "libscanmem.so")) threadpool = QThreadPool() # Placeholder number, may have to be changed in the future @@ -329,7 +329,7 @@ def run(self): def except_hook(exception_type, value, tb): focused_widget = app.focusWidget() - if focused_widget and exception_type == type_defs.GDBInitializeException: + if focused_widget and exception_type == typedefs.GDBInitializeException: QMessageBox.information(focused_widget, tr.ERROR, tr.GDB_INIT) traceback.print_exception(exception_type, value, tb) @@ -340,18 +340,18 @@ def except_hook(exception_type, value, tb): def signal_handler(signal, frame): - if GDB_Engine.lock_send_command.locked(): + if debugcore.lock_send_command.locked(): print("\nCancelling the last GDB command") - GDB_Engine.cancel_last_command() + debugcore.cancel_last_command() else: try: text = input("\nNo GDB command to cancel, quit PINCE? (y/n)") if text.lower().startswith("y"): - GDB_Engine.detach() + debugcore.detach() quit() except RuntimeError: print() # Prints a newline so the terminal looks nicer when we quit - GDB_Engine.detach() + debugcore.detach() quit() @@ -364,8 +364,8 @@ class AwaitProcessExit(QThread): def run(self): while True: - with GDB_Engine.process_exited_condition: - GDB_Engine.process_exited_condition.wait() + with debugcore.process_exited_condition: + debugcore.process_exited_condition.wait() self.process_exited.emit() @@ -378,7 +378,7 @@ def __init__(self): self.queue_active = True def run(self): - async_output_queue = GDB_Engine.gdb_async_output.register_queue() + async_output_queue = debugcore.gdb_async_output.register_queue() while self.queue_active: try: async_output = async_output_queue.get(timeout=5) @@ -386,7 +386,7 @@ def run(self): pass else: self.async_output_ready.emit(async_output) - GDB_Engine.gdb_async_output.delete_queue(async_output_queue) + debugcore.gdb_async_output.delete_queue(async_output_queue) def stop(self): self.queue_active = False @@ -398,11 +398,11 @@ class CheckInferiorStatus(QThread): def run(self): while True: - with GDB_Engine.status_changed_condition: - GDB_Engine.status_changed_condition.wait() - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_STOPPED: + with debugcore.status_changed_condition: + debugcore.status_changed_condition.wait() + if debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_STOPPED: self.process_stopped.emit() - elif GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + elif debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: self.process_running.emit() @@ -424,11 +424,11 @@ def __init__(self): Hotkeys.break_hotkey: self.break_hotkey_pressed, Hotkeys.continue_hotkey: self.continue_hotkey_pressed, Hotkeys.toggle_attach_hotkey: self.toggle_attach_hotkey_pressed, - Hotkeys.exact_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.EXACT), - Hotkeys.increased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.INCREASED), - Hotkeys.decreased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.DECREASED), - Hotkeys.changed_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.CHANGED), - Hotkeys.unchanged_scan_hotkey: lambda: self.nextscan_hotkey_pressed(type_defs.SCAN_TYPE.UNCHANGED) + Hotkeys.exact_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.EXACT), + Hotkeys.increased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.INCREASED), + Hotkeys.decreased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.DECREASED), + Hotkeys.changed_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.CHANGED), + Hotkeys.unchanged_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.UNCHANGED) } for hotkey, func in hotkey_to_func.items(): hotkey.change_func(func) @@ -440,7 +440,8 @@ def __init__(self): self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) self.settings = QSettings() - if not SysUtils.is_path_valid(self.settings.fileName()): + settings_path = self.settings.fileName() + if not utils.is_path_valid(settings_path): self.set_default_settings() try: settings_version = self.settings.value("Misc/version", type=str) @@ -449,16 +450,16 @@ def __init__(self): settings_version = None if settings_version != current_settings_version: print("Settings version mismatch, rolling back to the default configuration") - self.settings.clear() + os.remove(settings_path) self.set_default_settings() try: self.apply_settings() except Exception as e: print("An exception occurred while loading settings, rolling back to the default configuration\n", e) - self.settings.clear() + os.remove(settings_path) self.set_default_settings() try: - GDB_Engine.init_gdb(gdb_path) + debugcore.init_gdb(gdb_path) except pexpect.EOF: InputDialogForm(item_list=[(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() else: @@ -497,7 +498,7 @@ def __init__(self): self.pushButton_NewFirstScan.clicked.connect(self.pushButton_NewFirstScan_clicked) self.pushButton_UndoScan.clicked.connect(self.pushButton_UndoScan_clicked) self.pushButton_NextScan.clicked.connect(self.pushButton_NextScan_clicked) - self.scan_mode = type_defs.SCAN_MODE.NEW + self.scan_mode = typedefs.SCAN_MODE.NEW self.pushButton_NewFirstScan_clicked() self.comboBox_ScanScope_init() self.comboBox_ValueType_init() @@ -550,7 +551,7 @@ def set_default_settings(self): self.settings.setValue("auto_update_address_table", True) self.settings.setValue("address_table_update_interval", 500) self.settings.setValue("freeze_interval", 100) - self.settings.setValue("gdb_output_mode", type_defs.gdb_output_mode(True, True, True)) + self.settings.setValue("gdb_output_mode", typedefs.gdb_output_mode(True, True, True)) self.settings.setValue("auto_attach_list", "") self.settings.setValue("auto_attach_regex", False) self.settings.setValue("locale", get_locale()) @@ -561,14 +562,14 @@ def set_default_settings(self): self.settings.setValue(hotkey.name, hotkey.default) self.settings.endGroup() self.settings.beginGroup("CodeInjection") - self.settings.setValue("code_injection_method", type_defs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL) + self.settings.setValue("code_injection_method", typedefs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL) self.settings.endGroup() self.settings.beginGroup("Disassemble") self.settings.setValue("bring_disassemble_to_front", False) self.settings.setValue("instructions_per_scroll", 2) self.settings.endGroup() self.settings.beginGroup("Debug") - self.settings.setValue("gdb_path", type_defs.PATHS.GDB_PATH) + self.settings.setValue("gdb_path", typedefs.PATHS.GDB_PATH) self.settings.setValue("gdb_logging", False) self.settings.setValue("ignored_signals", "1,1,1,0") self.settings.endGroup() @@ -585,12 +586,12 @@ def apply_after_init(self): exp_cache.clear() gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) ignored_signals = self.settings.value("Debug/ignored_signals", type=str) - GDB_Engine.set_logging(gdb_logging) + debugcore.set_logging(gdb_logging) for index, ignore_status in enumerate(ignored_signals.split(",")): if ignore_status == "1": - GDB_Engine.ignore_signal(signal_list[index]) + debugcore.ignore_signal(signal_list[index]) else: - GDB_Engine.unignore_signal(signal_list[index]) + debugcore.unignore_signal(signal_list[index]) def apply_settings(self): global update_table @@ -614,8 +615,8 @@ def apply_settings(self): auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) locale = self.settings.value("General/locale", type=str) logo_path = self.settings.value("General/logo_path", type=str) - app.setWindowIcon(QIcon(os.path.join(SysUtils.get_logo_directory(), logo_path))) - GDB_Engine.set_gdb_output_mode(gdb_output_mode) + app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) + debugcore.set_gdb_output_mode(gdb_output_mode) for hotkey in Hotkeys.get_hotkeys(): hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) try: @@ -626,7 +627,7 @@ def apply_settings(self): bring_disassemble_to_front = self.settings.value("Disassemble/bring_disassemble_to_front", type=bool) instructions_per_scroll = self.settings.value("Disassemble/instructions_per_scroll", type=int) gdb_path = self.settings.value("Debug/gdb_path", type=str) - if GDB_Engine.gdb_initialized: + if debugcore.gdb_initialized: self.apply_after_init() # Check if any process should be attached to automatically @@ -640,14 +641,14 @@ def auto_attach(self): except: print("Auto-attach failed: " + auto_attach_list + " isn't a valid regex") return - for pid, _, name in SysUtils.get_process_list(): + for pid, _, name in utils.get_process_list(): if compiled_re.search(name): self.attach_to_pid(pid) self.flashAttachButton = False return else: for target in auto_attach_list.split(";"): - for pid, _, name in SysUtils.get_process_list(): + for pid, _, name in utils.get_process_list(): if name.find(target) != -1: self.attach_to_pid(pid) self.flashAttachButton = False @@ -657,29 +658,29 @@ def auto_attach(self): # Writing a custom event loop instead of ignoring exceptions could work as well but honestly, this looks cleaner # Keyboard package does not play well with Qt, do not use anything Qt related with hotkeys # Instead of using Qt functions, try to use their signals to prevent crashes - @SysUtils.ignore_exceptions + @utils.ignore_exceptions def pause_hotkey_pressed(self): - GDB_Engine.interrupt_inferior(type_defs.STOP_REASON.PAUSE) + debugcore.interrupt_inferior(typedefs.STOP_REASON.PAUSE) - @SysUtils.ignore_exceptions + @utils.ignore_exceptions def break_hotkey_pressed(self): - GDB_Engine.interrupt_inferior() + debugcore.interrupt_inferior() - @SysUtils.ignore_exceptions + @utils.ignore_exceptions def continue_hotkey_pressed(self): - GDB_Engine.continue_inferior() + debugcore.continue_inferior() - @SysUtils.ignore_exceptions + @utils.ignore_exceptions def toggle_attach_hotkey_pressed(self): - result = GDB_Engine.toggle_attach() + result = debugcore.toggle_attach() if not result: print("Unable to toggle attach") - elif result == type_defs.TOGGLE_ATTACH.DETACHED: + elif result == typedefs.TOGGLE_ATTACH.DETACHED: self.on_status_detached() - @SysUtils.ignore_exceptions + @utils.ignore_exceptions def nextscan_hotkey_pressed(self, index): - if self.scan_mode == type_defs.SCAN_MODE.NEW: + if self.scan_mode == typedefs.SCAN_MODE.NEW: return self.comboBox_ScanType.setCurrentIndex(index) self.pushButton_NextScan.clicked.emit() @@ -725,12 +726,12 @@ def treeWidget_AddressTable_context_menu_event(self, event): guiutils.delete_menu_entries(menu, deletion_list) else: value_type = current_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - if type_defs.VALUE_INDEX.is_integer(value_type.value_index): - if value_type.value_repr is type_defs.VALUE_REPR.HEX: + if typedefs.VALUE_INDEX.is_integer(value_type.value_index): + if value_type.value_repr is typedefs.VALUE_REPR.HEX: guiutils.delete_menu_entries(menu, [show_unsigned, show_signed, show_hex]) - elif value_type.value_repr is type_defs.VALUE_REPR.UNSIGNED: + elif value_type.value_repr is typedefs.VALUE_REPR.UNSIGNED: guiutils.delete_menu_entries(menu, [show_unsigned, show_dec]) - elif value_type.value_repr is type_defs.VALUE_REPR.SIGNED: + elif value_type.value_repr is typedefs.VALUE_REPR.SIGNED: guiutils.delete_menu_entries(menu, [show_signed, show_dec]) if current_row.checkState(FROZEN_COL) == Qt.CheckState.Unchecked: guiutils.delete_menu_entries(menu, [freeze_menu.menuAction()]) @@ -746,19 +747,19 @@ def treeWidget_AddressTable_context_menu_event(self, event): edit_address: self.treeWidget_AddressTable_edit_address, edit_type: self.treeWidget_AddressTable_edit_type, edit_value: self.treeWidget_AddressTable_edit_value, - show_hex: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.HEX), - show_dec: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.UNSIGNED), - show_unsigned: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.UNSIGNED), - show_signed: lambda: self.treeWidget_AddressTable_change_repr(type_defs.VALUE_REPR.SIGNED), + show_hex: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.HEX), + show_dec: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.UNSIGNED), + show_unsigned: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.UNSIGNED), + show_signed: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.SIGNED), toggle_record: self.toggle_records, - freeze_default: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.DEFAULT), - freeze_inc: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.INCREMENT), - freeze_dec: lambda: self.change_freeze_type(type_defs.FREEZE_TYPE.DECREMENT), + freeze_default: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT), + freeze_inc: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.INCREMENT), + freeze_dec: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DECREMENT), browse_region: self.browse_region_for_selected_row, disassemble: self.disassemble_selected_row, - what_writes: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.WRITE_ONLY), - what_reads: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.READ_ONLY), - what_accesses: lambda: self.exec_track_watchpoint_widget(type_defs.WATCHPOINT_TYPE.BOTH), + what_writes: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.WRITE_ONLY), + what_reads: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.READ_ONLY), + what_accesses: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.BOTH), cut_record: self.cut_records, copy_record: self.copy_records, paste_record: self.paste_records, @@ -777,7 +778,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): return address = selected_row.text(ADDR_COL).strip("P->") # @todo Maybe rework address grabbing logic in the future address_data = selected_row.data(ADDR_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, type_defs.PointerType): + if isinstance(address_data, typedefs.PointerType): selection_dialog = TrackSelectorDialogForm() selection_dialog.exec() if not selection_dialog.selection: @@ -785,14 +786,14 @@ def exec_track_watchpoint_widget(self, watchpoint_type): if selection_dialog.selection == "pointer": address = address_data.get_base_address() value_type = selected_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - if type_defs.VALUE_INDEX.is_string(value_type.value_index): + if typedefs.VALUE_INDEX.is_string(value_type.value_index): value_text = selected_row.text(VALUE_COL) - encoding, option = type_defs.string_index_to_encoding_dict[value_type.value_index] + encoding, option = typedefs.string_index_to_encoding_dict[value_type.value_index] byte_len = len(value_text.encode(encoding, option)) - elif value_type.value_index == type_defs.VALUE_INDEX.INDEX_AOB: + elif value_type.value_index == typedefs.VALUE_INDEX.INDEX_AOB: byte_len = value_type.length else: - byte_len = type_defs.index_to_valuetype_dict[value_type.value_index][0] + byte_len = typedefs.index_to_valuetype_dict[value_type.value_index][0] TrackWatchpointWidgetForm(address, byte_len, watchpoint_type, self).show() def browse_region_for_selected_row(self): @@ -816,13 +817,13 @@ def change_freeze_type(self, freeze_type): frozen.freeze_type = freeze_type # TODO: Create a QWidget subclass with signals so freeze type can be changed by clicking on the cell - if freeze_type == type_defs.FREEZE_TYPE.DEFAULT: + if freeze_type == typedefs.FREEZE_TYPE.DEFAULT: row.setText(FROZEN_COL, "") row.setForeground(FROZEN_COL, QBrush()) - elif freeze_type == type_defs.FREEZE_TYPE.INCREMENT: + elif freeze_type == typedefs.FREEZE_TYPE.INCREMENT: row.setText(FROZEN_COL, "▲") row.setForeground(FROZEN_COL, QBrush(QColor(0, 255, 0))) - elif freeze_type == type_defs.FREEZE_TYPE.DECREMENT: + elif freeze_type == typedefs.FREEZE_TYPE.DECREMENT: row.setText(FROZEN_COL, "▼") row.setForeground(FROZEN_COL, QBrush(QColor(255, 0, 0))) @@ -881,15 +882,15 @@ def insert_records(self, records, parent_row, insert_index): for rec in records: row = QTreeWidgetItem() row.setCheckState(FROZEN_COL, Qt.CheckState.Unchecked) - frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) + frozen = typedefs.Frozen("", typedefs.FREEZE_TYPE.DEFAULT) row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) # Deserialize the address_expr & value_type param if type(rec[1]) in [list, tuple]: - address_expr = type_defs.PointerType(*rec[1]) + address_expr = typedefs.PointerType(*rec[1]) else: address_expr = rec[1] - value_type = type_defs.ValueType(*rec[2]) + value_type = typedefs.ValueType(*rec[2]) self.change_address_table_entries(row, rec[0], address_expr, value_type) self.insert_records(rec[-1], row, 0) rows.append(row) @@ -945,7 +946,7 @@ def delete_records(self): (item.parent() or root).removeChild(item) def treeWidget_AddressTable_key_press_event(self, event): - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), self.browse_region_for_selected_row), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), @@ -972,10 +973,10 @@ def treeWidget_AddressTable_key_press_event(self, event): def update_address_table(self, use_cache=True): global exp_cache - if GDB_Engine.currentpid == -1 or self.treeWidget_AddressTable.topLevelItemCount() == 0: + if debugcore.currentpid == -1 or self.treeWidget_AddressTable.topLevelItemCount() == 0: return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) - mem_handle = GDB_Engine.memory_handle() + mem_handle = debugcore.memory_handle() basic_math_exp = re.compile(r"^[0-9a-fA-F][/*+\-0-9a-fA-FxX]+$") while True: row = it.value() @@ -983,7 +984,7 @@ def update_address_table(self, use_cache=True): break it += 1 address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, type_defs.PointerType): + if isinstance(address_data, typedefs.PointerType): expression = address_data.base_address else: expression = address_data @@ -998,20 +999,20 @@ def update_address_table(self, use_cache=True): try: address = hex(eval(expression)) except: - address = GDB_Engine.examine_expression(expression).address + address = debugcore.examine_expression(expression).address exp_cache[expression] = address else: - address = GDB_Engine.examine_expression(expression).address + address = debugcore.examine_expression(expression).address exp_cache[expression] = address vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, type_defs.PointerType): + if isinstance(address_data, typedefs.PointerType): # The original base could be a symbol so we have to save it # This little hack avoids the unnecessary examine_expression call # TODO: Consider implementing exp_cache inside libpince so we don't need this hack if address: old_base = address_data.base_address # save the old base address_data.base_address = address - address = GDB_Engine.read_pointer(address_data) + address = debugcore.read_pointer(address_data) address_data.base_address = old_base # then set it back if address: address = hex(address) @@ -1024,7 +1025,7 @@ def update_address_table(self, use_cache=True): row.setText(ADDR_COL, address or address_data) address = "" if not address else address row.setData(ADDR_COL, Qt.ItemDataRole.UserRole+1, address) - value = GDB_Engine.read_memory(address, vt.value_index, vt.length, vt.zero_terminate, + value = debugcore.read_memory(address, vt.value_index, vt.length, vt.zero_terminate, vt.value_repr, vt.endian, mem_handle=mem_handle) value = "" if value is None else str(value) row.setText(VALUE_COL, value) @@ -1045,7 +1046,7 @@ def pushButton_MemoryView_clicked(self): self.memory_view_window.activateWindow() def pushButton_Wiki_clicked(self): - SysUtils.execute_command_as_user('python3 -m webbrowser "https://github.com/korcankaraokcu/PINCE/wiki"') + utils.execute_command_as_user('python3 -m webbrowser "https://github.com/korcankaraokcu/PINCE/wiki"') def pushButton_About_clicked(self): self.about_widget.show() @@ -1072,13 +1073,13 @@ def checkBox_Hex_stateChanged(self, state): # TODO add a damn keybind for this... def pushButton_NewFirstScan_clicked(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: self.comboBox_ScanType_init() return - if self.scan_mode == type_defs.SCAN_MODE.ONGOING: + if self.scan_mode == typedefs.SCAN_MODE.ONGOING: self.reset_scan() else: - self.scan_mode = type_defs.SCAN_MODE.ONGOING + self.scan_mode = typedefs.SCAN_MODE.ONGOING self.pushButton_NewFirstScan.setText(tr.NEW_SCAN) self.comboBox_ValueType.setEnabled(False) self.pushButton_NextScan.setEnabled(True) @@ -1097,13 +1098,13 @@ def pushButton_UndoScan_clicked(self): self.pushButton_NextScan_clicked("undo") def comboBox_ScanType_current_index_changed(self): - hidden_types = [type_defs.SCAN_TYPE.INCREASED, type_defs.SCAN_TYPE.DECREASED, type_defs.SCAN_TYPE.CHANGED, - type_defs.SCAN_TYPE.UNCHANGED, type_defs.SCAN_TYPE.UNKNOWN] + hidden_types = [typedefs.SCAN_TYPE.INCREASED, typedefs.SCAN_TYPE.DECREASED, typedefs.SCAN_TYPE.CHANGED, + typedefs.SCAN_TYPE.UNCHANGED, typedefs.SCAN_TYPE.UNKNOWN] if self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) in hidden_types: self.widget_Scan.setEnabled(False) else: self.widget_Scan.setEnabled(True) - if self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) == type_defs.SCAN_TYPE.BETWEEN: + if self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) == typedefs.SCAN_TYPE.BETWEEN: self.label_Between.setVisible(True) self.lineEdit_Scan2.setVisible(True) else: @@ -1112,21 +1113,21 @@ def comboBox_ScanType_current_index_changed(self): def comboBox_ScanType_init(self): scan_type_text = { - type_defs.SCAN_TYPE.EXACT: tr.EXACT, - type_defs.SCAN_TYPE.INCREASED: tr.INCREASED, - type_defs.SCAN_TYPE.INCREASED_BY: tr.INCREASED_BY, - type_defs.SCAN_TYPE.DECREASED: tr.DECREASED, - type_defs.SCAN_TYPE.DECREASED_BY: tr.DECREASED_BY, - type_defs.SCAN_TYPE.LESS: tr.LESS_THAN, - type_defs.SCAN_TYPE.MORE: tr.MORE_THAN, - type_defs.SCAN_TYPE.BETWEEN: tr.BETWEEN, - type_defs.SCAN_TYPE.CHANGED: tr.CHANGED, - type_defs.SCAN_TYPE.UNCHANGED: tr.UNCHANGED, - type_defs.SCAN_TYPE.UNKNOWN: tr.UNKNOWN_VALUE + typedefs.SCAN_TYPE.EXACT: tr.EXACT, + typedefs.SCAN_TYPE.INCREASED: tr.INCREASED, + typedefs.SCAN_TYPE.INCREASED_BY: tr.INCREASED_BY, + typedefs.SCAN_TYPE.DECREASED: tr.DECREASED, + typedefs.SCAN_TYPE.DECREASED_BY: tr.DECREASED_BY, + typedefs.SCAN_TYPE.LESS: tr.LESS_THAN, + typedefs.SCAN_TYPE.MORE: tr.MORE_THAN, + typedefs.SCAN_TYPE.BETWEEN: tr.BETWEEN, + typedefs.SCAN_TYPE.CHANGED: tr.CHANGED, + typedefs.SCAN_TYPE.UNCHANGED: tr.UNCHANGED, + typedefs.SCAN_TYPE.UNKNOWN: tr.UNKNOWN_VALUE } current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() - items = type_defs.SCAN_TYPE.get_list(self.scan_mode) + items = typedefs.SCAN_TYPE.get_list(self.scan_mode) old_index = 0 for index, type_index in enumerate(items): if current_type == type_index: @@ -1136,20 +1137,20 @@ def comboBox_ScanType_init(self): def comboBox_ScanScope_init(self): scan_scope_text = [ - (type_defs.SCAN_SCOPE.BASIC, tr.BASIC), - (type_defs.SCAN_SCOPE.NORMAL, tr.NORMAL), - (type_defs.SCAN_SCOPE.FULL_RW, tr.RW), - (type_defs.SCAN_SCOPE.FULL, tr.FULL) + (typedefs.SCAN_SCOPE.BASIC, tr.BASIC), + (typedefs.SCAN_SCOPE.NORMAL, tr.NORMAL), + (typedefs.SCAN_SCOPE.FULL_RW, tr.RW), + (typedefs.SCAN_SCOPE.FULL, tr.FULL) ] for scope, text in scan_scope_text: self.comboBox_ScanScope.addItem(text, scope) - self.comboBox_ScanScope.setCurrentIndex(1) # type_defs.SCAN_SCOPE.NORMAL + self.comboBox_ScanScope.setCurrentIndex(1) # typedefs.SCAN_SCOPE.NORMAL def comboBox_ValueType_init(self): self.comboBox_ValueType.clear() - for value_index, value_text in type_defs.scan_index_to_text_dict.items(): + for value_index, value_text in typedefs.scan_index_to_text_dict.items(): self.comboBox_ValueType.addItem(value_text, value_index) - self.comboBox_ValueType.setCurrentIndex(type_defs.SCAN_INDEX.INDEX_INT32) + self.comboBox_ValueType.setCurrentIndex(typedefs.SCAN_INDEX.INDEX_INT32) self.comboBox_ValueType_current_index_changed() # :doc: @@ -1158,18 +1159,18 @@ def comboBox_ValueType_init(self): def validate_search(self, search_for, search_for2): type_index = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) symbol_map = { - type_defs.SCAN_TYPE.INCREASED: "+", - type_defs.SCAN_TYPE.DECREASED: "-", - type_defs.SCAN_TYPE.CHANGED: "!=", - type_defs.SCAN_TYPE.UNCHANGED: "=", - type_defs.SCAN_TYPE.UNKNOWN: "snapshot" + typedefs.SCAN_TYPE.INCREASED: "+", + typedefs.SCAN_TYPE.DECREASED: "-", + typedefs.SCAN_TYPE.CHANGED: "!=", + typedefs.SCAN_TYPE.UNCHANGED: "=", + typedefs.SCAN_TYPE.UNKNOWN: "snapshot" } if type_index in symbol_map: return symbol_map[type_index] # none of these should be possible to be true at the same time scan_index = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) - if scan_index >= type_defs.SCAN_INDEX.INDEX_FLOAT_ANY and scan_index <= type_defs.SCAN_INDEX.INDEX_FLOAT64: + if scan_index >= typedefs.SCAN_INDEX.INDEX_FLOAT_ANY and scan_index <= typedefs.SCAN_INDEX.INDEX_FLOAT64: # Adjust to locale whatever the input if QLocale.system().decimalPoint() == ".": search_for = search_for.replace(",", ".") @@ -1177,20 +1178,20 @@ def validate_search(self, search_for, search_for2): else: search_for = search_for.replace(".", ",") search_for2 = search_for2.replace(".", ",") - elif scan_index == type_defs.SCAN_INDEX.INDEX_STRING: + elif scan_index == typedefs.SCAN_INDEX.INDEX_STRING: search_for = "\" " + search_for elif self.checkBox_Hex.isChecked(): if not search_for.startswith("0x"): search_for = "0x" + search_for if not search_for2.startswith("0x"): search_for2 = "0x" + search_for2 - if type_index == type_defs.SCAN_TYPE.BETWEEN: + if type_index == typedefs.SCAN_TYPE.BETWEEN: return search_for + ".." + search_for2 cmp_symbols = { - type_defs.SCAN_TYPE.INCREASED_BY: "+", - type_defs.SCAN_TYPE.DECREASED_BY: "-", - type_defs.SCAN_TYPE.LESS: "<", - type_defs.SCAN_TYPE.MORE: ">" + typedefs.SCAN_TYPE.INCREASED_BY: "+", + typedefs.SCAN_TYPE.DECREASED_BY: "-", + typedefs.SCAN_TYPE.LESS: "<", + typedefs.SCAN_TYPE.MORE: ">" } if type_index in cmp_symbols: return cmp_symbols[type_index] + " " + search_for @@ -1198,7 +1199,7 @@ def validate_search(self, search_for, search_for2): def pushButton_NextScan_clicked(self, search_for=None): global threadpool - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if not search_for: search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) @@ -1225,24 +1226,24 @@ def scan_callback(self): self.tableWidget_valuesearchtable.setRowCount(0) current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) length = self._scan_to_length(current_type) - mem_handle = GDB_Engine.memory_handle() + mem_handle = debugcore.memory_handle() row = 0 # go back to using n when unknown issue gets fixed for n, address, offset, region_type, val, result_type in matches: address = "0x" + address result = result_type.split(" ")[0] if result == "unknown": # Ignore unknown entries for now continue - value_index = type_defs.scanmem_result_to_index_dict[result] + value_index = typedefs.scanmem_result_to_index_dict[result] if self.checkBox_Hex.isChecked(): - value_repr = type_defs.VALUE_REPR.HEX - elif type_defs.VALUE_INDEX.is_integer(value_index) and result.endswith("s"): - value_repr = type_defs.VALUE_REPR.SIGNED + value_repr = typedefs.VALUE_REPR.HEX + elif typedefs.VALUE_INDEX.is_integer(value_index) and result.endswith("s"): + value_repr = typedefs.VALUE_REPR.SIGNED else: - value_repr = type_defs.VALUE_REPR.UNSIGNED + value_repr = typedefs.VALUE_REPR.UNSIGNED endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) current_item = QTableWidgetItem(address) current_item.setData(Qt.ItemDataRole.UserRole, (value_index, value_repr, endian)) - value = str(GDB_Engine.read_memory(address, value_index, length, True, value_repr, endian, mem_handle)) + value = str(debugcore.read_memory(address, value_index, length, True, value_repr, endian, mem_handle)) self.tableWidget_valuesearchtable.insertRow(row) self.tableWidget_valuesearchtable.setItem(row, SEARCH_TABLE_ADDRESS_COL, current_item) self.tableWidget_valuesearchtable.setItem(row, SEARCH_TABLE_VALUE_COL, QTableWidgetItem(value)) @@ -1253,9 +1254,9 @@ def scan_callback(self): self.QWidget_Toolbox.setEnabled(True) def _scan_to_length(self, type_index): - if type_index == type_defs.SCAN_INDEX.INDEX_AOB: + if type_index == typedefs.SCAN_INDEX.INDEX_AOB: return self.lineEdit_Scan.text().count(" ") + 1 - if type_index == type_defs.SCAN_INDEX.INDEX_STRING: + if type_index == typedefs.SCAN_INDEX.INDEX_STRING: return len(self.lineEdit_Scan.text()) return 0 @@ -1263,7 +1264,7 @@ def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) value_index, value_repr, endian = current_item.data(Qt.ItemDataRole.UserRole) length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) - vt = type_defs.ValueType(value_index, length, True, value_repr, endian) + vt = typedefs.ValueType(value_index, length, True, value_repr, endian) self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), vt) self.update_address_table() @@ -1278,7 +1279,7 @@ def comboBox_ValueType_current_index_changed(self): # array of bytes "string": None } - scanmem_type = type_defs.scan_index_to_scanmem_dict[current_type] + scanmem_type = typedefs.scan_index_to_scanmem_dict[current_type] validator_str = scanmem_type # used to get the correct validator # TODO this can probably be made to look nicer, though it doesn't really matter @@ -1302,13 +1303,13 @@ def pushButton_AttachProcess_clicked(self): self.processwindow.show() def pushButton_Open_clicked(self): - pct_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.CHEAT_TABLES_PATH) + pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES_PATH) file_paths = QFileDialog.getOpenFileNames(self, tr.OPEN_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_paths: return self.clear_address_table() for file_path in file_paths: - content = SysUtils.load_file(file_path) + content = utils.load_file(file_path) if content is None: QMessageBox.information(self, tr.ERROR, tr.FILE_LOAD_ERROR.format(file_path)) break @@ -1316,20 +1317,20 @@ def pushButton_Open_clicked(self): self.treeWidget_AddressTable.topLevelItemCount()) def pushButton_Save_clicked(self): - pct_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.CHEAT_TABLES_PATH) + pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES_PATH) file_path = QFileDialog.getSaveFileName(self, tr.SAVE_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_path: return content = [self.read_address_table_recursively(self.treeWidget_AddressTable.topLevelItem(i)) for i in range(self.treeWidget_AddressTable.topLevelItemCount())] - file_path = SysUtils.append_file_extension(file_path, "pct") - if not SysUtils.save_file(content, file_path): + file_path = utils.append_file_extension(file_path, "pct") + if not utils.save_file(content, file_path): QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) # Returns: a bool value indicates whether the operation succeeded. def attach_to_pid(self, pid): - attach_result = GDB_Engine.attach(pid, gdb_path) - if attach_result == type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL: + attach_result = debugcore.attach(pid, gdb_path) + if attach_result == typedefs.ATTACH_RESULT.ATTACH_SUCCESSFUL: self.apply_after_init() scanmem.pid(pid) self.on_new_process() @@ -1337,22 +1338,22 @@ def attach_to_pid(self, pid): # TODO: This makes PINCE call on_process_stop twice when attaching # TODO: Signal design might have to change to something like mutexes eventually self.memory_view_window.on_process_stop() - GDB_Engine.continue_inferior() + debugcore.continue_inferior() return True else: messages = { - type_defs.ATTACH_RESULT.ATTACH_SELF: tr.SMARTASS, # easter egg - type_defs.ATTACH_RESULT.PROCESS_NOT_VALID: tr.PROCESS_NOT_VALID, - type_defs.ATTACH_RESULT.ALREADY_DEBUGGING: tr.ALREADY_DEBUGGING, - type_defs.ATTACH_RESULT.ALREADY_TRACED: tr.ALREADY_TRACED.format(SysUtils.is_traced(pid)), - type_defs.ATTACH_RESULT.PERM_DENIED: tr.PERM_DENIED + typedefs.ATTACH_RESULT.ATTACH_SELF: tr.SMARTASS, # easter egg + typedefs.ATTACH_RESULT.PROCESS_NOT_VALID: tr.PROCESS_NOT_VALID, + typedefs.ATTACH_RESULT.ALREADY_DEBUGGING: tr.ALREADY_DEBUGGING, + typedefs.ATTACH_RESULT.ALREADY_TRACED: tr.ALREADY_TRACED.format(utils.is_traced(pid)), + typedefs.ATTACH_RESULT.PERM_DENIED: tr.PERM_DENIED } QMessageBox.information(app.focusWidget(), tr.ERROR, messages[attach_result]) return False # Returns: a bool value indicates whether the operation succeeded. def create_new_process(self, file_path, args, ld_preload_path): - if GDB_Engine.create_process(file_path, args, ld_preload_path): + if debugcore.create_process(file_path, args, ld_preload_path): self.apply_after_init() self.on_new_process() return True @@ -1363,8 +1364,8 @@ def create_new_process(self, file_path, args, ld_preload_path): # Changes appearance whenever a new process is created or attached def on_new_process(self): - name = SysUtils.get_process_name(GDB_Engine.currentpid) - self.label_SelectedProcess.setText(str(GDB_Engine.currentpid) + " - " + name) + name = utils.get_process_name(debugcore.currentpid) + self.label_SelectedProcess.setText(str(debugcore.currentpid) + " - " + name) # enable scan GUI self.lineEdit_Scan.setPlaceholderText(tr.SCAN_FOR) @@ -1391,12 +1392,12 @@ def copy_to_address_table(self): i = i + 1 if i % 3 == 0: value_index, value_repr, endian = row.data(Qt.ItemDataRole.UserRole) - vt = type_defs.ValueType(value_index, length, True, value_repr, endian) + vt = typedefs.ValueType(value_index, length, True, value_repr, endian) self.add_entry_to_addresstable(tr.NO_DESCRIPTION, row.text(), vt) self.update_address_table() def reset_scan(self): - self.scan_mode = type_defs.SCAN_MODE.NEW + self.scan_mode = typedefs.SCAN_MODE.NEW self.pushButton_NewFirstScan.setText(tr.FIRST_SCAN) scanmem.reset() self.tableWidget_valuesearchtable.setRowCount(0) @@ -1415,7 +1416,7 @@ def on_inferior_exit(self): self.lineEdit_Scan.setText("") self.reset_scan() self.on_status_running() - GDB_Engine.init_gdb(gdb_path) + debugcore.init_gdb(gdb_path) self.apply_after_init() self.flashAttachButton = True self.flashAttachButtonTimer.start(100) @@ -1440,16 +1441,16 @@ def on_status_running(self): # closes all windows on exit def closeEvent(self, event): - GDB_Engine.detach() + debugcore.detach() app.closeAllWindows() # Call update_address_table manually after this def add_entry_to_addresstable(self, description, address_expr, value_type=None): current_row = QTreeWidgetItem() current_row.setCheckState(FROZEN_COL, Qt.CheckState.Unchecked) - frozen = type_defs.Frozen("", type_defs.FREEZE_TYPE.DEFAULT) + frozen = typedefs.Frozen("", typedefs.FREEZE_TYPE.DEFAULT) current_row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) - value_type = type_defs.ValueType() if not value_type else value_type + value_type = typedefs.ValueType() if not value_type else value_type self.treeWidget_AddressTable.addTopLevelItem(current_row) self.change_address_table_entries(current_row, description, address_expr, value_type) self.show() # In case of getting called from elsewhere @@ -1500,18 +1501,18 @@ def freeze_loop(self): # ---------------------------------------------------- def update_search_table(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return row_count = self.tableWidget_valuesearchtable.rowCount() if row_count > 0: length = self._scan_to_length(self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole)) - mem_handle = GDB_Engine.memory_handle() + mem_handle = debugcore.memory_handle() for row_index in range(row_count): address_item = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_ADDRESS_COL) previous_text = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_PREVIOUS_COL).text() value_index, value_repr, endian = address_item.data(Qt.ItemDataRole.UserRole) address = address_item.text() - new_value = str(GDB_Engine.read_memory(address, value_index, length, value_repr=value_repr, + new_value = str(debugcore.read_memory(address, value_index, length, value_repr=value_repr, endian=endian, mem_handle=mem_handle)) value_item = QTableWidgetItem(new_value) if new_value != previous_text: @@ -1519,7 +1520,7 @@ def update_search_table(self): self.tableWidget_valuesearchtable.setItem(row_index, SEARCH_TABLE_VALUE_COL, value_item) def freeze(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) while it.value(): @@ -1530,15 +1531,15 @@ def freeze(self): frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) value = frozen.value freeze_type = frozen.freeze_type - if type_defs.VALUE_INDEX.is_integer(vt.value_index): - new_value = GDB_Engine.read_memory(address, vt.value_index, endian=vt.endian) + if typedefs.VALUE_INDEX.is_integer(vt.value_index): + new_value = debugcore.read_memory(address, vt.value_index, endian=vt.endian) new_value = int(new_value, 0) if isinstance(new_value, str) else new_value - if freeze_type == type_defs.FREEZE_TYPE.INCREMENT and new_value > int(value, 0) or \ - freeze_type == type_defs.FREEZE_TYPE.DECREMENT and new_value < int(value, 0): + if freeze_type == typedefs.FREEZE_TYPE.INCREMENT and new_value > int(value, 0) or \ + freeze_type == typedefs.FREEZE_TYPE.DECREMENT and new_value < int(value, 0): frozen.value = str(new_value) - GDB_Engine.write_memory(address, vt.value_index, frozen.value, vt.endian) + debugcore.write_memory(address, vt.value_index, frozen.value, vt.endian) continue - GDB_Engine.write_memory(address, vt.value_index, value, vt.endian) + debugcore.write_memory(address, vt.value_index, value, vt.endian) it += 1 def treeWidget_AddressTable_item_clicked(self, row, column): @@ -1570,15 +1571,15 @@ def treeWidget_AddressTable_edit_value(self): for row in self.treeWidget_AddressTable.selectedItems(): address = row.text(ADDR_COL).strip("P->") value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - if type_defs.VALUE_INDEX.has_length(value_type.value_index): - unknown_type = SysUtils.parse_string(new_value, value_type.value_index) + if typedefs.VALUE_INDEX.has_length(value_type.value_index): + unknown_type = utils.parse_string(new_value, value_type.value_index) if unknown_type is not None: value_type.length = len(unknown_type) row.setText(TYPE_COL, value_type.text()) frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) frozen.value = new_value row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) - GDB_Engine.write_memory(address, value_type.value_index, new_value, value_type.endian) + debugcore.write_memory(address, value_type.value_index, new_value, value_type.endian) self.update_address_table() def treeWidget_AddressTable_edit_desc(self): @@ -1630,7 +1631,7 @@ def read_address_table_entries(self, row, serialize=False): description = row.text(DESC_COL) if serialize: address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, type_defs.PointerType): + if isinstance(address_data, typedefs.PointerType): address_expr = address_data.serialize() else: address_expr = address_data @@ -1673,7 +1674,7 @@ def __init__(self, parent=None): super().__init__(parent=parent) self.setupUi(self) guiutils.center_to_parent(self) - self.refresh_process_table(self.tableWidget_ProcessTable, SysUtils.get_process_list()) + self.refresh_process_table(self.tableWidget_ProcessTable, utils.get_process_list()) self.pushButton_Close.clicked.connect(self.close) self.pushButton_Open.clicked.connect(self.pushButton_Open_clicked) self.pushButton_CreateProcess.clicked.connect(self.pushButton_CreateProcess_clicked) @@ -1683,7 +1684,7 @@ def __init__(self, parent=None): # refreshes process list def generate_new_list(self): text = self.lineEdit_SearchProcess.text() - processlist = SysUtils.search_processes(text) + processlist = utils.search_processes(text) self.refresh_process_table(self.tableWidget_ProcessTable, processlist) def keyPressEvent(self, e): @@ -1740,13 +1741,13 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val super().__init__(parent=parent) self.setupUi(self) self.setMaximumSize(100, 100) - vt = type_defs.ValueType() if not value_type else value_type + vt = typedefs.ValueType() if not value_type else value_type self.lineEdit_Length.setValidator(QHexValidator(99, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) self.lineEdit_Description.setText(description) self.offsetsList = [] - if not isinstance(address, type_defs.PointerType): + if not isinstance(address, typedefs.PointerType): self.lineEdit_Address.setText(address) self.widget_Pointer.hide() else: @@ -1755,7 +1756,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val self.lineEdit_PtrStartAddress.setText(address.get_base_address()) self.create_offsets_list(address) self.widget_Pointer.show() - if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): + if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() try: length = str(length) @@ -1764,7 +1765,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.show() self.checkBox_ZeroTerminate.setChecked(vt.zero_terminate) - elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: self.widget_Length.show() try: length = str(length) @@ -1774,10 +1775,10 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val self.checkBox_ZeroTerminate.hide() else: self.widget_Length.hide() - if vt.value_repr == type_defs.VALUE_REPR.HEX: + if vt.value_repr == typedefs.VALUE_REPR.HEX: self.checkBox_Hex.setChecked(True) self.checkBox_Signed.setEnabled(False) - elif vt.value_repr == type_defs.VALUE_REPR.SIGNED: + elif vt.value_repr == typedefs.VALUE_REPR.SIGNED: self.checkBox_Signed.setChecked(True) else: self.checkBox_Signed.setChecked(False) @@ -1844,36 +1845,36 @@ def removeOffsetLayout(self): def update_value(self): if self.checkBox_IsPointer.isChecked(): - pointer_type = type_defs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) - address = GDB_Engine.read_pointer(pointer_type) + pointer_type = typedefs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) + address = debugcore.read_pointer(pointer_type) if address != None: address_text = hex(address) else: address_text = "??" self.lineEdit_Address.setText(address_text) else: - address = GDB_Engine.examine_expression(self.lineEdit_Address.text()).address + address = debugcore.examine_expression(self.lineEdit_Address.text()).address if not address: self.label_Value.setText("??") return if self.checkBox_Hex.isChecked(): - value_repr = type_defs.VALUE_REPR.HEX + value_repr = typedefs.VALUE_REPR.HEX elif self.checkBox_Signed.isChecked(): - value_repr = type_defs.VALUE_REPR.SIGNED + value_repr = typedefs.VALUE_REPR.SIGNED else: - value_repr = type_defs.VALUE_REPR.UNSIGNED + value_repr = typedefs.VALUE_REPR.UNSIGNED address_type = self.comboBox_ValueType.currentIndex() length = self.lineEdit_Length.text() zero_terminate = self.checkBox_ZeroTerminate.isChecked() endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) - value = GDB_Engine.read_memory(address, address_type, length, zero_terminate, value_repr, endian) + value = debugcore.read_memory(address, address_type, length, zero_terminate, value_repr, endian) self.label_Value.setText("??" if value is None else str(value)) def comboBox_ValueType_current_index_changed(self): - if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): + if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() self.checkBox_ZeroTerminate.show() - elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: self.widget_Length.show() self.checkBox_ZeroTerminate.hide() else: @@ -1928,15 +1929,15 @@ def get_values(self): zero_terminate = self.checkBox_ZeroTerminate.isChecked() value_index = self.comboBox_ValueType.currentIndex() if self.checkBox_Hex.isChecked(): - value_repr = type_defs.VALUE_REPR.HEX + value_repr = typedefs.VALUE_REPR.HEX elif self.checkBox_Signed.isChecked(): - value_repr = type_defs.VALUE_REPR.SIGNED + value_repr = typedefs.VALUE_REPR.SIGNED else: - value_repr = type_defs.VALUE_REPR.UNSIGNED + value_repr = typedefs.VALUE_REPR.UNSIGNED endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) - vt = type_defs.ValueType(value_index, length, zero_terminate, value_repr, endian) + vt = typedefs.ValueType(value_index, length, zero_terminate, value_repr, endian) if self.checkBox_IsPointer.isChecked(): - address = type_defs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) + address = typedefs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) return description, address, vt def get_offsets_int_list(self): @@ -1951,7 +1952,7 @@ def get_offsets_int_list(self): return offsetsIntList def create_offsets_list(self, address): - if not isinstance(address, type_defs.PointerType): + if not isinstance(address, typedefs.PointerType): raise TypeError("Passed non-pointer type to create_offsets_list!") for offset in address.offsets_list: @@ -1965,7 +1966,7 @@ def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): offsetValue = int(offsetText, 16) except ValueError: offsetValue = 0 - sizeVal = type_defs.index_to_valuetype_dict[self.comboBox_ValueType.currentIndex()][0] + sizeVal = typedefs.index_to_valuetype_dict[self.comboBox_ValueType.currentIndex()][0] offsetValue = operator_func(offsetValue, sizeVal) offsetTextWidget.setText(hex(offsetValue)) @@ -1974,12 +1975,12 @@ class EditTypeDialogForm(QDialog, EditTypeDialog): def __init__(self, parent=None, value_type=None): super().__init__(parent=parent) self.setupUi(self) - vt = type_defs.ValueType() if not value_type else value_type + vt = typedefs.ValueType() if not value_type else value_type self.setMaximumSize(100, 100) self.lineEdit_Length.setValidator(QHexValidator(99, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) - if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): + if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() try: length = str(length) @@ -1988,7 +1989,7 @@ def __init__(self, parent=None, value_type=None): self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.show() self.checkBox_ZeroTerminate.setChecked(vt.zero_terminate) - elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: self.widget_Length.show() try: length = str(length) @@ -1998,10 +1999,10 @@ def __init__(self, parent=None, value_type=None): self.checkBox_ZeroTerminate.hide() else: self.widget_Length.hide() - if vt.value_repr == type_defs.VALUE_REPR.HEX: + if vt.value_repr == typedefs.VALUE_REPR.HEX: self.checkBox_Hex.setChecked(True) self.checkBox_Signed.setEnabled(False) - elif vt.value_repr == type_defs.VALUE_REPR.SIGNED: + elif vt.value_repr == typedefs.VALUE_REPR.SIGNED: self.checkBox_Signed.setChecked(True) else: self.checkBox_Signed.setChecked(False) @@ -2009,10 +2010,10 @@ def __init__(self, parent=None, value_type=None): self.checkBox_Hex.stateChanged.connect(self.repr_changed) def comboBox_ValueType_current_index_changed(self): - if type_defs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): + if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() self.checkBox_ZeroTerminate.show() - elif self.comboBox_ValueType.currentIndex() == type_defs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: self.widget_Length.show() self.checkBox_ZeroTerminate.hide() else: @@ -2049,13 +2050,13 @@ def get_values(self): length = 0 zero_terminate = self.checkBox_ZeroTerminate.isChecked() if self.checkBox_Hex.isChecked(): - value_repr = type_defs.VALUE_REPR.HEX + value_repr = typedefs.VALUE_REPR.HEX elif self.checkBox_Signed.isChecked(): - value_repr = type_defs.VALUE_REPR.SIGNED + value_repr = typedefs.VALUE_REPR.SIGNED else: - value_repr = type_defs.VALUE_REPR.UNSIGNED + value_repr = typedefs.VALUE_REPR.UNSIGNED endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) - return type_defs.ValueType(value_index, length, zero_terminate, value_repr, endian) + return typedefs.ValueType(value_index, length, zero_terminate, value_repr, endian) class TrackSelectorDialogForm(QDialog, TrackSelectorDialog): @@ -2088,7 +2089,7 @@ def __init__(self, parent=None): self.background_thread = self.BackgroundThread() self.background_thread.output_ready.connect(self.accept) self.pushButton_Cancel.clicked.connect(self.cancel_thread) - media_directory = SysUtils.get_media_directory() + media_directory = utils.get_media_directory() self.movie = QMovie(media_directory + "/LoadingDialog/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) self.movie.setScaledSize(QSize(25, 25)) @@ -2099,7 +2100,7 @@ def __init__(self, parent=None): # 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() + debugcore.cancel_last_command() def exec(self): self.background_thread.start() @@ -2133,7 +2134,7 @@ class InputDialogForm(QDialog, InputDialog): # that points the current index of the QComboBox, for instance: ["0", "1", 1] will create a QCombobox with the items # "0" and "1" then will set current index to 1 (which is the item "1") # label_alignment is optional - def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=type_defs.VALUE_INDEX.INDEX_INT32, + def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typedefs.VALUE_INDEX.INDEX_INT32, buttons=(QDialogButtonBox.StandardButton.Ok, QDialogButtonBox.StandardButton.Cancel)): super().__init__(parent=parent) self.setupUi(self) @@ -2194,7 +2195,7 @@ def get_values(self): def accept(self): if self.parsed_index != -1: item = self.object_list[self.parsed_index] - if SysUtils.parse_string(self.get_text(item), self.value_index) is None: + if utils.parse_string(self.get_text(item), self.value_index) is None: QMessageBox.information(self, tr.ERROR, tr.PARSE_ERROR) return super(InputDialogForm, self).accept() @@ -2275,7 +2276,7 @@ def accept(self): if self.checkBox_AutoUpdateAddressTable.isChecked(): self.settings.setValue("General/address_table_update_interval", current_table_update_interval) self.settings.setValue("General/freeze_interval", current_freeze_interval) - current_gdb_output_mode = type_defs.gdb_output_mode(self.checkBox_OutputModeAsync.isChecked(), + current_gdb_output_mode = typedefs.gdb_output_mode(self.checkBox_OutputModeAsync.isChecked(), self.checkBox_OutputModeCommand.isChecked(), self.checkBox_OutputModeCommandInfo.isChecked()) self.settings.setValue("General/gdb_output_mode", current_gdb_output_mode) @@ -2295,9 +2296,9 @@ def accept(self): for hotkey in Hotkeys.get_hotkeys(): self.settings.setValue("Hotkeys/" + hotkey.name, self.hotkey_to_value[hotkey.name]) if self.radioButton_SimpleDLopenCall.isChecked(): - injection_method = type_defs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL + injection_method = typedefs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL elif self.radioButton_AdvancedInjection.isChecked(): - injection_method = type_defs.INJECTION_METHOD.ADVANCED_INJECTION + injection_method = typedefs.INJECTION_METHOD.ADVANCED_INJECTION self.settings.setValue("CodeInjection/code_injection_method", injection_method) self.settings.setValue("Disassemble/bring_disassemble_to_front", self.checkBox_BringDisassembleToFront.isChecked()) @@ -2306,7 +2307,7 @@ def accept(self): current_gdb_path = self.settings.value("Debug/gdb_path", type=str) if selected_gdb_path != current_gdb_path: if InputDialogForm(item_list=[(tr.GDB_RESET,)]).exec(): - GDB_Engine.init_gdb(selected_gdb_path) + debugcore.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) if self.handle_signals_data is not None: @@ -2330,8 +2331,8 @@ def config_gui(self): self.comboBox_Language.addItem(lang) if loc == cur_loc: self.comboBox_Language.setCurrentIndex(self.comboBox_Language.count()-1) - logo_directory = SysUtils.get_logo_directory() - logo_list = SysUtils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") + logo_directory = utils.get_logo_directory() + logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") self.comboBox_Logo.clear() for logo in logo_list: self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) @@ -2342,9 +2343,9 @@ def config_gui(self): self.listWidget_Functions.addItem(hotkey.desc) self.hotkey_to_value[hotkey.name] = self.settings.value("Hotkeys/" + hotkey.name) injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) - if injection_method == type_defs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL: + if injection_method == typedefs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL: self.radioButton_SimpleDLopenCall.setChecked(True) - elif injection_method == type_defs.INJECTION_METHOD.ADVANCED_INJECTION: + elif injection_method == typedefs.INJECTION_METHOD.ADVANCED_INJECTION: self.radioButton_AdvancedInjection.setChecked(True) self.checkBox_BringDisassembleToFront.setChecked( self.settings.value("Disassemble/bring_disassemble_to_front", type=bool)) @@ -2491,9 +2492,9 @@ def communicate(self): console_output = tr.CONT_SESSION_CRASH else: if self.radioButton_CLI.isChecked(): - console_output = GDB_Engine.send_command(console_input, cli_output=True) + console_output = debugcore.send_command(console_input, cli_output=True) else: - console_output = GDB_Engine.send_command(console_input) + console_output = debugcore.send_command(console_input) self.textBrowser.append("-->" + console_input) if console_output: self.textBrowser.append(console_output) @@ -2536,7 +2537,7 @@ def scroll_forwards_history(self): self.lineEdit.setText(self.input_history[self.current_history_index]) def lineEdit_key_press_event(self, event): - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), self.scroll_backwards_history), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), self.scroll_forwards_history) ]) @@ -2549,8 +2550,8 @@ def finish_completion(self): self.completion_model.setStringList([]) def complete_command(self): - if GDB_Engine.gdb_initialized and GDB_Engine.currentpid != -1 and self.lineEdit.text(): - self.completion_model.setStringList(GDB_Engine.complete_command(self.lineEdit.text())) + if debugcore.gdb_initialized and debugcore.currentpid != -1 and self.lineEdit.text(): + self.completion_model.setStringList(debugcore.complete_command(self.lineEdit.text())) self.completer.complete() else: self.finish_completion() @@ -2610,8 +2611,8 @@ def initialize_file_context_menu(self): self.actionLoad_Trace.triggered.connect(self.show_trace_window) def initialize_debug_context_menu(self): - self.actionBreak.triggered.connect(GDB_Engine.interrupt_inferior) - self.actionRun.triggered.connect(GDB_Engine.continue_inferior) + self.actionBreak.triggered.connect(debugcore.interrupt_inferior) + self.actionRun.triggered.connect(debugcore.continue_inferior) self.actionToggle_Attach.triggered.connect(lambda: self.parent().toggle_attach_hotkey_pressed()) self.actionStep.triggered.connect(self.step_instruction) self.actionStep_Over.triggered.connect(self.step_over_instruction) @@ -2721,7 +2722,7 @@ def initialize_disassemble_view(self): def initialize_hex_view(self): self.hex_view_last_selected_address_int = 0 - self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) + self.hex_view_current_region = typedefs.tuple_region_info(0, 0, None, None) self.widget_HexView.wheelEvent = self.widget_HexView_wheel_event # Saving the original function because super() doesn't work when we override functions like this @@ -2765,94 +2766,94 @@ def initialize_hex_view(self): guiutils.center_scroll_bar(self.verticalScrollBar_HexView) def show_trace_window(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return TraceInstructionsWindowForm(prompt_dialog=False) def step_instruction(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if self.updating_memoryview: return - GDB_Engine.step_instruction() + debugcore.step_instruction() def step_over_instruction(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if self.updating_memoryview: return - GDB_Engine.step_over_instruction() + debugcore.step_over_instruction() def execute_till_return(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if self.updating_memoryview: return - GDB_Engine.execute_till_return() + debugcore.execute_till_return() def set_address(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) - GDB_Engine.set_convenience_variable("pc", current_address) + current_address = utils.extract_address(current_address_text) + debugcore.set_convenience_variable("pc", current_address) self.refresh_disassemble_view() def edit_instruction(self): selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) bytes_aob = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() EditInstructionDialogForm(current_address, bytes_aob, self).exec() def nop_instruction(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) array_of_bytes = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() - GDB_Engine.nop_instruction(current_address_int, len(array_of_bytes.split())) + debugcore.nop_instruction(current_address_int, len(array_of_bytes.split())) self.refresh_disassemble_view() def toggle_breakpoint(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) - if GDB_Engine.check_address_in_breakpoints(current_address_int): - GDB_Engine.delete_breakpoint(current_address) + if debugcore.check_address_in_breakpoints(current_address_int): + debugcore.delete_breakpoint(current_address) else: - if not GDB_Engine.add_breakpoint(current_address): + if not debugcore.add_breakpoint(current_address): QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_FAILED.format(current_address)) self.refresh_disassemble_view() - def toggle_watchpoint(self, address, watchpoint_type=type_defs.WATCHPOINT_TYPE.BOTH): - if GDB_Engine.currentpid == -1: + def toggle_watchpoint(self, address, watchpoint_type=typedefs.WATCHPOINT_TYPE.BOTH): + if debugcore.currentpid == -1: return - if GDB_Engine.check_address_in_breakpoints(address): - GDB_Engine.delete_breakpoint(hex(address)) + if debugcore.check_address_in_breakpoints(address): + debugcore.delete_breakpoint(hex(address)) else: watchpoint_dialog = InputDialogForm(item_list=[(tr.ENTER_WATCHPOINT_LENGTH, "")]) if watchpoint_dialog.exec(): user_input = watchpoint_dialog.get_values() - user_input_int = SysUtils.parse_string(user_input, type_defs.VALUE_INDEX.INDEX_INT32) + user_input_int = utils.parse_string(user_input, typedefs.VALUE_INDEX.INDEX_INT32) if user_input_int is None: QMessageBox.information(self, tr.ERROR, tr.PARSE_ERROR_INT.format(user_input)) return if user_input_int < 1: QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_ASSERT_LT.format(1)) return - if len(GDB_Engine.add_watchpoint(hex(address), user_input_int, watchpoint_type)) < 1: + if len(debugcore.add_watchpoint(hex(address), user_input_int, watchpoint_type)) < 1: QMessageBox.information(self, tr.ERROR, tr.WATCHPOINT_FAILED.format(hex(address))) self.refresh_hex_view() def label_HexView_Information_context_menu_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return def copy_to_clipboard(): @@ -2872,7 +2873,7 @@ def copy_to_clipboard(): pass def widget_HexView_context_menu_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_address = self.tableView_HexView_Hex.get_selected_address() menu = QMenu() @@ -2891,7 +2892,7 @@ def widget_HexView_context_menu_event(self, event): watchpoint_both = watchpoint_menu.addAction(tr.BOTH) add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) delete_breakpoint = menu.addAction(tr.DELETE_BREAKPOINT) - if not GDB_Engine.check_address_in_breakpoints(selected_address): + if not debugcore.check_address_in_breakpoints(selected_address): guiutils.delete_menu_entries(menu, [add_condition, delete_breakpoint]) else: guiutils.delete_menu_entries(menu, [watchpoint_menu.menuAction()]) @@ -2904,9 +2905,9 @@ def widget_HexView_context_menu_event(self, event): disassemble: lambda: self.disassemble_expression(hex(selected_address), append_to_travel_history=True), add_address: self.exec_hex_view_add_address_dialog, refresh: self.refresh_hex_view, - watchpoint_write: lambda: self.toggle_watchpoint(selected_address, type_defs.WATCHPOINT_TYPE.WRITE_ONLY), - watchpoint_read: lambda: self.toggle_watchpoint(selected_address, type_defs.WATCHPOINT_TYPE.READ_ONLY), - watchpoint_both: lambda: self.toggle_watchpoint(selected_address, type_defs.WATCHPOINT_TYPE.BOTH), + watchpoint_write: lambda: self.toggle_watchpoint(selected_address, typedefs.WATCHPOINT_TYPE.WRITE_ONLY), + watchpoint_read: lambda: self.toggle_watchpoint(selected_address, typedefs.WATCHPOINT_TYPE.READ_ONLY), + watchpoint_both: lambda: self.toggle_watchpoint(selected_address, typedefs.WATCHPOINT_TYPE.BOTH), add_condition: lambda: self.add_breakpoint_condition(selected_address), delete_breakpoint: lambda: self.toggle_watchpoint(selected_address) } @@ -2916,30 +2917,30 @@ def widget_HexView_context_menu_event(self, event): pass def exec_hex_view_edit_dialog(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_address = self.tableView_HexView_Hex.get_selected_address() HexEditDialogForm(hex(selected_address)).exec() self.refresh_hex_view() def exec_hex_view_go_to_dialog(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return current_address = hex(self.tableView_HexView_Hex.get_selected_address()) go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, current_address)]) if go_to_dialog.exec(): expression = go_to_dialog.get_values() - dest_address = GDB_Engine.examine_expression(expression).address + dest_address = debugcore.examine_expression(expression).address if not dest_address: QMessageBox.information(self, tr.ERROR, tr.INVALID.format(expression)) return self.hex_dump_address(int(dest_address, 16)) def exec_hex_view_add_address_dialog(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_address = self.tableView_HexView_Hex.get_selected_address() - vt = type_defs.ValueType(type_defs.VALUE_INDEX.INDEX_AOB) + vt = typedefs.ValueType(typedefs.VALUE_INDEX.INDEX_AOB) manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), value_type=vt) if manual_address_dialog.exec(): desc, address, vt = manual_address_dialog.get_values() @@ -2997,7 +2998,7 @@ def disassemble_scrollbar_sliderchanged(self, even): self.bDisassemblyScrolling = False def on_hex_view_current_changed(self, QModelIndex_current): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.tableView_HexView_Ascii.selectionModel().setCurrentIndex(QModelIndex_current, @@ -3007,7 +3008,7 @@ def on_hex_view_current_changed(self, QModelIndex_current): self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) def on_ascii_view_current_changed(self, QModelIndex_current): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.tableView_HexView_Hex.selectionModel().setCurrentIndex(QModelIndex_current, @@ -3019,33 +3020,33 @@ def on_ascii_view_current_changed(self, QModelIndex_current): # TODO: Move this function to that class if that happens # TODO: Also consider moving shared fields of HexView and HexModel to that class(such as HexModel.current_address) def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return - int_address = SysUtils.modulo_address(int_address, GDB_Engine.inferior_arch) + int_address = utils.modulo_address(int_address, debugcore.inferior_arch) if not (self.hex_view_current_region.start <= int_address < self.hex_view_current_region.end): - info = SysUtils.get_region_info(GDB_Engine.currentpid, int_address) + info = utils.get_region_info(debugcore.currentpid, int_address) if info: self.hex_view_current_region = info self.label_HexView_Information.setText(tr.REGION_INFO.format( info.perms, hex(info.start), hex(info.end), info.file_name)) else: - self.hex_view_current_region = type_defs.tuple_region_info(0, 0, None, None) + self.hex_view_current_region = typedefs.tuple_region_info(0, 0, None, None) self.label_HexView_Information.setText(tr.INVALID_REGION) self.tableWidget_HexView_Address.setRowCount(0) self.tableWidget_HexView_Address.setRowCount(HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT) for row, current_offset in enumerate(range(HEX_VIEW_ROW_COUNT)): - row_address = hex(SysUtils.modulo_address(int_address + current_offset * 16, GDB_Engine.inferior_arch)) + row_address = hex(utils.modulo_address(int_address + current_offset * 16, debugcore.inferior_arch)) self.tableWidget_HexView_Address.setItem(row, 0, QTableWidgetItem(row_address)) tableWidget_HexView_column_size = self.tableWidget_HexView_Address.sizeHintForColumn(0) + 5 self.tableWidget_HexView_Address.setMaximumWidth(tableWidget_HexView_column_size) self.tableWidget_HexView_Address.setMinimumWidth(tableWidget_HexView_column_size) self.tableWidget_HexView_Address.setColumnWidth(0, tableWidget_HexView_column_size) - data_array = GDB_Engine.hex_dump(int_address, offset) - breakpoint_info = GDB_Engine.get_breakpoint_info() + data_array = debugcore.hex_dump(int_address, offset) + breakpoint_info = debugcore.get_breakpoint_info() self.hex_model.refresh(int_address, offset, data_array, breakpoint_info) self.ascii_model.refresh(int_address, offset, data_array, breakpoint_info) for index in range(offset): - current_address = SysUtils.modulo_address(self.hex_model.current_address + index, GDB_Engine.inferior_arch) + current_address = utils.modulo_address(self.hex_model.current_address + index, debugcore.inferior_arch) if current_address == self.hex_view_last_selected_address_int: row_index = int(index / HEX_VIEW_COL_COUNT) model_index = QModelIndex(self.hex_model.index(row_index, index % HEX_VIEW_COL_COUNT)) @@ -3062,10 +3063,10 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL self.tableView_HexView_Ascii.clearSelection() def refresh_hex_view(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if self.tableWidget_HexView_Address.rowCount() == 0: - entry_point = GDB_Engine.find_entry_point() + entry_point = debugcore.find_entry_point() if not entry_point: # **Shrugs** entry_point = "0x00400000" @@ -3078,31 +3079,31 @@ def refresh_hex_view(self): # offset can also be an address as hex str # returns True if the given expression is disassembled correctly, False if not def disassemble_expression(self, expression, offset="+200", append_to_travel_history=False): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return - disas_data = GDB_Engine.disassemble(expression, offset) + disas_data = debugcore.disassemble(expression, offset) if not disas_data: QMessageBox.information(app.focusWidget(), tr.ERROR, tr.EXPRESSION_ACCESS_ERROR.format(expression)) return False - program_counter = GDB_Engine.examine_expression("$pc").address + program_counter = debugcore.examine_expression("$pc").address program_counter_int = int(program_counter, 16) if program_counter else None row_color = {} - breakpoint_info = GDB_Engine.get_breakpoint_info() + breakpoint_info = debugcore.get_breakpoint_info() # TODO: Change this nonsense when the huge refactorization happens - current_first_address = SysUtils.extract_address(disas_data[0][0]) # address of first list entry + current_first_address = utils.extract_address(disas_data[0][0]) # address of first list entry try: - previous_first_address = SysUtils.extract_address( + previous_first_address = utils.extract_address( self.tableWidget_Disassemble.item(0, DISAS_ADDR_COL).text()) except AttributeError: previous_first_address = current_first_address self.tableWidget_Disassemble.setRowCount(0) self.tableWidget_Disassemble.setRowCount(len(disas_data)) - jmp_dict, call_dict = GDB_Engine.get_dissect_code_data(False, True, True) + jmp_dict, call_dict = debugcore.get_dissect_code_data(False, True, True) for row, (address_info, bytes_aob, opcode) in enumerate(disas_data): comment = "" - current_address = int(SysUtils.extract_address(address_info), 16) + current_address = int(utils.extract_address(address_info), 16) current_address_str = hex(current_address) jmp_ref_exists = False call_ref_exists = False @@ -3204,13 +3205,13 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his return True def refresh_disassemble_view(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return self.disassemble_expression(self.disassemble_currently_displayed_address) # Set color of a row if a specific address is encountered(e.g $pc, a bookmarked address etc.) def handle_colors(self, row_color): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return for row in row_color: current_row = row_color[row] @@ -3237,7 +3238,7 @@ def handle_colors(self, row_color): self.set_row_color(row, REF_COLOR) def set_row_color(self, row, color): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return for col in range(self.tableWidget_Disassemble.columnCount()): color = QColor(color) @@ -3245,12 +3246,12 @@ def set_row_color(self, row, color): self.tableWidget_Disassemble.item(row, col).setData(Qt.ItemDataRole.BackgroundRole, color) def on_process_stop(self): - if GDB_Engine.stop_reason == type_defs.STOP_REASON.PAUSE: + if debugcore.stop_reason == typedefs.STOP_REASON.PAUSE: self.setWindowTitle(tr.MV_PAUSED) return self.updating_memoryview = True time0 = time() - self.setWindowTitle(tr.MV_DEBUGGING.format(GDB_Engine.get_thread_info())) + self.setWindowTitle(tr.MV_DEBUGGING.format(debugcore.get_thread_info())) self.disassemble_expression("$pc") self.update_registers() if self.stackedWidget_StackScreens.currentWidget() == self.StackTrace: @@ -3286,9 +3287,9 @@ def on_process_running(self): self.setWindowTitle(tr.MV_RUNNING) def add_breakpoint_condition(self, int_address): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return - breakpoint = GDB_Engine.check_address_in_breakpoints(int_address) + breakpoint = debugcore.check_address_in_breakpoints(int_address) if breakpoint: condition_line_edit_text = breakpoint.condition else: @@ -3297,15 +3298,15 @@ def add_breakpoint_condition(self, int_address): item_list=[(tr.ENTER_BP_CONDITION, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) if condition_dialog.exec(): condition = condition_dialog.get_values() - if not GDB_Engine.modify_breakpoint(hex(int_address), type_defs.BREAKPOINT_MODIFY.CONDITION, + if not debugcore.modify_breakpoint(hex(int_address), typedefs.BREAKPOINT_MODIFY.CONDITION, condition=condition): QMessageBox.information(app.focusWidget(), tr.ERROR, tr.BP_CONDITION_FAILED.format(hex(int_address))) def update_registers(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return - registers = GDB_Engine.read_registers() - if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64: + registers = debugcore.read_registers() + if debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64: self.stackedWidget.setCurrentWidget(self.registers_64) self.RAX.set_value(registers["rax"]) self.RBX.set_value(registers["rbx"]) @@ -3324,7 +3325,7 @@ def update_registers(self): self.R13.set_value(registers["r13"]) self.R14.set_value(registers["r14"]) self.R15.set_value(registers["r15"]) - elif GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_32: + elif debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_32: self.stackedWidget.setCurrentWidget(self.registers_32) self.EAX.set_value(registers["eax"]) self.EBX.set_value(registers["ebx"]) @@ -3352,9 +3353,9 @@ def update_registers(self): self.FS.set_value(registers["fs"]) def update_stacktrace(self): - if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: return - stack_trace_info = GDB_Engine.get_stacktrace_info() + stack_trace_info = debugcore.get_stacktrace_info() self.tableWidget_StackTrace.setRowCount(0) self.tableWidget_StackTrace.setRowCount(len(stack_trace_info)) for row, item in enumerate(stack_trace_info): @@ -3362,7 +3363,7 @@ def update_stacktrace(self): self.tableWidget_StackTrace.setItem(row, STACKTRACE_FRAME_ADDRESS_COL, QTableWidgetItem(item[1])) def set_stack_widget(self, stack_widget): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return self.stackedWidget_StackScreens.setCurrentWidget(stack_widget) if stack_widget == self.Stack: @@ -3371,7 +3372,7 @@ def set_stack_widget(self, stack_widget): self.update_stacktrace() def tableWidget_StackTrace_context_menu_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return def copy_to_clipboard(row, column): @@ -3403,9 +3404,9 @@ def copy_to_clipboard(row, column): pass def update_stack(self): - if GDB_Engine.currentpid == -1 or GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: return - stack_info = GDB_Engine.get_stack_info() + stack_info = debugcore.get_stack_info() self.tableWidget_Stack.setRowCount(0) self.tableWidget_Stack.setRowCount(len(stack_info)) for row, item in enumerate(stack_info): @@ -3416,18 +3417,18 @@ def update_stack(self): self.tableWidget_Stack.resizeColumnToContents(STACK_VALUE_COL) def tableWidget_Stack_key_press_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Stack) if selected_row == -1: - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack) ]) else: current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), lambda: self.disassemble_expression(current_address, append_to_travel_history=True)), @@ -3444,14 +3445,14 @@ def tableWidget_Stack_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_Stack.item(row, column).text()) - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Stack) if selected_row == -1: current_address = None else: current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) menu = QMenu() switch_to_stacktrace = menu.addAction(tr.STACKTRACE) menu.addSeparator() @@ -3483,39 +3484,39 @@ def copy_to_clipboard(row, column): pass def tableWidget_Stack_double_click(self, index): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Stack) if index.column() == STACK_POINTER_ADDRESS_COL: current_address_text = self.tableWidget_Stack.item(selected_row, STACK_POINTER_ADDRESS_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) self.hex_dump_address(int(current_address, 16)) else: points_to_text = self.tableWidget_Stack.item(selected_row, STACK_POINTS_TO_COL).text() current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) if points_to_text.startswith("(str)"): self.hex_dump_address(int(current_address, 16)) else: self.disassemble_expression(current_address, append_to_travel_history=True) def tableWidget_StackTrace_double_click(self, index): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_StackTrace) if index.column() == STACKTRACE_RETURN_ADDRESS_COL: current_address_text = self.tableWidget_StackTrace.item(selected_row, STACKTRACE_RETURN_ADDRESS_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) self.disassemble_expression(current_address, append_to_travel_history=True) if index.column() == STACKTRACE_FRAME_ADDRESS_COL: current_address_text = self.tableWidget_StackTrace.item(selected_row, STACKTRACE_FRAME_ADDRESS_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) self.hex_dump_address(int(current_address, 16)) def tableWidget_StackTrace_key_press_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stacktrace) ]) try: @@ -3525,7 +3526,7 @@ def tableWidget_StackTrace_key_press_event(self, event): self.tableWidget_StackTrace.keyPressEvent_original(event) def widget_Disassemble_wheel_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return steps = event.angleDelta() if steps.y() > 0: @@ -3534,7 +3535,7 @@ def widget_Disassemble_wheel_event(self, event): self.tableWidget_Disassemble_scroll("next", instructions_per_scroll) def disassemble_check_viewport(self, where, instruction_count): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return current_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_row_height = self.tableWidget_Disassemble.rowViewportPosition(current_row) @@ -3548,22 +3549,22 @@ def disassemble_check_viewport(self, where, instruction_count): if self.tableWidget_Disassemble.rowViewportPosition(row) > height: break last_visible_row += 1 - current_address = SysUtils.extract_address( + current_address = utils.extract_address( self.tableWidget_Disassemble.item(current_row, DISAS_ADDR_COL).text()) - new_address = GDB_Engine.find_closest_instruction_address(current_address, "previous", last_visible_row) + new_address = debugcore.find_closest_instruction_address(current_address, "previous", last_visible_row) self.disassemble_expression(new_address) elif (where == "previous" and current_row == 0) or (where == "next" and current_row_height > height): self.tableWidget_Disassemble_scroll(where, instruction_count) def tableWidget_Disassemble_scroll(self, where, instruction_count): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return current_address = self.disassemble_currently_displayed_address - new_address = GDB_Engine.find_closest_instruction_address(current_address, where, instruction_count) + new_address = debugcore.find_closest_instruction_address(current_address, where, instruction_count) self.disassemble_expression(new_address) def widget_HexView_wheel_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return steps = event.angleDelta() current_address = self.hex_model.current_address @@ -3574,11 +3575,11 @@ def widget_HexView_wheel_event(self, event): self.hex_dump_address(next_address) def widget_HexView_key_press_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_address = self.tableView_HexView_Hex.get_selected_address() - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_hex_view_go_to_dialog), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), lambda: self.disassemble_expression(hex(selected_address), append_to_travel_history=True)), @@ -3594,16 +3595,16 @@ def widget_HexView_key_press_event(self, event): self.widget_HexView.keyPressEvent_original(event) def tableWidget_Disassemble_key_press_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), lambda: self.follow_instruction(selected_row)), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_E), @@ -3630,39 +3631,39 @@ def tableWidget_Disassemble_key_press_event(self, event): self.tableWidget_Disassemble.keyPressEvent_original(event) def tableWidget_Disassemble_item_double_clicked(self, index): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if index.column() == DISAS_COMMENT_COL: selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = int(SysUtils.extract_address(current_address_text), 16) + current_address = int(utils.extract_address(current_address_text), 16) if current_address in self.tableWidget_Disassemble.bookmarks: self.change_bookmark_comment(current_address) else: self.bookmark_address(current_address) def tableWidget_Disassemble_item_selection_changed(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return try: selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) selected_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - self.disassemble_last_selected_address_int = int(SysUtils.extract_address(selected_address_text), 16) + self.disassemble_last_selected_address_int = int(utils.extract_address(selected_address_text), 16) except (TypeError, ValueError, AttributeError): pass # Search the item in given row for location changing instructions # Go to the address pointed by that instruction if it contains any def follow_instruction(self, selected_row): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return - address = SysUtils.instruction_follow_address( + address = utils.instruction_follow_address( self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text()) if address: self.disassemble_expression(address, append_to_travel_history=True) def disassemble_go_back(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if self.tableWidget_Disassemble.travel_history: last_location = self.tableWidget_Disassemble.travel_history[-1] @@ -3670,7 +3671,7 @@ def disassemble_go_back(self): self.tableWidget_Disassemble.travel_history.pop() def tableWidget_Disassemble_context_menu_event(self, event): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return def copy_to_clipboard(row, column): @@ -3684,7 +3685,7 @@ def copy_all_columns(row): selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) menu = QMenu() @@ -3692,7 +3693,7 @@ def copy_all_columns(row): back = menu.addAction(tr.BACK) show_in_hex_view = menu.addAction(f"{tr.HEXVIEW_ADDRESS}[Ctrl+H]") menu.addSeparator() - followable = SysUtils.instruction_follow_address( + followable = utils.instruction_follow_address( self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text()) follow = menu.addAction(f"{tr.FOLLOW}[Space]") if not followable: @@ -3710,11 +3711,11 @@ def copy_all_columns(row): guiutils.delete_menu_entries(menu, [bookmark]) go_to_bookmark = menu.addMenu(tr.GO_TO_BOOKMARK_ADDRESS) address_list = [hex(address) for address in self.tableWidget_Disassemble.bookmarks.keys()] - bookmark_actions = [go_to_bookmark.addAction(item.all) for item in GDB_Engine.examine_expressions(address_list)] + bookmark_actions = [go_to_bookmark.addAction(item.all) for item in debugcore.examine_expressions(address_list)] menu.addSeparator() toggle_breakpoint = menu.addAction(f"{tr.TOGGLE_BREAKPOINT}[F5]") add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) - if not GDB_Engine.check_address_in_breakpoints(current_address_int): + if not debugcore.check_address_in_breakpoints(current_address_int): guiutils.delete_menu_entries(menu, [add_condition]) menu.addSeparator() edit_instruction = menu.addAction(tr.EDIT_INSTRUCTION) @@ -3765,47 +3766,47 @@ def copy_all_columns(row): except KeyError: pass if action in bookmark_actions: - self.disassemble_expression(SysUtils.extract_address(action.text()), append_to_travel_history=True) + self.disassemble_expression(utils.extract_address(action.text()), append_to_travel_history=True) def dissect_current_region(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) dissect_code_dialog = DissectCodeDialogForm(int_address=int(current_address, 16)) dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec() self.refresh_disassemble_view() def exec_examine_referrers_widget(self, current_address_text): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if not guiutils.contains_reference_mark(current_address_text): return - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) examine_referrers_widget = ExamineReferrersWidgetForm(current_address_int, self) examine_referrers_widget.show() def exec_trace_instructions_dialog(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) TraceInstructionsWindowForm(current_address, parent=self) def exec_track_breakpoint_dialog(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_instruction = self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() register_expression_dialog = InputDialogForm(item_list=[(tr.ENTER_TRACK_BP_EXPRESSION, "")]) if register_expression_dialog.exec(): @@ -3814,13 +3815,13 @@ def exec_track_breakpoint_dialog(self): track_breakpoint_widget.show() def exec_disassemble_go_to_dialog(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) if selected_row == -1: selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, current_address)]) if go_to_dialog.exec(): @@ -3828,7 +3829,7 @@ def exec_disassemble_go_to_dialog(self): self.disassemble_expression(traveled_exp, append_to_travel_history=True) def bookmark_address(self, int_address): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if int_address in self.tableWidget_Disassemble.bookmarks: QMessageBox.information(app.focusWidget(), tr.ERROR, tr.ALREADY_BOOKMARKED) @@ -3842,7 +3843,7 @@ def bookmark_address(self, int_address): self.refresh_disassemble_view() def change_bookmark_comment(self, int_address): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return current_comment = self.tableWidget_Disassemble.bookmarks[int_address] comment_dialog = InputDialogForm(item_list=[(tr.ENTER_BOOKMARK_COMMENT, current_comment)]) @@ -3854,91 +3855,91 @@ def change_bookmark_comment(self, int_address): self.refresh_disassemble_view() def delete_bookmark(self, int_address): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return if int_address in self.tableWidget_Disassemble.bookmarks: del self.tableWidget_Disassemble.bookmarks[int_address] self.refresh_disassemble_view() def actionBookmarks_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return bookmark_widget = BookmarkWidgetForm(self) bookmark_widget.show() bookmark_widget.activateWindow() def actionStackTrace_Info_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return self.stacktrace_info_widget = StackTraceInfoWidgetForm() self.stacktrace_info_widget.show() def actionBreakpoints_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return breakpoint_widget = BreakpointInfoWidgetForm(self) breakpoint_widget.show() breakpoint_widget.activateWindow() def actionFunctions_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return functions_info_widget = FunctionsInfoWidgetForm(self) functions_info_widget.show() def actionGDB_Log_File_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return log_file_widget = LogFileWidgetForm() log_file_widget.showMaximized() def actionMemory_Regions_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return memory_regions_widget = MemoryRegionsWidgetForm(self) memory_regions_widget.show() def actionRestore_Instructions_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return restore_instructions_widget = RestoreInstructionsWidgetForm(self) restore_instructions_widget.show() def actionReferenced_Strings_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return ref_str_widget = ReferencedStringsWidgetForm(self) ref_str_widget.show() def actionReferenced_Calls_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return ref_call_widget = ReferencedCallsWidgetForm(self) ref_call_widget.show() def actionInject_so_file_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return file_path = QFileDialog.getOpenFileName(self, tr.SELECT_SO_FILE, "", tr.SHARED_OBJECT_TYPE)[0] if file_path: - if GDB_Engine.inject_with_dlopen_call(file_path): + if debugcore.inject_with_dlopen_call(file_path): QMessageBox.information(self, tr.SUCCESS, tr.FILE_INJECTED) else: QMessageBox.information(self, tr.ERROR, tr.FILE_INJECT_FAILED) def actionCall_Function_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return call_dialog = InputDialogForm(item_list=[(tr.ENTER_CALL_EXPRESSION, "")]) if call_dialog.exec(): - result = GDB_Engine.call_function_from_inferior(call_dialog.get_values()) + result = debugcore.call_function_from_inferior(call_dialog.get_values()) if result[0]: QMessageBox.information(self, tr.SUCCESS, result[0] + " = " + result[1]) else: QMessageBox.information(self, tr.ERROR, tr.CALL_EXPRESSION_FAILED.format(call_dialog.get_values())) def actionSearch_Opcode_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return start_address = int(self.disassemble_currently_displayed_address, 16) end_address = start_address + 0x30000 @@ -3946,20 +3947,20 @@ def actionSearch_Opcode_triggered(self): search_opcode_widget.show() def actionDissect_Code_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return self.dissect_code_dialog = DissectCodeDialogForm() self.dissect_code_dialog.exec() self.refresh_disassemble_view() def actionlibpince_triggered(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return libpince_widget = LibpinceReferenceWidgetForm(is_window=True) libpince_widget.showMaximized() def pushButton_ShowFloatRegisters_clicked(self): - if GDB_Engine.currentpid == -1: + if debugcore.currentpid == -1: return self.float_registers_widget = FloatRegisterWidgetForm() self.float_registers_widget.show() @@ -3987,21 +3988,21 @@ def __init__(self, parent=None): def refresh_table(self): self.listWidget.clear() address_list = [hex(address) for address in self.parent().tableWidget_Disassemble.bookmarks.keys()] - self.listWidget.addItems([item.all for item in GDB_Engine.examine_expressions(address_list)]) + self.listWidget.addItems([item.all for item in debugcore.examine_expressions(address_list)]) def change_display(self, row): - current_address = SysUtils.extract_address(self.listWidget.item(row).text()) - self.lineEdit_Info.setText(GDB_Engine.get_address_info(current_address)) + current_address = utils.extract_address(self.listWidget.item(row).text()) + self.lineEdit_Info.setText(debugcore.get_address_info(current_address)) self.lineEdit_Comment.setText(self.parent().tableWidget_Disassemble.bookmarks[int(current_address, 16)]) def listWidget_item_double_clicked(self, item): - self.parent().disassemble_expression(SysUtils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) def exec_add_entry_dialog(self): entry_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, "")]) if entry_dialog.exec(): text = entry_dialog.get_values() - address = GDB_Engine.examine_expression(text).address + address = debugcore.examine_expression(text).address if not address: QMessageBox.information(self, tr.ERROR, tr.INVALID_EXPRESSION) return @@ -4015,7 +4016,7 @@ def exec_change_comment_dialog(self, current_address): def listWidget_context_menu_event(self, event): current_item = guiutils.get_current_item(self.listWidget) if current_item: - current_address = int(SysUtils.extract_address(current_item.text()), 16) + current_address = int(utils.extract_address(current_item.text()), 16) if current_address not in self.parent().tableWidget_Disassemble.bookmarks: QMessageBox.information(self, tr.ERROR, tr.INVALID_ENTRY) self.refresh_table() @@ -4048,7 +4049,7 @@ def delete_record(self): current_item = guiutils.get_current_item(self.listWidget) if not current_item: return - current_address = int(SysUtils.extract_address(current_item.text()), 16) + current_address = int(utils.extract_address(current_item.text()), 16) self.parent().delete_bookmark(current_address) self.refresh_table() @@ -4071,8 +4072,8 @@ def update_registers(self): self.tableWidget_FPU.setRowCount(8) self.tableWidget_XMM.setRowCount(0) self.tableWidget_XMM.setRowCount(8) - float_registers = GDB_Engine.read_float_registers() - for row, (st, xmm) in enumerate(zip(type_defs.REGISTERS.FLOAT.ST, type_defs.REGISTERS.FLOAT.XMM)): + float_registers = debugcore.read_float_registers() + for row, (st, xmm) in enumerate(zip(typedefs.REGISTERS.FLOAT.ST, typedefs.REGISTERS.FLOAT.XMM)): self.tableWidget_FPU.setItem(row, FLOAT_REGISTERS_NAME_COL, QTableWidgetItem(st)) self.tableWidget_FPU.setItem(row, FLOAT_REGISTERS_VALUE_COL, QTableWidgetItem(float_registers[st])) self.tableWidget_XMM.setItem(row, FLOAT_REGISTERS_NAME_COL, QTableWidgetItem(xmm)) @@ -4093,7 +4094,7 @@ def set_register(self, index): if register_dialog.exec(): if self.currentWidget() == self.XMM: current_register += ".v4_float" - GDB_Engine.set_convenience_variable(current_register, register_dialog.get_values()) + debugcore.set_convenience_variable(current_register, register_dialog.get_values()) self.update_registers() @@ -4108,16 +4109,16 @@ def __init__(self, parent=None): def update_stacktrace(self): self.listWidget_ReturnAddresses.clear() - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: return - return_addresses = GDB_Engine.get_stack_frame_return_addresses() + return_addresses = debugcore.get_stack_frame_return_addresses() self.listWidget_ReturnAddresses.addItems(return_addresses) def update_frame_info(self, index): - if GDB_Engine.inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: self.textBrowser_Info.setText(tr.PROCESS_RUNNING) return - frame_info = GDB_Engine.get_stack_frame_info(index) + frame_info = debugcore.get_stack_frame_info(index) self.textBrowser_Info.setText(frame_info) @@ -4144,7 +4145,7 @@ def tableWidget_Instructions_context_menu_event(self, event): restore_instruction = menu.addAction(tr.RESTORE_INSTRUCTION) if selected_row != -1: selected_address_text = self.tableWidget_Instructions.item(selected_row, INSTR_ADDR_COL).text() - selected_address = SysUtils.extract_address(selected_address_text) + selected_address = utils.extract_address(selected_address_text) selected_address_int = int(selected_address, 16) else: guiutils.delete_menu_entries(menu, [restore_instruction]) @@ -4164,16 +4165,16 @@ def tableWidget_Instructions_context_menu_event(self, event): pass def restore_instruction(self, selected_address_int): - GDB_Engine.restore_instruction(selected_address_int) + debugcore.restore_instruction(selected_address_int) self.refresh_all() def refresh(self): - modified_instructions = GDB_Engine.get_modified_instructions() + modified_instructions = debugcore.get_modified_instructions() self.tableWidget_Instructions.setRowCount(len(modified_instructions)) for row, (address, aob) in enumerate(modified_instructions.items()): self.tableWidget_Instructions.setItem(row, INSTR_ADDR_COL, QTableWidgetItem(hex(address))) self.tableWidget_Instructions.setItem(row, INSTR_AOB_COL, QTableWidgetItem(aob)) - instr_name = SysUtils.get_opcodes(address, aob, GDB_Engine.get_inferior_arch()) + instr_name = utils.get_opcodes(address, aob, debugcore.get_inferior_arch()) if not instr_name: instr_name = "??" self.tableWidget_Instructions.setItem(row, INSTR_NAME_COL, QTableWidgetItem(instr_name)) @@ -4185,7 +4186,7 @@ def refresh_all(self): self.refresh() def tableWidget_Instructions_key_press_event(self, event): - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) ]) try: @@ -4196,7 +4197,7 @@ def tableWidget_Instructions_key_press_event(self, event): def tableWidget_Instructions_double_clicked(self, index): current_address_text = self.tableWidget_Instructions.item(index.row(), INSTR_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) self.parent().disassemble_expression(current_address, append_to_travel_history=True) def closeEvent(self, QCloseEvent): @@ -4222,7 +4223,7 @@ def __init__(self, parent=None): self.refresh() def refresh(self): - break_info = GDB_Engine.get_breakpoint_info() + break_info = debugcore.get_breakpoint_info() self.tableWidget_BreakpointInfo.setRowCount(0) self.tableWidget_BreakpointInfo.setRowCount(len(break_info)) for row, item in enumerate(break_info): @@ -4237,22 +4238,22 @@ def refresh(self): self.tableWidget_BreakpointInfo.setItem(row, BREAK_COND_COL, QTableWidgetItem(item.condition)) guiutils.resize_to_contents(self.tableWidget_BreakpointInfo) self.textBrowser_BreakpointInfo.clear() - self.textBrowser_BreakpointInfo.setText(GDB_Engine.send_command("info break", cli_output=True)) + self.textBrowser_BreakpointInfo.setText(debugcore.send_command("info break", cli_output=True)) def delete_breakpoint(self, address): if address is not None: - GDB_Engine.delete_breakpoint(address) + debugcore.delete_breakpoint(address) self.refresh_all() def tableWidget_BreakpointInfo_key_press_event(self, event): selected_row = guiutils.get_current_row(self.tableWidget_BreakpointInfo) if selected_row != -1: current_address_text = self.tableWidget_BreakpointInfo.item(selected_row, BREAK_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) else: current_address = None - actions = type_defs.KeyboardModifiersTupleDict([ + actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), lambda: self.delete_breakpoint(current_address)), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) @@ -4275,14 +4276,14 @@ def exec_enable_count_dialog(self, current_address): if count < 1: QMessageBox.information(self, tr.ERROR, tr.HIT_COUNT_ASSERT_LT.format(1)) else: - GDB_Engine.modify_breakpoint(current_address, type_defs.BREAKPOINT_MODIFY.ENABLE_COUNT, + debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.ENABLE_COUNT, count=count) def tableWidget_BreakpointInfo_context_menu_event(self, event): selected_row = guiutils.get_current_row(self.tableWidget_BreakpointInfo) if selected_row != -1: current_address_text = self.tableWidget_BreakpointInfo.item(selected_row, BREAK_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) else: current_address = None @@ -4308,13 +4309,13 @@ def tableWidget_BreakpointInfo_context_menu_event(self, event): action = menu.exec(event.globalPos()) actions = { change_condition: lambda: self.parent().add_breakpoint_condition(current_address_int), - enable: lambda: GDB_Engine.modify_breakpoint(current_address, type_defs.BREAKPOINT_MODIFY.ENABLE), - disable: lambda: GDB_Engine.modify_breakpoint(current_address, type_defs.BREAKPOINT_MODIFY.DISABLE), - enable_once: lambda: GDB_Engine.modify_breakpoint(current_address, type_defs.BREAKPOINT_MODIFY.ENABLE_ONCE), + enable: lambda: debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.ENABLE), + disable: lambda: debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.DISABLE), + enable_once: lambda: debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.ENABLE_ONCE), enable_count: lambda: self.exec_enable_count_dialog(current_address), - enable_delete: lambda: GDB_Engine.modify_breakpoint(current_address, - type_defs.BREAKPOINT_MODIFY.ENABLE_DELETE), - delete_breakpoint: lambda: GDB_Engine.delete_breakpoint(current_address), + enable_delete: lambda: debugcore.modify_breakpoint(current_address, + typedefs.BREAKPOINT_MODIFY.ENABLE_DELETE), + delete_breakpoint: lambda: debugcore.delete_breakpoint(current_address), refresh: self.refresh } try: @@ -4331,7 +4332,7 @@ def refresh_all(self): def tableWidget_BreakpointInfo_double_clicked(self, index): current_address_text = self.tableWidget_BreakpointInfo.item(index.row(), BREAK_ADDR_COL).text() - current_address = SysUtils.extract_address(current_address_text) + current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) if index.column() == BREAK_COND_COL: @@ -4361,16 +4362,16 @@ def __init__(self, address, length, watchpoint_type, parent=None): self.update_timer = QTimer(timeout=self.update_list) self.stopped = False self.address = address - if watchpoint_type == type_defs.WATCHPOINT_TYPE.WRITE_ONLY: + if watchpoint_type == typedefs.WATCHPOINT_TYPE.WRITE_ONLY: string = tr.OPCODE_WRITING_TO.format(address) - elif watchpoint_type == type_defs.WATCHPOINT_TYPE.READ_ONLY: + elif watchpoint_type == typedefs.WATCHPOINT_TYPE.READ_ONLY: string = tr.OPCODE_READING_FROM.format(address) - elif watchpoint_type == type_defs.WATCHPOINT_TYPE.BOTH: + elif watchpoint_type == typedefs.WATCHPOINT_TYPE.BOTH: string = tr.OPCODE_ACCESSING_TO.format(address) else: raise Exception("Watchpoint type is invalid: " + str(watchpoint_type)) self.setWindowTitle(string) - breakpoints = GDB_Engine.track_watchpoint(address, length, watchpoint_type) + breakpoints = debugcore.track_watchpoint(address, length, watchpoint_type) if not breakpoints: QMessageBox.information(self, tr.ERROR, tr.TRACK_WATCHPOINT_FAILED.format(address)) return @@ -4384,7 +4385,7 @@ def __init__(self, address, length, watchpoint_type, parent=None): self.update_timer.start(100) def update_list(self): - info = GDB_Engine.get_track_watchpoint_info(self.breakpoints) + info = debugcore.get_track_watchpoint_info(self.breakpoints) if not info or self.info == info: return self.info = info @@ -4424,7 +4425,7 @@ def pushButton_Stop_clicked(self): if self.stopped: self.close() return - if not GDB_Engine.delete_breakpoint(self.address): + if not debugcore.delete_breakpoint(self.address): QMessageBox.information(self, tr.ERROR, tr.DELETE_WATCHPOINT_FAILED.format(self.address)) return self.stopped = True @@ -4434,7 +4435,7 @@ def closeEvent(self, QCloseEvent): global instances self.update_timer.stop() if not self.stopped: - GDB_Engine.delete_breakpoint(self.address) + debugcore.delete_breakpoint(self.address) self.deleteLater() instances.remove(self) @@ -4453,7 +4454,7 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.setWindowFlags(Qt.WindowType.Window) guiutils.center_to_parent(self) self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) - breakpoint = GDB_Engine.track_breakpoint(address, register_expressions) + breakpoint = debugcore.track_breakpoint(address, register_expressions) if not breakpoint: QMessageBox.information(self, tr.ERROR, tr.TRACK_BREAKPOINT_FAILED.format(address)) return @@ -4470,7 +4471,7 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.parent().refresh_disassemble_view() def update_list(self): - info = GDB_Engine.get_track_breakpoint_info(self.breakpoint) + info = debugcore.get_track_breakpoint_info(self.breakpoint) if not info: return if info == self.info: @@ -4488,11 +4489,11 @@ def update_list(self): self.update_values() def update_values(self): - mem_handle = GDB_Engine.memory_handle() + mem_handle = debugcore.memory_handle() value_type = self.comboBox_ValueType.currentIndex() for row in range(self.tableWidget_TrackInfo.rowCount()): address = self.tableWidget_TrackInfo.item(row, TRACK_BREAKPOINT_ADDR_COL).text() - value = GDB_Engine.read_memory(address, value_type, 10, mem_handle=mem_handle) + value = debugcore.read_memory(address, value_type, 10, mem_handle=mem_handle) value = "" if value is None else str(value) self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_VALUE_COL, QTableWidgetItem(value)) guiutils.resize_to_contents(self.tableWidget_TrackInfo) @@ -4505,7 +4506,7 @@ def tableWidget_TrackInfo_current_changed(self, QModelIndex_current): def tableWidget_TrackInfo_item_double_clicked(self, index): address = self.tableWidget_TrackInfo.item(index.row(), TRACK_BREAKPOINT_ADDR_COL).text() - vt = type_defs.ValueType(self.comboBox_ValueType.currentIndex()) + vt = typedefs.ValueType(self.comboBox_ValueType.currentIndex()) self.parent().parent().add_entry_to_addresstable(tr.ACCESSED_BY.format(self.address), address, vt) self.parent().parent().update_address_table() @@ -4513,7 +4514,7 @@ def pushButton_Stop_clicked(self): if self.stopped: self.close() return - if not GDB_Engine.delete_breakpoint(self.address): + if not debugcore.delete_breakpoint(self.address): QMessageBox.information(self, tr.ERROR, tr.DELETE_BREAKPOINT_FAILED.format(self.address)) return self.stopped = True @@ -4525,7 +4526,7 @@ def closeEvent(self, QCloseEvent): self.update_list_timer.stop() self.update_values_timer.stop() if not self.stopped: - GDB_Engine.delete_breakpoint(self.address) + debugcore.delete_breakpoint(self.address) self.parent().refresh_disassemble_view() self.deleteLater() instances.remove(self) @@ -4541,9 +4542,9 @@ def get_values(self): trigger_condition = self.lineEdit_TriggerCondition.text() stop_condition = self.lineEdit_StopCondition.text() if self.checkBox_StepOver.isChecked(): - step_mode = type_defs.STEP_MODE.STEP_OVER + step_mode = typedefs.STEP_MODE.STEP_OVER else: - step_mode = type_defs.STEP_MODE.SINGLE_STEP + step_mode = typedefs.STEP_MODE.SINGLE_STEP stop_after_trace = self.checkBox_StopAfterTrace.isChecked() collect_general_registers = self.checkBox_GeneralRegisters.isChecked() collect_flag_registers = self.checkBox_FlagRegisters.isChecked() @@ -4566,16 +4567,16 @@ def __init__(self, address, breakpoint, parent=None): super().__init__(parent=parent) self.setupUi(self) self.status_to_text = { - type_defs.TRACE_STATUS.STATUS_IDLE: tr.WAITING_FOR_BREAKPOINT, - type_defs.TRACE_STATUS.STATUS_CANCELED: tr.TRACING_CANCELED, - type_defs.TRACE_STATUS.STATUS_PROCESSING: tr.PROCESSING_DATA, - type_defs.TRACE_STATUS.STATUS_FINISHED: tr.TRACING_COMPLETED + typedefs.TRACE_STATUS.STATUS_IDLE: tr.WAITING_FOR_BREAKPOINT, + typedefs.TRACE_STATUS.STATUS_CANCELED: tr.TRACING_CANCELED, + typedefs.TRACE_STATUS.STATUS_PROCESSING: tr.PROCESSING_DATA, + typedefs.TRACE_STATUS.STATUS_FINISHED: tr.TRACING_COMPLETED } self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) guiutils.center(self) self.address = address self.breakpoint = breakpoint - media_directory = SysUtils.get_media_directory() + media_directory = utils.get_media_directory() self.movie = QMovie(media_directory + "/TraceInstructionsWaitWidget/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) self.movie.setScaledSize(QSize(215, 100)) @@ -4590,12 +4591,12 @@ def __init__(self, address, breakpoint, parent=None): self.status_timer.start() def change_status(self): - status_info = GDB_Engine.get_trace_instructions_status(self.breakpoint) - if status_info[0] == type_defs.TRACE_STATUS.STATUS_FINISHED or \ - status_info[0] == type_defs.TRACE_STATUS.STATUS_PROCESSING: + status_info = debugcore.get_trace_instructions_status(self.breakpoint) + if status_info[0] == typedefs.TRACE_STATUS.STATUS_FINISHED or \ + status_info[0] == typedefs.TRACE_STATUS.STATUS_PROCESSING: self.close() return - if status_info[0] == type_defs.TRACE_STATUS.STATUS_TRACING: + if status_info[0] == typedefs.TRACE_STATUS.STATUS_TRACING: self.label_StatusText.setText(status_info[1]) else: self.label_StatusText.setText(self.status_to_text[status_info[0]]) @@ -4607,15 +4608,15 @@ def closeEvent(self, QCloseEvent): self.pushButton_Cancel.setVisible(False) self.adjustSize() app.processEvents() - status_info = GDB_Engine.get_trace_instructions_status(self.breakpoint) - if status_info[0] == type_defs.TRACE_STATUS.STATUS_TRACING or \ - status_info[0] == type_defs.TRACE_STATUS.STATUS_PROCESSING: - GDB_Engine.cancel_trace_instructions(self.breakpoint) - while GDB_Engine.get_trace_instructions_status(self.breakpoint)[0] \ - != type_defs.TRACE_STATUS.STATUS_FINISHED: + status_info = debugcore.get_trace_instructions_status(self.breakpoint) + if status_info[0] == typedefs.TRACE_STATUS.STATUS_TRACING or \ + status_info[0] == typedefs.TRACE_STATUS.STATUS_PROCESSING: + debugcore.cancel_trace_instructions(self.breakpoint) + while debugcore.get_trace_instructions_status(self.breakpoint)[0] \ + != typedefs.TRACE_STATUS.STATUS_FINISHED: sleep(0.1) app.processEvents() - GDB_Engine.delete_breakpoint(self.address) + debugcore.delete_breakpoint(self.address) self.widget_closed.emit() @@ -4640,7 +4641,7 @@ def __init__(self, address="", prompt_dialog=True, parent=None): prompt_dialog = TraceInstructionsPromptDialogForm() if prompt_dialog.exec(): params = (address,) + prompt_dialog.get_values() - breakpoint = GDB_Engine.trace_instructions(*params) + breakpoint = debugcore.trace_instructions(*params) if not breakpoint: QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_FAILED.format(address)) self.close() @@ -4669,7 +4670,7 @@ def show_trace_info(self, trace_data=None): if trace_data: trace_tree, current_root_index = trace_data else: - trace_data = GDB_Engine.get_trace_instructions_info(self.breakpoint) + trace_data = debugcore.get_trace_instructions_info(self.breakpoint) if trace_data: trace_tree, current_root_index = trace_data else: @@ -4693,18 +4694,18 @@ def show_trace_info(self, trace_data=None): self.treeWidget_InstructionInfo.expandAll() def save_file(self): - trace_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) + trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) file_path = QFileDialog.getSaveFileName(self, tr.SAVE_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] if file_path: - file_path = SysUtils.append_file_extension(file_path, "trace") - if not SysUtils.save_file(self.trace_data, file_path): + file_path = utils.append_file_extension(file_path, "trace") + if not utils.save_file(self.trace_data, file_path): QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) def load_file(self): - trace_file_path = SysUtils.get_user_path(type_defs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) + trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) file_path = QFileDialog.getOpenFileName(self, tr.OPEN_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] if file_path: - content = SysUtils.load_file(file_path) + content = utils.load_file(file_path) if content is None: QMessageBox.information(self, tr.ERROR, tr.FILE_LOAD_ERROR.format(file_path)) return @@ -4731,7 +4732,7 @@ def treeWidget_InstructionInfo_item_double_clicked(self, index): current_item = guiutils.get_current_item(self.treeWidget_InstructionInfo) if not current_item: return - address = SysUtils.extract_address(current_item.trace_data[0]) + address = utils.extract_address(current_item.trace_data[0]) if address: self.parent().disassemble_expression(address, append_to_travel_history=True) @@ -4770,7 +4771,7 @@ def refresh_table(self): self.loading_dialog.exec() def process_data(self, gdb_input, case_sensitive): - return GDB_Engine.search_functions(gdb_input, case_sensitive) + return debugcore.search_functions(gdb_input, case_sensitive) def apply_data(self, output): self.tableWidget_SymbolInfo.setSortingEnabled(False) @@ -4796,10 +4797,10 @@ def tableWidget_SymbolInfo_current_changed(self, QModelIndex_current): if current_row < 0: return address = self.tableWidget_SymbolInfo.item(current_row, FUNCTIONS_INFO_ADDR_COL).text() - if SysUtils.extract_address(address): + if utils.extract_address(address): symbol = self.tableWidget_SymbolInfo.item(current_row, FUNCTIONS_INFO_SYMBOL_COL).text() - for item in SysUtils.split_symbol(symbol): - info = GDB_Engine.get_symbol_info(item) + for item in utils.split_symbol(symbol): + info = debugcore.get_symbol_info(item) self.textBrowser_AddressInfo.append(info) else: self.textBrowser_AddressInfo.append(tr.DEFINED_SYMBOL) @@ -4863,9 +4864,9 @@ def set_valid(self, valid): def lineEdit_Bytes_text_edited(self): bytes_aob = self.lineEdit_Bytes.text() - if SysUtils.parse_string(bytes_aob, type_defs.VALUE_INDEX.INDEX_AOB): + if utils.parse_string(bytes_aob, typedefs.VALUE_INDEX.INDEX_AOB): address = int(self.lineEdit_Address.text(), 0) - instruction = SysUtils.get_opcodes(address, bytes_aob, GDB_Engine.inferior_arch) + instruction = utils.get_opcodes(address, bytes_aob, debugcore.inferior_arch) if instruction: self.set_valid(True) self.lineEdit_Instruction.setText(instruction) @@ -4876,7 +4877,7 @@ def lineEdit_Bytes_text_edited(self): def lineEdit_Instruction_text_edited(self): instruction = self.lineEdit_Instruction.text() address = int(self.lineEdit_Address.text(), 0) - result = SysUtils.assemble(instruction, address, GDB_Engine.inferior_arch) + result = utils.assemble(instruction, address, debugcore.inferior_arch) if result: byte_list = result[0] self.set_valid(True) @@ -4901,7 +4902,7 @@ def accept(self): elif new_length > old_length: if not InputDialogForm(item_list=[(tr.NEW_OPCODE.format(new_length, old_length),)]).exec(): return - GDB_Engine.modify_instruction(address, bytes_aob) + debugcore.modify_instruction(address, bytes_aob) self.parent().refresh_hex_view() self.parent().refresh_disassemble_view() super(EditInstructionDialogForm, self).accept() @@ -4926,9 +4927,9 @@ def __init__(self, address, parent=None): self.lineEdit_Length.textChanged.connect(self.refresh_view) def lineEdit_AsciiView_selection_changed(self): - length = len(SysUtils.str_to_aob(self.lineEdit_AsciiView.selectedText(), "utf-8")) + length = len(utils.str_to_aob(self.lineEdit_AsciiView.selectedText(), "utf-8")) start_index = self.lineEdit_AsciiView.selectionStart() - start_index = len(SysUtils.str_to_aob(self.lineEdit_AsciiView.text()[0:start_index], "utf-8")) + start_index = len(utils.str_to_aob(self.lineEdit_AsciiView.text()[0:start_index], "utf-8")) if start_index > 0: start_index += 1 self.lineEdit_HexView.deselect() @@ -4941,12 +4942,12 @@ def lineEdit_HexView_selection_changed(self): def lineEdit_HexView_text_edited(self): aob_string = self.lineEdit_HexView.text() - if not SysUtils.parse_string(aob_string, type_defs.VALUE_INDEX.INDEX_AOB): + if not utils.parse_string(aob_string, typedefs.VALUE_INDEX.INDEX_AOB): self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") return aob_array = aob_string.split() try: - self.lineEdit_AsciiView.setText(SysUtils.aob_to_str(aob_array, "utf-8")) + self.lineEdit_AsciiView.setText(utils.aob_to_str(aob_array, "utf-8")) self.lineEdit_HexView.setStyleSheet("") # This should set background color back to QT default except ValueError: self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") @@ -4954,7 +4955,7 @@ def lineEdit_HexView_text_edited(self): def lineEdit_AsciiView_text_edited(self): ascii_str = self.lineEdit_AsciiView.text() try: - self.lineEdit_HexView.setText(SysUtils.str_to_aob(ascii_str, "utf-8")) + self.lineEdit_HexView.setText(utils.str_to_aob(ascii_str, "utf-8")) self.lineEdit_AsciiView.setStyleSheet("") except ValueError: self.lineEdit_AsciiView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") @@ -4962,7 +4963,7 @@ def lineEdit_AsciiView_text_edited(self): def refresh_view(self): self.lineEdit_AsciiView.clear() self.lineEdit_HexView.clear() - address = GDB_Engine.examine_expression(self.lineEdit_Address.text()).address + address = debugcore.examine_expression(self.lineEdit_Address.text()).address if not address: return length = self.lineEdit_Length.text() @@ -4971,19 +4972,19 @@ def refresh_view(self): address = int(address, 0) except ValueError: return - aob_array = GDB_Engine.hex_dump(address, length) - ascii_str = SysUtils.aob_to_str(aob_array, "utf-8") + aob_array = debugcore.hex_dump(address, length) + ascii_str = utils.aob_to_str(aob_array, "utf-8") self.lineEdit_AsciiView.setText(ascii_str) self.lineEdit_HexView.setText(" ".join(aob_array)) def accept(self): expression = self.lineEdit_Address.text() - address = GDB_Engine.examine_expression(expression).address + address = debugcore.examine_expression(expression).address if not address: QMessageBox.information(self, tr.ERROR, tr.IS_INVALID_EXPRESSION.format(expression)) return value = self.lineEdit_HexView.text() - GDB_Engine.write_memory(address, type_defs.VALUE_INDEX.INDEX_AOB, value) + debugcore.write_memory(address, typedefs.VALUE_INDEX.INDEX_AOB, value) super(HexEditDialogForm, self).accept() @@ -5002,13 +5003,13 @@ def __init__(self, is_window=False, parent=None): if is_window: guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) - self.show_type_defs() + self.show_typedefs() self.splitter.setStretchFactor(0, 1) self.widget_Resources.resize(700, self.widget_Resources.height()) - libpince_directory = SysUtils.get_libpince_directory() - self.textBrowser_TypeDefs.setText(open(libpince_directory + "/type_defs.py").read()) + libpince_directory = utils.get_libpince_directory() + self.textBrowser_TypeDefs.setText(open(libpince_directory + "/typedefs.py").read()) source_menu_items = ["(Tagged only)", "(All)"] - self.source_files = ["GDB_Engine", "SysUtils", "guiutils"] + self.source_files = ["debugcore", "utils", "guiutils"] source_menu_items.extend(self.source_files) self.comboBox_SourceFile.addItems(source_menu_items) self.comboBox_SourceFile.setCurrentIndex(0) @@ -5017,7 +5018,7 @@ def __init__(self, is_window=False, parent=None): self.pushButton_TextUp.setIcon(QIcon(QPixmap(icons_directory + "/bullet_arrow_up.png"))) self.pushButton_TextDown.setIcon(QIcon(QPixmap(icons_directory + "/bullet_arrow_down.png"))) self.comboBox_SourceFile.currentIndexChanged.connect(self.comboBox_SourceFile_current_index_changed) - self.pushButton_ShowTypeDefs.clicked.connect(self.toggle_type_defs) + self.pushButton_ShowTypeDefs.clicked.connect(self.toggle_typedefs) self.lineEdit_SearchText.textChanged.connect(self.highlight_text) self.pushButton_TextDown.clicked.connect(self.pushButton_TextDown_clicked) self.pushButton_TextUp.clicked.connect(self.pushButton_TextUp_clicked) @@ -5113,8 +5114,8 @@ def fill_resource_tree(self): self.treeWidget_ResourceTree.clear() parent = self.treeWidget_ResourceTree checked_source_files = self.convert_to_modules(self.source_files) - tag_dict = SysUtils.get_tags(checked_source_files, type_defs.tag_to_string, self.lineEdit_Search.text()) - docstring_dict = SysUtils.get_docstrings(checked_source_files, self.lineEdit_Search.text()) + tag_dict = utils.get_tags(checked_source_files, typedefs.tag_to_string, self.lineEdit_Search.text()) + docstring_dict = utils.get_docstrings(checked_source_files, self.lineEdit_Search.text()) for tag in tag_dict: child = QTreeWidgetItem(parent) child.setText(0, tag) @@ -5142,7 +5143,7 @@ def fill_resource_table(self): else: checked_source_files = [self.comboBox_SourceFile.currentText()] checked_source_files = self.convert_to_modules(checked_source_files) - element_dict = SysUtils.get_docstrings(checked_source_files, self.lineEdit_Search.text()) + element_dict = utils.get_docstrings(checked_source_files, self.lineEdit_Search.text()) self.tableWidget_ResourceTable.setRowCount(len(element_dict)) for row, item in enumerate(element_dict): docstring = element_dict.get(item) @@ -5217,21 +5218,21 @@ def highlight_text(self): self.textBrowser_TypeDefs.find(pattern) self.current_found = 1 - def toggle_type_defs(self): - if self.type_defs_shown: - self.hide_type_defs() + def toggle_typedefs(self): + if self.typedefs_shown: + self.hide_typedefs() else: - self.show_type_defs() + self.show_typedefs() - def hide_type_defs(self): - self.type_defs_shown = False + def hide_typedefs(self): + self.typedefs_shown = False self.widget_TypeDefs.hide() - self.pushButton_ShowTypeDefs.setText("Show type_defs") + self.pushButton_ShowTypeDefs.setText("Show typedefs") - def show_type_defs(self): - self.type_defs_shown = True + def show_typedefs(self): + self.typedefs_shown = True self.widget_TypeDefs.show() - self.pushButton_ShowTypeDefs.setText("Hide type_defs") + self.pushButton_ShowTypeDefs.setText("Hide typedefs") def closeEvent(self, QCloseEvent): global instances @@ -5254,8 +5255,8 @@ def __init__(self, parent=None): self.refresh_timer.start() def refresh_contents(self): - log_path = SysUtils.get_logging_file(GDB_Engine.currentpid) - self.setWindowTitle(tr.LOG_FILE.format(GDB_Engine.currentpid)) + log_path = utils.get_logging_file(debugcore.currentpid) + self.setWindowTitle(tr.LOG_FILE.format(debugcore.currentpid)) self.label_FilePath.setText(tr.LOG_CONTENTS.format(log_path, 20000)) logging_status = f"{tr.ON}" if gdb_logging else f"{tr.OFF}" self.label_LoggingStatus.setText(f"{tr.LOG_STATUS.format(logging_status)}") @@ -5328,7 +5329,7 @@ def refresh_table(self): self.loading_dialog.exec() def process_data(self, regex, start_address, end_address, case_sensitive, enable_regex): - return GDB_Engine.search_opcode(regex, start_address, end_address, case_sensitive, enable_regex) + return debugcore.search_opcode(regex, start_address, end_address, case_sensitive, enable_regex) def apply_data(self, disas_data): if disas_data is None: @@ -5349,7 +5350,7 @@ def pushButton_Help_clicked(self): def tableWidget_Opcodes_item_double_clicked(self, index): row = index.row() address = self.tableWidget_Opcodes.item(row, SEARCH_OPCODE_ADDR_COL).text() - self.parent().disassemble_expression(SysUtils.extract_address(address), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(address), append_to_travel_history=True) def tableWidget_Opcodes_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -5395,7 +5396,7 @@ def __init__(self, parent=None): self.shortcut_refresh.activated.connect(self.refresh_table) def refresh_table(self): - memory_regions = SysUtils.get_regions(GDB_Engine.currentpid) + memory_regions = utils.get_regions(debugcore.currentpid) self.tableWidget_MemoryRegions.setRowCount(0) self.tableWidget_MemoryRegions.setRowCount(len(memory_regions)) for row, (start, end, perms, offset, _, _, path) in enumerate(memory_regions): @@ -5484,7 +5485,7 @@ def __init__(self, region_list, discard_invalid_strings): self.discard_invalid_strings = discard_invalid_strings def run(self): - GDB_Engine.dissect_code(self.region_list, self.discard_invalid_strings) + debugcore.dissect_code(self.region_list, self.discard_invalid_strings) if not self.is_canceled: self.output_ready.emit() @@ -5499,7 +5500,7 @@ def init_after_scan_gui(self): self.pushButton_StartCancel.setText(tr.CANCEL) def refresh_dissect_status(self): - region, region_count, range, string_count, jump_count, call_count = GDB_Engine.get_dissect_code_status() + region, region_count, range, string_count, jump_count, call_count = debugcore.get_dissect_code_status() if not region: return self.label_RegionInfo.setText(region) @@ -5511,7 +5512,7 @@ def refresh_dissect_status(self): def update_dissect_results(self): try: - referenced_strings, referenced_jumps, referenced_calls = GDB_Engine.get_dissect_code_data() + referenced_strings, referenced_jumps, referenced_calls = debugcore.get_dissect_code_data() except: return self.label_StringReferenceCount.setText(str(len(referenced_strings))) @@ -5519,7 +5520,7 @@ def update_dissect_results(self): self.label_CallReferenceCount.setText(str(len(referenced_calls))) def show_memory_regions(self): - executable_regions = SysUtils.filter_regions(GDB_Engine.currentpid, "permissions", "..x.") + executable_regions = utils.filter_regions(debugcore.currentpid, "permissions", "..x.") self.region_list = [] self.tableWidget_ExecutableMemoryRegions.setRowCount(0) self.tableWidget_ExecutableMemoryRegions.setRowCount(len(executable_regions)) @@ -5544,7 +5545,7 @@ def pushButton_StartCancel_clicked(self): if self.is_scanning: self.is_canceled = True self.background_thread.is_canceled = True - GDB_Engine.cancel_dissect_code() + debugcore.cancel_dissect_code() self.refresh_timer.stop() self.update_dissect_results() self.label_ScanInfo.setText(tr.SCAN_CANCELED) @@ -5564,7 +5565,7 @@ def pushButton_StartCancel_clicked(self): self.background_thread.start() def closeEvent(self, QCloseEvent): - GDB_Engine.cancel_dissect_code() + debugcore.cancel_dissect_code() self.refresh_timer.stop() @@ -5572,7 +5573,7 @@ class ReferencedStringsWidgetForm(QWidget, ReferencedStringsWidget): def __init__(self, parent=None): super().__init__() self.setupUi(self) - guiutils.fill_value_combobox(self.comboBox_ValueType, type_defs.VALUE_INDEX.INDEX_STRING_UTF8) + guiutils.fill_value_combobox(self.comboBox_ValueType, typedefs.VALUE_INDEX.INDEX_STRING_UTF8) self.parent = lambda: parent global instances instances.append(self) @@ -5582,8 +5583,8 @@ def __init__(self, parent=None): self.tableWidget_References.setColumnWidth(REF_STR_COUNT_COL, 80) self.splitter.setStretchFactor(0, 1) self.listWidget_Referrers.resize(400, self.listWidget_Referrers.height()) - self.hex_len = 16 if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64 else 8 - str_dict, jmp_dict, call_dict = GDB_Engine.get_dissect_code_data() + self.hex_len = 16 if debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64 else 8 + str_dict, jmp_dict, call_dict = debugcore.get_dissect_code_data() str_dict_len, jmp_dict_len, call_dict_len = len(str_dict), len(jmp_dict), len(call_dict) str_dict.close() jmp_dict.close() @@ -5615,7 +5616,7 @@ def pad_hex(self, hex_str): return '0x' + hex_str[2:].zfill(self.hex_len + self_len) def refresh_table(self): - item_list = GDB_Engine.search_referenced_strings(self.lineEdit_Regex.text(), + item_list = debugcore.search_referenced_strings(self.lineEdit_Regex.text(), self.comboBox_ValueType.currentIndex(), self.checkBox_CaseSensitive.isChecked(), self.checkBox_Regex.isChecked()) @@ -5639,11 +5640,11 @@ def tableWidget_References_current_changed(self, QModelIndex_current): if QModelIndex_current.row() < 0: return self.listWidget_Referrers.clear() - str_dict = GDB_Engine.get_dissect_code_data(True, False, False)[0] + str_dict = debugcore.get_dissect_code_data(True, False, False)[0] addr = self.tableWidget_References.item(QModelIndex_current.row(), REF_STR_ADDR_COL).text() referrers = str_dict[hex(int(addr, 16))] addrs = [hex(address) for address in referrers] - self.listWidget_Referrers.addItems([self.pad_hex(item.all) for item in GDB_Engine.examine_expressions(addrs)]) + self.listWidget_Referrers.addItems([self.pad_hex(item.all) for item in debugcore.examine_expressions(addrs)]) self.listWidget_Referrers.sortItems(Qt.SortOrder.AscendingOrder) str_dict.close() @@ -5653,7 +5654,7 @@ def tableWidget_References_item_double_clicked(self, index): self.parent().hex_dump_address(int(address, 16)) def listWidget_Referrers_item_double_clicked(self, item): - self.parent().disassemble_expression(SysUtils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) def tableWidget_References_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -5716,8 +5717,8 @@ def __init__(self, parent=None): self.tableWidget_References.setColumnWidth(REF_CALL_ADDR_COL, 480) self.splitter.setStretchFactor(0, 1) self.listWidget_Referrers.resize(400, self.listWidget_Referrers.height()) - self.hex_len = 16 if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64 else 8 - str_dict, jmp_dict, call_dict = GDB_Engine.get_dissect_code_data() + self.hex_len = 16 if debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64 else 8 + str_dict, jmp_dict, call_dict = debugcore.get_dissect_code_data() str_dict_len, jmp_dict_len, call_dict_len = len(str_dict), len(jmp_dict), len(call_dict) str_dict.close() jmp_dict.close() @@ -5748,7 +5749,7 @@ def pad_hex(self, hex_str): return '0x' + hex_str[2:].zfill(self.hex_len + self_len) def refresh_table(self): - item_list = GDB_Engine.search_referenced_calls(self.lineEdit_Regex.text(), + item_list = debugcore.search_referenced_calls(self.lineEdit_Regex.text(), self.checkBox_CaseSensitive.isChecked(), self.checkBox_Regex.isChecked()) if item_list is None: @@ -5768,21 +5769,21 @@ def tableWidget_References_current_changed(self, QModelIndex_current): if QModelIndex_current.row() < 0: return self.listWidget_Referrers.clear() - call_dict = GDB_Engine.get_dissect_code_data(False, False, True)[0] + call_dict = debugcore.get_dissect_code_data(False, False, True)[0] addr = self.tableWidget_References.item(QModelIndex_current.row(), REF_CALL_ADDR_COL).text() - referrers = call_dict[hex(int(SysUtils.extract_address(addr), 16))] + referrers = call_dict[hex(int(utils.extract_address(addr), 16))] addrs = [hex(address) for address in referrers] - self.listWidget_Referrers.addItems([self.pad_hex(item.all) for item in GDB_Engine.examine_expressions(addrs)]) + self.listWidget_Referrers.addItems([self.pad_hex(item.all) for item in debugcore.examine_expressions(addrs)]) self.listWidget_Referrers.sortItems(Qt.SortOrder.AscendingOrder) call_dict.close() def tableWidget_References_item_double_clicked(self, index): row = index.row() address = self.tableWidget_References.item(row, REF_CALL_ADDR_COL).text() - self.parent().disassemble_expression(SysUtils.extract_address(address), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(address), append_to_travel_history=True) def listWidget_Referrers_item_double_clicked(self, item): - self.parent().disassemble_expression(SysUtils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) def tableWidget_References_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -5843,7 +5844,7 @@ def __init__(self, int_address, parent=None): self.splitter.setStretchFactor(0, 1) self.textBrowser_DisasInfo.resize(600, self.textBrowser_DisasInfo.height()) self.referenced_hex = hex(int_address) - self.hex_len = 16 if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64 else 8 + self.hex_len = 16 if debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64 else 8 self.collect_referrer_data() self.refresh_table() self.listWidget_Referrers.sortItems(Qt.SortOrder.AscendingOrder) @@ -5863,7 +5864,7 @@ def pad_hex(self, hex_str): return '0x' + hex_str[2:].zfill(self.hex_len + self_len) def collect_referrer_data(self): - jmp_dict, call_dict = GDB_Engine.get_dissect_code_data(False, True, True) + jmp_dict, call_dict = debugcore.get_dissect_code_data(False, True, True) self.referrer_data = [] try: jmp_referrers = jmp_dict[self.referenced_hex] @@ -5871,14 +5872,14 @@ def collect_referrer_data(self): pass else: jmp_referrers = [hex(item) for item in jmp_referrers] - self.referrer_data.extend([item.all for item in GDB_Engine.examine_expressions(jmp_referrers)]) + self.referrer_data.extend([item.all for item in debugcore.examine_expressions(jmp_referrers)]) try: call_referrers = call_dict[self.referenced_hex] except KeyError: pass else: call_referrers = [hex(item) for item in call_referrers] - self.referrer_data.extend([item.all for item in GDB_Engine.examine_expressions(call_referrers)]) + self.referrer_data.extend([item.all for item in debugcore.examine_expressions(call_referrers)]) jmp_dict.close() call_dict.close() @@ -5916,8 +5917,8 @@ def listWidget_Referrers_current_changed(self, QModelIndex_current): if QModelIndex_current.row() < 0: return self.textBrowser_DisasInfo.clear() - disas_data = GDB_Engine.disassemble( - SysUtils.extract_address(self.listWidget_Referrers.item(QModelIndex_current.row()).text()), "+200") + disas_data = debugcore.disassemble( + utils.extract_address(self.listWidget_Referrers.item(QModelIndex_current.row()).text()), "+200") for address_info, _, opcode in disas_data: self.textBrowser_DisasInfo.append(address_info + opcode) cursor = self.textBrowser_DisasInfo.textCursor() @@ -5926,7 +5927,7 @@ def listWidget_Referrers_current_changed(self, QModelIndex_current): self.textBrowser_DisasInfo.ensureCursorVisible() def listWidget_Referrers_item_double_clicked(self, item): - self.parent().disassemble_expression(SysUtils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) def listWidget_Referrers_context_menu_event(self, event): def copy_to_clipboard(row): diff --git a/README.md b/README.md index f3418bf7..c4022d2b 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Pre-release screenshots: * Custom scripts instead of using gdb's x command for reading memory * Custom scripts instead of using gdb's set command for modifying memory - **libpince - A reusable python library** - * PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget is automatically generated by looking at the docstrings of the source files. PINCE has a unique parsing technique that allows parsing variables. Check the function get_variable_comments in SysUtils for the details. This feature might be replaced with Sphinx in the future + * PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget is automatically generated by looking at the docstrings of the source files. PINCE has a unique parsing technique that allows parsing variables. Check the function get_variable_comments in utils for the details. This feature might be replaced with Sphinx in the future - **Extendable with .so files at runtime** * See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 9a3bbf1a..02f44a47 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -553,7 +553,7 @@ Patterns at former positions have higher priority if regex is off - type_defs(Type Definitions) + typedefs(Type Definitions) @@ -581,7 +581,7 @@ Patterns at former positions have higher priority if regex is off - Hide type_defs + Hide typedefs diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index fb80ca44..248dc5eb 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -555,8 +555,8 @@ Patterns at former positions have higher priority if regex is off - type_defs(Type Definitions) - type_defs(类型定义) + typedefs(Type Definitions) + typedefs(类型定义) @@ -583,8 +583,8 @@ Patterns at former positions have higher priority if regex is off - Hide type_defs - 隐藏 type_defs + Hide typedefs + 隐藏 typedefs diff --git a/libpince/GDB_Engine.py b/libpince/debugcore.py similarity index 84% rename from libpince/GDB_Engine.py rename to libpince/debugcore.py index 2d279982..0cde1176 100644 --- a/libpince/GDB_Engine.py +++ b/libpince/debugcore.py @@ -19,11 +19,11 @@ from time import sleep, time from collections import OrderedDict, defaultdict import pexpect, os, sys, ctypes, pickle, json, shelve, re, struct, io -from . import SysUtils, type_defs, common_regexes +from . import utils, typedefs, regexes self_pid = os.getpid() libc = ctypes.CDLL('libc.so.6') -system_endianness = type_defs.ENDIANNESS.LITTLE if sys.byteorder == "little" else type_defs.ENDIANNESS.BIG +system_endianness = typedefs.ENDIANNESS.LITTLE if sys.byteorder == "little" else typedefs.ENDIANNESS.BIG #:tag:GDBInformation #:doc: @@ -32,12 +32,12 @@ #:tag:InferiorInformation #:doc: -# An integer. Can be a member of type_defs.INFERIOR_ARCH +# An integer. Can be a member of typedefs.INFERIOR_ARCH inferior_arch = int #:tag:InferiorInformation #:doc: -# An integer. Can be a member of type_defs.INFERIOR_STATUS +# An integer. Can be a member of typedefs.INFERIOR_STATUS inferior_status = -1 #:tag:InferiorInformation @@ -47,7 +47,7 @@ #:tag:GDBInformation #:doc: -# An integer. Can be a member of type_defs.STOP_REASON +# An integer. Can be a member of typedefs.STOP_REASON stop_reason = int #:tag:GDBInformation @@ -102,9 +102,9 @@ #:tag:GDBInformation #:doc: -# An instance of type_defs.RegisterQueue. Updated whenever GDB receives an async event such as breakpoint modification +# An instance of typedefs.RegisterQueue. Updated whenever GDB receives an async event such as breakpoint modification # See PINCE's AwaitAsyncOutput class for an example of usage -gdb_async_output = type_defs.RegisterQueue() +gdb_async_output = typedefs.RegisterQueue() #:tag:GDBInformation #:doc: @@ -122,7 +122,7 @@ #:doc: # A list of booleans. Used to adjust gdb output # Use the function set_gdb_output_mode to make use of this variable -gdb_output_mode = type_defs.gdb_output_mode(True, True, True) +gdb_output_mode = typedefs.gdb_output_mode(True, True, True) #:tag:InferiorInformation #:doc: @@ -144,7 +144,7 @@ def set_gdb_output_mode(output_mode_tuple): """Adjusts gdb output Args: - output_mode_tuple (type_defs.gdb_output_mode): Setting any field True will enable the output that's associated + output_mode_tuple (typedefs.gdb_output_mode): Setting any field True will enable the output that's associated with that field. Setting it False will disable the associated output """ global gdb_output_mode @@ -168,7 +168,7 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, command (str): The command that'll be sent control (bool): This param should be True if the command sent is ctrl+key instead of the regular command cli_output (bool): If True, returns the readable parsed cli output instead of gdb/mi garbage - send_with_file (bool): Custom commands declared in GDBCommandExtensions.py requires file communication. If + send_with_file (bool): Custom commands declared in gdbextensions.py requires file communication. If called command has any parameters, pass this as True file_contents_send (any type that pickle.dump supports): Arguments for the called custom gdb command recv_with_file (bool): Pass this as True if the called custom gdb command returns something @@ -200,13 +200,13 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, if gdb_output_mode.command_info: time0 = time() if not gdb_initialized: - raise type_defs.GDBInitializeException + raise typedefs.GDBInitializeException gdb_output = "" if send_with_file: - send_file = SysUtils.get_ipc_from_pince_file(currentpid) + send_file = utils.get_ipc_from_pince_file(currentpid) pickle.dump(file_contents_send, open(send_file, "wb")) if recv_with_file or cli_output: - recv_file = SysUtils.get_ipc_to_pince_file(currentpid) + recv_file = utils.get_ipc_to_pince_file(currentpid) # Truncating the recv_file because we wouldn't like to see output of previous command in case of errors open(recv_file, "w").close() @@ -218,7 +218,7 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, if control: child.sendcontrol(command) else: - command_file = SysUtils.get_gdb_command_file(currentpid) + command_file = utils.get_gdb_command_file(currentpid) command_fd = open(command_file, "r+") command_fd.truncate() command_fd.write(command) @@ -229,7 +229,7 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, child.sendline("cli-output source " + command_file) if not control: while not gdb_output: - sleep(type_defs.CONST_TIME.GDB_INPUT_SLEEP) + sleep(typedefs.CONST_TIME.GDB_INPUT_SLEEP) if cancel_send_command: break if not cancel_send_command: @@ -262,7 +262,7 @@ def state_observe_thread(): """ def check_inferior_status(): - matches = common_regexes.gdb_state_observe.findall(child.before) + matches = regexes.gdb_state_observe.findall(child.before) if len(matches) > 0: global stop_reason global inferior_status @@ -279,15 +279,15 @@ def check_inferior_status(): # Get the last match only to optimize parsing stop_info = matches[-1][0] if stop_info: - bp_num = common_regexes.breakpoint_number.search(stop_info) + bp_num = regexes.breakpoint_number.search(stop_info) # Return -1 for invalid breakpoints to ignore racing conditions - if bp_num and breakpoint_on_hit_dict.get(bp_num.group(1), -1) != type_defs.BREAKPOINT_ON_HIT.BREAK: + if bp_num and breakpoint_on_hit_dict.get(bp_num.group(1), -1) != typedefs.BREAKPOINT_ON_HIT.BREAK: return - stop_reason = type_defs.STOP_REASON.DEBUG - inferior_status = type_defs.INFERIOR_STATUS.INFERIOR_STOPPED + stop_reason = typedefs.STOP_REASON.DEBUG + inferior_status = typedefs.INFERIOR_STATUS.INFERIOR_STOPPED else: - inferior_status = type_defs.INFERIOR_STATUS.INFERIOR_RUNNING + inferior_status = typedefs.INFERIOR_STATUS.INFERIOR_RUNNING if old_status != inferior_status: with status_changed_condition: status_changed_condition.notify_all() @@ -301,8 +301,8 @@ def check_inferior_status(): if not child.before: continue check_inferior_status() - command_file = re.escape(SysUtils.get_gdb_command_file(currentpid)) - if common_regexes.gdb_command_source(command_file).search(child.before): + command_file = re.escape(utils.get_gdb_command_file(currentpid)) + if regexes.gdb_command_source(command_file).search(child.before): child.expect_exact("(gdb)") child.before = child.before.strip() check_inferior_status() @@ -335,11 +335,11 @@ def execute_func_temporary_interruption(func, *args, **kwargs): ???: Result of the given function. Return type depends on the given function """ old_status = inferior_status - if old_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - interrupt_inferior(type_defs.STOP_REASON.PAUSE) + if old_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + interrupt_inferior(typedefs.STOP_REASON.PAUSE) wait_for_stop() result = func(*args, **kwargs) - if old_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: + if old_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: continue_inferior() return result @@ -371,19 +371,19 @@ def wait_for_stop(timeout=1): timeout (float): Timeout time in seconds """ remaining_time = timeout - while inferior_status == type_defs.INFERIOR_STATUS.INFERIOR_RUNNING: - sleep(type_defs.CONST_TIME.GDB_INPUT_SLEEP) - remaining_time -= type_defs.CONST_TIME.GDB_INPUT_SLEEP + while inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + sleep(typedefs.CONST_TIME.GDB_INPUT_SLEEP) + remaining_time -= typedefs.CONST_TIME.GDB_INPUT_SLEEP if remaining_time < 0: break #:tag:Debug -def interrupt_inferior(interrupt_reason=type_defs.STOP_REASON.DEBUG): +def interrupt_inferior(interrupt_reason=typedefs.STOP_REASON.DEBUG): """Interrupt the inferior Args: - interrupt_reason (int): Just changes the global variable stop_reason. Can be a member of type_defs.STOP_REASON + interrupt_reason (int): Just changes the global variable stop_reason. Can be a member of typedefs.STOP_REASON """ if currentpid == -1: return @@ -440,7 +440,7 @@ def unignore_signal(signal_name): #:tag:GDBCommunication -def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): +def init_gdb(gdb_path=typedefs.PATHS.GDB_PATH): """Spawns gdb and initializes/resets some of the global variables Args: @@ -456,11 +456,11 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): global gdb_output global cancel_send_command global last_gdb_command - SysUtils.init_user_files() + utils.init_user_files() detach() # Temporary IPC_PATH, this little hack is needed because send_command requires a valid IPC_PATH - SysUtils.create_ipc_path(currentpid) + utils.create_ipc_path(currentpid) breakpoint_on_hit_dict.clear() chained_breakpoints.clear() @@ -468,7 +468,7 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): cancel_send_command = False last_gdb_command = "" - libpince_dir = SysUtils.get_libpince_directory() + libpince_dir = utils.get_libpince_directory() child = pexpect.spawn(f'sudo -E --preserve-env=PATH LC_NUMERIC=C {gdb_path} --nx --interpreter=mi', cwd=libpince_dir, encoding="utf-8") child.setecho(False) @@ -481,8 +481,8 @@ def init_gdb(gdb_path=type_defs.PATHS.GDB_PATH): gdb_initialized = True set_logging(False) send_command("source ./gdbinit_venv") - send_command("source " + SysUtils.get_user_path(type_defs.USER_PATHS.GDBINIT_PATH)) - SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_PATH)) + send_command("source " + utils.get_user_path(typedefs.USER_PATHS.GDBINIT_PATH)) + utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_PATH)) #:tag:GDBCommunication @@ -493,23 +493,23 @@ def set_logging(state): state (bool): Sets logging on if True, off if False """ send_command("set logging enabled off") - send_command("set logging file " + SysUtils.get_logging_file(currentpid)) + send_command("set logging file " + utils.get_logging_file(currentpid)) if state: send_command("set logging enabled on") #:tag:GDBCommunication def set_pince_paths(): - """Initializes $PINCE_PATH and $GDBINIT_AA_PATH convenience variables to make commands in GDBCommandExtensions.py - and ScriptUtils.py work. GDB scripts need to know libpince and .config directories, unfortunately they don't start + """Initializes $PINCE_PATH and $GDBINIT_AA_PATH convenience variables to make commands in gdbextensions.py + and gdbutils.py work. GDB scripts need to know libpince and .config directories, unfortunately they don't start from the place where script exists """ - libpince_dir = SysUtils.get_libpince_directory() + libpince_dir = utils.get_libpince_directory() pince_dir = os.path.dirname(libpince_dir) - gdbinit_aa_dir = SysUtils.get_user_path(type_defs.USER_PATHS.GDBINIT_AA_PATH) + gdbinit_aa_dir = utils.get_user_path(typedefs.USER_PATHS.GDBINIT_AA_PATH) send_command('set $GDBINIT_AA_PATH=' + '"' + gdbinit_aa_dir + '"') send_command('set $PINCE_PATH=' + '"' + pince_dir + '"') - send_command("source gdb_python_scripts/GDBCommandExtensions.py") + send_command("source gdb_python_scripts/gdbextensions.py") def init_referenced_dicts(pid): @@ -518,13 +518,13 @@ def init_referenced_dicts(pid): Args: pid (int,str): PID of the attached process """ - shelve.open(SysUtils.get_referenced_strings_file(pid), "c") - shelve.open(SysUtils.get_referenced_jumps_file(pid), "c") - shelve.open(SysUtils.get_referenced_calls_file(pid), "c") + shelve.open(utils.get_referenced_strings_file(pid), "c") + shelve.open(utils.get_referenced_jumps_file(pid), "c") + shelve.open(utils.get_referenced_calls_file(pid), "c") #:tag:Debug -def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): +def attach(pid, gdb_path=typedefs.PATHS.GDB_PATH): """Attaches gdb to the target and initializes some of the global variables Args: @@ -532,21 +532,21 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): gdb_path (str): Path of the gdb binary Returns: - int: A member of type_defs.ATTACH_RESULT + int: A member of typedefs.ATTACH_RESULT Note: If gdb is already initialized, gdb_path will be ignored """ global currentpid pid = int(pid) - traced_by = SysUtils.is_traced(pid) + traced_by = utils.is_traced(pid) pid_control_list = [ # Attaching PINCE to itself makes PINCE freeze immediately because gdb freezes the target on attach - (lambda: pid == self_pid, type_defs.ATTACH_RESULT.ATTACH_SELF), - (lambda: not SysUtils.is_process_valid(pid), type_defs.ATTACH_RESULT.PROCESS_NOT_VALID), - (lambda: pid == currentpid, type_defs.ATTACH_RESULT.ALREADY_DEBUGGING), - (lambda: traced_by is not None, type_defs.ATTACH_RESULT.ALREADY_TRACED), - (lambda: not can_attach(pid), type_defs.ATTACH_RESULT.PERM_DENIED) + (lambda: pid == self_pid, typedefs.ATTACH_RESULT.ATTACH_SELF), + (lambda: not utils.is_process_valid(pid), typedefs.ATTACH_RESULT.PROCESS_NOT_VALID), + (lambda: pid == currentpid, typedefs.ATTACH_RESULT.ALREADY_DEBUGGING), + (lambda: traced_by is not None, typedefs.ATTACH_RESULT.ALREADY_TRACED), + (lambda: not can_attach(pid), typedefs.ATTACH_RESULT.PERM_DENIED) ] for control_func, attach_result in pid_control_list: if control_func(): @@ -557,17 +557,17 @@ def attach(pid, gdb_path=type_defs.PATHS.GDB_PATH): global mem_file currentpid = pid mem_file = "/proc/" + str(currentpid) + "/mem" - SysUtils.create_ipc_path(pid) + utils.create_ipc_path(pid) send_command("attach " + str(pid)) set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() - SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_AA_PATH)) - return type_defs.ATTACH_RESULT.ATTACH_SUCCESSFUL + utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_AA_PATH)) + return typedefs.ATTACH_RESULT.ATTACH_SUCCESSFUL #:tag:Debug -def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs.PATHS.GDB_PATH): +def create_process(process_path, args="", ld_preload_path="", gdb_path=typedefs.PATHS.GDB_PATH): """Creates a new process for debugging and initializes some of the global variables Current process will be detached even if the create_process call fails Make sure to save your data before calling this monstrosity @@ -590,7 +590,7 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs if currentpid != -1 or not gdb_initialized: init_gdb(gdb_path) output = send_command("file " + process_path) - if common_regexes.gdb_error.search(output): + if regexes.gdb_error.search(output): print("An error occurred while trying to create process from the file at " + process_path) detach() return False @@ -611,11 +611,11 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=type_defs pid = get_inferior_pid() currentpid = int(pid) mem_file = "/proc/" + str(currentpid) + "/mem" - SysUtils.create_ipc_path(pid) + utils.create_ipc_path(pid) set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() - SysUtils.execute_script(SysUtils.get_user_path(type_defs.USER_PATHS.PINCEINIT_AA_PATH)) + utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_AA_PATH)) return True @@ -633,7 +633,7 @@ def detach(): gdb_initialized = False child.close() if old_pid != -1: - SysUtils.delete_ipc_path(old_pid) + utils.delete_ipc_path(old_pid) print("Detached from the process with PID:" + str(old_pid)) @@ -642,18 +642,18 @@ def toggle_attach(): """Detaches from the current process without ending the season if currently attached. Attaches back if detached Returns: - int: The new state of the process as a member of type_defs.TOGGLE_ATTACH + int: The new state of the process as a member of typedefs.TOGGLE_ATTACH None: If detaching or attaching fails """ if currentpid == -1: return if is_attached(): - if common_regexes.gdb_error.search(send_command("phase-out")): + if regexes.gdb_error.search(send_command("phase-out")): return - return type_defs.TOGGLE_ATTACH.DETACHED - if common_regexes.gdb_error.search(send_command("phase-in")): + return typedefs.TOGGLE_ATTACH.DETACHED + if regexes.gdb_error.search(send_command("phase-in")): return - return type_defs.TOGGLE_ATTACH.ATTACHED + return typedefs.TOGGLE_ATTACH.ATTACHED #:tag:Debug @@ -663,7 +663,7 @@ def is_attached(): Returns: bool: True if attached, False if not """ - if common_regexes.gdb_error.search(send_command("info proc")): + if regexes.gdb_error.search(send_command("info proc")): return False return True @@ -713,19 +713,19 @@ def read_pointer(pointer_type): """Reads the address pointed by this pointer Args: - pointer_type (PointerType): type_defs.PointerType class containing a base_address and an offsets list + pointer_type (PointerType): typedefs.PointerType class containing a base_address and an offsets list Returns: int: Final pointed address after dereferencing this pointer and it's offsets list None: If an error occurs while reading the given pointer """ - if not isinstance(pointer_type, type_defs.PointerType): + if not isinstance(pointer_type, typedefs.PointerType): raise TypeError("Passed non-PointerType to read_pointer!") - if inferior_arch == type_defs.INFERIOR_ARCH.ARCH_32: - value_index = type_defs.VALUE_INDEX.INDEX_INT32 + if inferior_arch == typedefs.INFERIOR_ARCH.ARCH_32: + value_index = typedefs.VALUE_INDEX.INDEX_INT32 else: - value_index = type_defs.VALUE_INDEX.INDEX_INT64 + value_index = typedefs.VALUE_INDEX.INDEX_INT64 # Simple addresses first, examine_expression takes much longer time, especially for larger tables try: @@ -762,19 +762,19 @@ def memory_handle(): #:tag:MemoryRW -def read_memory(address, value_index, length=None, zero_terminate=True, value_repr=type_defs.VALUE_REPR.UNSIGNED, - endian=type_defs.ENDIANNESS.HOST, mem_handle=None): +def read_memory(address, value_index, length=None, zero_terminate=True, value_repr=typedefs.VALUE_REPR.UNSIGNED, + endian=typedefs.ENDIANNESS.HOST, mem_handle=None): """Reads value from the given address Args: address (str, int): Can be a hex string or an integer. - value_index (int): Determines the type of data read. Can be a member of type_defs.VALUE_INDEX + value_index (int): Determines the type of data read. Can be a member of typedefs.VALUE_INDEX length (int): Length of the data that'll be read. Must be greater than 0. Only used when the value_index is INDEX_STRING or INDEX_AOB. Ignored otherwise zero_terminate (bool): If True, data will be split when a null character has been read. Only used when value_index is INDEX_STRING. Ignored otherwise - value_repr (int): Can be a member of type_defs.VALUE_REPR. Only usable with integer types - endian (int): Can be a member of type_defs.ENDIANNESS + value_repr (int): Can be a member of typedefs.VALUE_REPR. Only usable with integer types + endian (int): Can be a member of typedefs.ENDIANNESS mem_handle (BinaryIO): A file handle that points to the memory file of the current process This parameter is used for optimization, See memory_handle Don't forget to close the handle after you're done if you use this parameter manually @@ -796,8 +796,8 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re except: # print(str(address) + " is not a valid address") return - packed_data = type_defs.index_to_valuetype_dict.get(value_index, -1) - if type_defs.VALUE_INDEX.is_string(value_index): + packed_data = typedefs.index_to_valuetype_dict.get(value_index, -1) + if typedefs.VALUE_INDEX.is_string(value_index): try: length = int(length) except: @@ -806,8 +806,8 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re if not length > 0: # print("length must be greater than 0") return - expected_length = length * type_defs.string_index_to_multiplier_dict.get(value_index, 1) - elif value_index is type_defs.VALUE_INDEX.INDEX_AOB: + expected_length = length * typedefs.string_index_to_multiplier_dict.get(value_index, 1) + elif value_index is typedefs.VALUE_INDEX.INDEX_AOB: try: expected_length = int(length) except: @@ -824,7 +824,7 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re mem_handle = open(mem_file, "rb") mem_handle.seek(address) data_read = mem_handle.read(expected_length) - if endian != type_defs.ENDIANNESS.HOST and system_endianness != endian: + if endian != typedefs.ENDIANNESS.HOST and system_endianness != endian: data_read = data_read[::-1] except (OSError, ValueError): # TODO (read/write error output) @@ -833,8 +833,8 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re # Maybe creating a function that toggles logging on and off? Other functions could use it too # print("Can't access the memory at address " + hex(address) + " or offset " + hex(address + expected_length)) return - if type_defs.VALUE_INDEX.is_string(value_index): - encoding, option = type_defs.string_index_to_encoding_dict[value_index] + if typedefs.VALUE_INDEX.is_string(value_index): + encoding, option = typedefs.string_index_to_encoding_dict[value_index] returned_string = data_read.decode(encoding, option) if zero_terminate: if returned_string.startswith('\x00'): @@ -842,20 +842,20 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re else: returned_string = returned_string.split('\x00')[0] return returned_string[0:length] - elif value_index is type_defs.VALUE_INDEX.INDEX_AOB: + elif value_index is typedefs.VALUE_INDEX.INDEX_AOB: return " ".join(format(n, '02x') for n in data_read) else: - is_integer = type_defs.VALUE_INDEX.is_integer(value_index) - if is_integer and value_repr == type_defs.VALUE_REPR.SIGNED: + is_integer = typedefs.VALUE_INDEX.is_integer(value_index) + if is_integer and value_repr == typedefs.VALUE_REPR.SIGNED: data_type = data_type.lower() result = struct.unpack_from(data_type, data_read)[0] - if is_integer and value_repr == type_defs.VALUE_REPR.HEX: + if is_integer and value_repr == typedefs.VALUE_REPR.HEX: return hex(result) return result #:tag:MemoryRW -def write_memory(address, value_index, value, endian=type_defs.ENDIANNESS.HOST): +def write_memory(address, value_index, value, endian=typedefs.ENDIANNESS.HOST): """Sets the given value to the given address If any errors occurs while setting value to the according address, it'll be ignored but the information about @@ -863,9 +863,9 @@ def write_memory(address, value_index, value, endian=type_defs.ENDIANNESS.HOST): Args: address (str, int): Can be a hex string or an integer - value_index (int): Can be a member of type_defs.VALUE_INDEX + value_index (int): Can be a member of typedefs.VALUE_INDEX value (str): The value that'll be written to the given address - endian (int): Can be a member of type_defs.ENDIANNESS + endian (int): Can be a member of typedefs.ENDIANNESS Notes: TODO: Implement a mem_handle parameter for optimization, check read_memory for an example @@ -878,19 +878,19 @@ def write_memory(address, value_index, value, endian=type_defs.ENDIANNESS.HOST): except: # print(str(address) + " is not a valid address") return - write_data = SysUtils.parse_string(value, value_index) + write_data = utils.parse_string(value, value_index) if write_data is None: return - encoding, option = type_defs.string_index_to_encoding_dict.get(value_index, (None, None)) + encoding, option = typedefs.string_index_to_encoding_dict.get(value_index, (None, None)) if encoding is None: - if value_index is type_defs.VALUE_INDEX.INDEX_AOB: + if value_index is typedefs.VALUE_INDEX.INDEX_AOB: write_data = bytearray(write_data) else: - data_type = type_defs.index_to_struct_pack_dict.get(value_index, -1) + data_type = typedefs.index_to_struct_pack_dict.get(value_index, -1) write_data = struct.pack(data_type, write_data) else: write_data = write_data.encode(encoding, option) + b"\x00" # Zero-terminated by default - if endian != type_defs.ENDIANNESS.HOST and system_endianness != endian: + if endian != typedefs.ENDIANNESS.HOST and system_endianness != endian: write_data = write_data[::-1] FILE = open(mem_file, "rb+") try: @@ -920,7 +920,7 @@ def disassemble(expression, offset_or_address): output = send_command("disas /r " + expression + "," + offset_or_address) disas_data = [] for line in output.splitlines(): - result = common_regexes.disassemble_output.search(line) + result = regexes.disassemble_output.search(line) if result: disas_data.append(result.groups()) return disas_data @@ -934,7 +934,7 @@ def examine_expression(expression): expression (str): Any gdb expression Returns: - type_defs.tuple_examine_expression: Evaluated value, address and symbol in a tuple + typedefs.tuple_examine_expression: Evaluated value, address and symbol in a tuple Any erroneous field will be returned as None instead of str """ return send_command("pince-examine-expressions", send_with_file=True, file_contents_send=[expression], @@ -948,7 +948,7 @@ def examine_expressions(expression_list): expression_list (list): List of gdb expressions as str Returns: - list: List of type_defs.tuple_examine_expression + list: List of typedefs.tuple_examine_expression """ if not expression_list: return [] @@ -987,7 +987,7 @@ def get_thread_info(): None: If the output doesn't fit the regex """ thread_info = send_command("info threads") - return re.sub(r'\\"', r'"', common_regexes.thread_info.search(thread_info).group(1)) + return re.sub(r'\\"', r'"', regexes.thread_info.search(thread_info).group(1)) #:tag:Assembly @@ -1019,21 +1019,21 @@ def find_closest_instruction_address(address, instruction_location="next", instr disas_data = disassemble(address + offset, address) if not disas_data: if instruction_location != "next": - start_address = hex(SysUtils.get_region_info(currentpid, address).start) + start_address = hex(utils.get_region_info(currentpid, address).start) disas_data = disassemble(start_address, address) if instruction_location == "next": try: - return SysUtils.extract_address(disas_data[instruction_count][0]) + return utils.extract_address(disas_data[instruction_count][0]) except IndexError: - return hex(SysUtils.get_region_info(currentpid, address).end) + return hex(utils.get_region_info(currentpid, address).end) else: try: - return SysUtils.extract_address(disas_data[-instruction_count][0]) + return utils.extract_address(disas_data[-instruction_count][0]) except IndexError: try: return start_address except UnboundLocalError: - return hex(SysUtils.get_region_info(currentpid, address).start) + return hex(utils.get_region_info(currentpid, address).start) #:tag:GDBExpressions @@ -1095,7 +1095,7 @@ def get_inferior_pid(): str: pid """ output = send_command("info inferior") - return common_regexes.inferior_pid.search(output).group(1) + return regexes.inferior_pid.search(output).group(1) #:tag:InferiorInformation @@ -1103,11 +1103,11 @@ def get_inferior_arch(): """Returns the architecture of the current inferior Returns: - int: A member of type_defs.INFERIOR_ARCH + int: A member of typedefs.INFERIOR_ARCH """ if parse_and_eval("$rax") == "void": - return type_defs.INFERIOR_ARCH.ARCH_32 - return type_defs.INFERIOR_ARCH.ARCH_64 + return typedefs.INFERIOR_ARCH.ARCH_32 + return typedefs.INFERIOR_ARCH.ARCH_64 #:tag:Registers @@ -1115,7 +1115,7 @@ def read_registers(): """Returns the current registers Returns: - dict: A dict that holds general, flag and segment registers. Check type_defs.REGISTERS for the full list + dict: A dict that holds general, flag and segment registers. Check typedefs.REGISTERS for the full list """ return send_command("pince-read-registers", recv_with_file=True) @@ -1125,7 +1125,7 @@ def read_float_registers(): """Returns the current floating point registers Returns: - dict: A dict that holds floating point registers. Check type_defs.REGISTERS.FLOAT for the full list + dict: A dict that holds floating point registers. Check typedefs.REGISTERS.FLOAT for the full list Note: Returned xmm values are based on xmm.v4_float @@ -1151,7 +1151,7 @@ def set_register_flag(flag, value): """Sets given register flag to given value Args: - flag (str): A member of type_defs.REGISTERS.FLAG + flag (str): A member of typedefs.REGISTERS.FLAG value (Union[int,str]): 0 or 1 """ registers = read_registers() @@ -1159,8 +1159,8 @@ def set_register_flag(flag, value): registers[flag] = value if value != "0" and value != "1": raise Exception(value + " isn't valid value. It can be only 0 or 1") - if flag not in type_defs.REGISTERS.FLAG: - raise Exception(flag + " isn't a valid flag, must be a member of type_defs.REGISTERS.FLAG") + if flag not in typedefs.REGISTERS.FLAG: + raise Exception(flag + " isn't a valid flag, must be a member of typedefs.REGISTERS.FLAG") eflags_hex_value = hex(int( registers["of"] + registers["df"] + registers["if"] + registers["tf"] + registers["sf"] + registers[ "zf"] + "0" + registers["af"] + "0" + registers["pf"] + "0" + registers["cf"], 2)) @@ -1294,7 +1294,7 @@ def nop_instruction(start_address, length_of_instr): modified_instructions_dict[start_address] = old_aob nop_aob = '90 ' * length_of_instr - write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, nop_aob) + write_memory(start_address, typedefs.VALUE_INDEX.INDEX_AOB, nop_aob) #:tag:MemoryRW @@ -1314,7 +1314,7 @@ def modify_instruction(start_address, array_of_bytes): global modified_instructions_dict if start_address not in modified_instructions_dict: modified_instructions_dict[start_address] = old_aob - write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, array_of_bytes) + write_memory(start_address, typedefs.VALUE_INDEX.INDEX_AOB, array_of_bytes) #:tag:MemoryRW @@ -1329,7 +1329,7 @@ def restore_instruction(start_address): """ global modified_instructions_dict array_of_bytes = modified_instructions_dict.pop(start_address) - write_memory(start_address, type_defs.VALUE_INDEX.INDEX_AOB, array_of_bytes) + write_memory(start_address, typedefs.VALUE_INDEX.INDEX_AOB, array_of_bytes) #:tag:BreakWatchpoints @@ -1337,7 +1337,7 @@ def get_breakpoint_info(): """Returns current breakpoint/watchpoint list Returns: - list: A list of type_defs.tuple_breakpoint_info where; + list: A list of typedefs.tuple_breakpoint_info where; number is the gdb breakpoint number breakpoint_type is the breakpoint type disp shows what will be done after breakpoint hits @@ -1361,7 +1361,7 @@ def get_breakpoint_info(): # Temporary fix for https://sourceware.org/bugzilla/show_bug.cgi?id=9659 # TODO:Delete this line when gdb or pygdbmi fixes the problem raw_info = re.sub("script={(.*?)}", "script=[\g<1>]", raw_info) # Please refer to issue #53 - for item in SysUtils.parse_response(raw_info)['payload']['BreakpointTable']['body']: + for item in utils.parse_response(raw_info)['payload']['BreakpointTable']['body']: item = defaultdict(lambda: "", item) number, breakpoint_type, disp, enabled, address, what, condition, hit_count, enable_count = \ item['number'], item['type'], item['disp'], item['enabled'], item['addr'], item['what'], item['cond'], \ @@ -1373,21 +1373,21 @@ def get_breakpoint_info(): number = number.split(".")[0] breakpoint_type, disp, condition, hit_count = multiple_break_data[number] if what: - address = SysUtils.extract_address(what) + address = utils.extract_address(what) if not address: address = examine_expression(what).address - on_hit_dict_value = breakpoint_on_hit_dict.get(number, type_defs.BREAKPOINT_ON_HIT.BREAK) - on_hit = type_defs.on_hit_to_text_dict.get(on_hit_dict_value, "Unknown") + on_hit_dict_value = breakpoint_on_hit_dict.get(number, typedefs.BREAKPOINT_ON_HIT.BREAK) + on_hit = typedefs.on_hit_to_text_dict.get(on_hit_dict_value, "Unknown") if breakpoint_type.find("breakpoint") >= 0: size = 1 else: - possible_size = common_regexes.breakpoint_size.search(what) + possible_size = regexes.breakpoint_size.search(what) if possible_size: size = int(possible_size.group(1)) else: size = 1 returned_list.append( - type_defs.tuple_breakpoint_info(number, breakpoint_type, disp, enabled, address, size, on_hit, hit_count, + typedefs.tuple_breakpoint_info(number, breakpoint_type, disp, enabled, address, size, on_hit, hit_count, enable_count, condition)) return returned_list @@ -1402,7 +1402,7 @@ def check_address_in_breakpoints(address, range_offset=0): checked instead of just address itself Returns: - type_defs.tuple_breakpoint_info: Info of the existing breakpoint for given address range + typedefs.tuple_breakpoint_info: Info of the existing breakpoint for given address range None: If it doesn't exist """ if type(address) != int: @@ -1430,7 +1430,7 @@ def hardware_breakpoint_available(): breakpoint_info = get_breakpoint_info() hw_bp_total = 0 for item in breakpoint_info: - if common_regexes.hw_breakpoint_count.search(item.breakpoint_type): + if regexes.hw_breakpoint_count.search(item.breakpoint_type): hw_bp_total += 1 # Maximum number of hardware breakpoints is limited to 4 in x86 architecture @@ -1438,15 +1438,15 @@ def hardware_breakpoint_available(): #:tag:BreakWatchpoints -def add_breakpoint(expression, breakpoint_type=type_defs.BREAKPOINT_TYPE.HARDWARE_BP, - on_hit=type_defs.BREAKPOINT_ON_HIT.BREAK): +def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE_BP, + on_hit=typedefs.BREAKPOINT_ON_HIT.BREAK): """Adds a breakpoint at the address evaluated by the given expression. Uses a software breakpoint if all hardware breakpoint slots are being used Args: expression (str): Any gdb expression - breakpoint_type (int): Can be a member of type_defs.BREAKPOINT_TYPE - on_hit (int): Can be a member of type_defs.BREAKPOINT_ON_HIT + breakpoint_type (int): Can be a member of typedefs.BREAKPOINT_TYPE + on_hit (int): Can be a member of typedefs.BREAKPOINT_ON_HIT Returns: str: Number of the breakpoint set @@ -1460,17 +1460,17 @@ def add_breakpoint(expression, breakpoint_type=type_defs.BREAKPOINT_TYPE.HARDWAR if check_address_in_breakpoints(str_address): print("breakpoint/watchpoint for address " + str_address + " is already set") return - if breakpoint_type == type_defs.BREAKPOINT_TYPE.HARDWARE_BP: + if breakpoint_type == typedefs.BREAKPOINT_TYPE.HARDWARE_BP: if hardware_breakpoint_available(): output = send_command("hbreak *" + str_address) else: print("All hardware breakpoint slots are being used, using a software breakpoint instead") output = send_command("break *" + str_address) - elif breakpoint_type == type_defs.BREAKPOINT_TYPE.SOFTWARE_BP: + elif breakpoint_type == typedefs.BREAKPOINT_TYPE.SOFTWARE_BP: output = send_command("break *" + str_address) - if common_regexes.breakpoint_created.search(output): + if regexes.breakpoint_created.search(output): global breakpoint_on_hit_dict - number = common_regexes.breakpoint_number.search(output).group(1) + number = regexes.breakpoint_number.search(output).group(1) breakpoint_on_hit_dict[number] = on_hit return number else: @@ -1478,15 +1478,15 @@ def add_breakpoint(expression, breakpoint_type=type_defs.BREAKPOINT_TYPE.HARDWAR #:tag:BreakWatchpoints -def add_watchpoint(expression, length=4, watchpoint_type=type_defs.WATCHPOINT_TYPE.BOTH, - on_hit=type_defs.BREAKPOINT_ON_HIT.BREAK): +def add_watchpoint(expression, length=4, watchpoint_type=typedefs.WATCHPOINT_TYPE.BOTH, + on_hit=typedefs.BREAKPOINT_ON_HIT.BREAK): """Adds a watchpoint at the address evaluated by the given expression Args: expression (str): Any gdb expression length (int): Length of the watchpoint - watchpoint_type (int): Can be a member of type_defs.WATCHPOINT_TYPE - on_hit (int): Can be a member of type_defs.BREAKPOINT_ON_HIT + watchpoint_type (int): Can be a member of typedefs.WATCHPOINT_TYPE + on_hit (int): Can be a member of typedefs.BREAKPOINT_ON_HIT Returns: list: Numbers of the successfully set breakpoints as strings @@ -1495,18 +1495,18 @@ def add_watchpoint(expression, length=4, watchpoint_type=type_defs.WATCHPOINT_TY if not str_address: print("expression for watchpoint is not valid") return - if watchpoint_type == type_defs.WATCHPOINT_TYPE.WRITE_ONLY: + if watchpoint_type == typedefs.WATCHPOINT_TYPE.WRITE_ONLY: watch_command = "watch" - elif watchpoint_type == type_defs.WATCHPOINT_TYPE.READ_ONLY: + elif watchpoint_type == typedefs.WATCHPOINT_TYPE.READ_ONLY: watch_command = "rwatch" - elif watchpoint_type == type_defs.WATCHPOINT_TYPE.BOTH: + elif watchpoint_type == typedefs.WATCHPOINT_TYPE.BOTH: watch_command = "awatch" remaining_length = length breakpoints_set = [] arch = get_inferior_arch() str_address_int = int(str_address, 16) breakpoint_addresses = [] - if arch == type_defs.INFERIOR_ARCH.ARCH_64: + if arch == typedefs.INFERIOR_ARCH.ARCH_64: max_length = 8 else: max_length = 4 @@ -1523,12 +1523,12 @@ def add_watchpoint(expression, length=4, watchpoint_type=type_defs.WATCHPOINT_TY breakpoint_length = remaining_length cmd = f"{watch_command} * (char[{breakpoint_length}] *) {hex(str_address_int)}" output = execute_func_temporary_interruption(send_command, cmd) - if common_regexes.breakpoint_created.search(output): + if regexes.breakpoint_created.search(output): breakpoint_addresses.append([str_address_int, breakpoint_length]) else: print("Failed to create a watchpoint at address " + hex(str_address_int) + ". Bailing out...") break - breakpoint_number = common_regexes.breakpoint_number.search(output).group(1) + breakpoint_number = regexes.breakpoint_number.search(output).group(1) breakpoints_set.append(breakpoint_number) global breakpoint_on_hit_dict breakpoint_on_hit_dict[breakpoint_number] = on_hit @@ -1545,7 +1545,7 @@ def modify_breakpoint(expression, modify_what, condition=None, count=None): Args: expression (str): Any gdb expression - modify_what (int): Can be a member of type_defs.BREAKPOINT_MODIFY_TYPES + modify_what (int): Can be a member of typedefs.BREAKPOINT_MODIFY_TYPES This function modifies condition of the breakpoint if CONDITION, enables the breakpoint if ENABLE, disables the breakpoint if DISABLE, enables once then disables after hit if ENABLE_ONCE, enables for specified count then disables after the count is reached if ENABLE_COUNT, enables once then deletes the breakpoint if ENABLE_DELETE @@ -1556,12 +1556,12 @@ def modify_breakpoint(expression, modify_what, condition=None, count=None): bool: True if the condition has been set successfully, False otherwise Examples: - modify_what-->type_defs.BREAKPOINT_MODIFY_TYPES.CONDITION + modify_what-->typedefs.BREAKPOINT_MODIFY_TYPES.CONDITION condition-->$eax==0x523 condition-->$rax>0 && ($rbp<0 || $rsp==0) condition-->printf($r10)==3 - modify_what-->type_defs.BREAKPOINT_MODIFY_TYPES.ENABLE_COUNT + modify_what-->typedefs.BREAKPOINT_MODIFY_TYPES.ENABLE_COUNT count-->10 """ str_address = examine_expression(expression).address @@ -1582,18 +1582,18 @@ def modify_breakpoint(expression, modify_what, condition=None, count=None): continue else: breakpoint_number = found_breakpoint.number - if modify_what == type_defs.BREAKPOINT_MODIFY.CONDITION: + if modify_what == typedefs.BREAKPOINT_MODIFY.CONDITION: if condition is None: print("Please set condition first") return False send_command("condition " + breakpoint_number + " " + condition) - elif modify_what == type_defs.BREAKPOINT_MODIFY.ENABLE: + elif modify_what == typedefs.BREAKPOINT_MODIFY.ENABLE: send_command("enable " + breakpoint_number) - elif modify_what == type_defs.BREAKPOINT_MODIFY.DISABLE: + elif modify_what == typedefs.BREAKPOINT_MODIFY.DISABLE: send_command("disable " + breakpoint_number) - elif modify_what == type_defs.BREAKPOINT_MODIFY.ENABLE_ONCE: + elif modify_what == typedefs.BREAKPOINT_MODIFY.ENABLE_ONCE: send_command("enable once " + breakpoint_number) - elif modify_what == type_defs.BREAKPOINT_MODIFY.ENABLE_COUNT: + elif modify_what == typedefs.BREAKPOINT_MODIFY.ENABLE_COUNT: if count is None: print("Please set count first") return False @@ -1601,7 +1601,7 @@ def modify_breakpoint(expression, modify_what, condition=None, count=None): print("Count can't be lower than 1") return False send_command("enable count " + str(count) + " " + breakpoint_number) - elif modify_what == type_defs.BREAKPOINT_MODIFY.ENABLE_DELETE: + elif modify_what == typedefs.BREAKPOINT_MODIFY.ENABLE_DELETE: send_command("enable delete " + breakpoint_number) else: print("Parameter modify_what is not valid") @@ -1656,13 +1656,13 @@ def track_watchpoint(expression, length, watchpoint_type): Args: expression (str): Any gdb expression length (int): Length of the watchpoint - watchpoint_type (int): Can be a member of type_defs.WATCHPOINT_TYPE + watchpoint_type (int): Can be a member of typedefs.WATCHPOINT_TYPE Returns: list: Numbers of the successfully set breakpoints as strings None: If fails to set any watchpoint """ - breakpoints = add_watchpoint(expression, length, watchpoint_type, type_defs.BREAKPOINT_ON_HIT.FIND_CODE) + breakpoints = add_watchpoint(expression, length, watchpoint_type, typedefs.BREAKPOINT_ON_HIT.FIND_CODE) if not breakpoints: return for breakpoint in breakpoints: @@ -1691,7 +1691,7 @@ def get_track_watchpoint_info(watchpoint_list): float_info-->(dict) Same dict returned from read_float_registers() disas_info-->(str) A small section that's disassembled just after previous_pc_counter """ - track_watchpoint_file = SysUtils.get_track_watchpoint_file(currentpid, watchpoint_list) + track_watchpoint_file = utils.get_track_watchpoint_file(currentpid, watchpoint_list) try: output = pickle.load(open(track_watchpoint_file, "rb")) except: @@ -1714,7 +1714,7 @@ def track_breakpoint(expression, register_expressions): str: Number of the breakpoint set None: If fails to set any breakpoint """ - breakpoint = add_breakpoint(expression, on_hit=type_defs.BREAKPOINT_ON_HIT.FIND_ADDR) + breakpoint = add_breakpoint(expression, on_hit=typedefs.BREAKPOINT_ON_HIT.FIND_ADDR) if not breakpoint: return send_command("commands " + breakpoint @@ -1739,7 +1739,7 @@ def get_track_breakpoint_info(breakpoint): value-->(str) Value calculated by given register expression as hex str count-->(int) How many times this expression has been reached """ - track_breakpoint_file = SysUtils.get_track_breakpoint_file(currentpid, breakpoint) + track_breakpoint_file = utils.get_track_breakpoint_file(currentpid, breakpoint) try: output = pickle.load(open(track_breakpoint_file, "rb")) except: @@ -1749,7 +1749,7 @@ def get_track_breakpoint_info(breakpoint): #:tag:Tools def trace_instructions(expression, max_trace_count=1000, trigger_condition="", stop_condition="", - step_mode=type_defs.STEP_MODE.SINGLE_STEP, + step_mode=typedefs.STEP_MODE.SINGLE_STEP, stop_after_trace=False, collect_general_registers=True, collect_flag_registers=True, collect_segment_registers=True, collect_float_registers=True): """Starts tracing instructions at the address evaluated by the given expression @@ -1762,7 +1762,7 @@ def trace_instructions(expression, max_trace_count=1000, trigger_condition="", s max_trace_count (int): Maximum number of steps will be taken while tracing. Must be greater than or equal to 1 trigger_condition (str): Optional, any gdb expression. Tracing will start if the condition is met stop_condition (str): Optional, any gdb expression. Tracing will stop whenever the condition is met - step_mode (int): Can be a member of type_defs.STEP_MODE + step_mode (int): Can be a member of typedefs.STEP_MODE stop_after_trace (bool): Inferior won't be continuing after the tracing process collect_general_registers (bool): Collect general registers while stepping collect_flag_registers (bool): Collect flag registers while stepping @@ -1779,12 +1779,12 @@ def trace_instructions(expression, max_trace_count=1000, trigger_condition="", s if type(max_trace_count) != int: print("max_trace_count must be an integer") return - breakpoint = add_breakpoint(expression, on_hit=type_defs.BREAKPOINT_ON_HIT.TRACE) + breakpoint = add_breakpoint(expression, on_hit=typedefs.BREAKPOINT_ON_HIT.TRACE) if not breakpoint: return - modify_breakpoint(expression, type_defs.BREAKPOINT_MODIFY.CONDITION, condition=trigger_condition) - contents_send = (type_defs.TRACE_STATUS.STATUS_IDLE, "") - trace_status_file = SysUtils.get_trace_instructions_status_file(currentpid, breakpoint) + modify_breakpoint(expression, typedefs.BREAKPOINT_MODIFY.CONDITION, condition=trigger_condition) + contents_send = (typedefs.TRACE_STATUS.STATUS_IDLE, "") + trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) pickle.dump(contents_send, open(trace_status_file, "wb")) param_str = ( breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_general_registers, @@ -1813,7 +1813,7 @@ def get_trace_instructions_info(breakpoint): Any "call" instruction creates a node in SINGLE_STEP mode Any "ret" instruction creates a parent regardless of the mode """ - trace_instructions_file = SysUtils.get_trace_instructions_file(currentpid, breakpoint) + trace_instructions_file = utils.get_trace_instructions_file(currentpid, breakpoint) try: output = json.load(open(trace_instructions_file, "r"), object_pairs_hook=OrderedDict) except: @@ -1831,12 +1831,12 @@ def get_trace_instructions_status(breakpoint): Returns: tuple:(status_id, status_str) - status_id-->(int) A member of type_defs.TRACE_STATUS - status_str-->(str) Status string, only used with type_defs.TRACE_STATUS.STATUS_TRACING + status_id-->(int) A member of typedefs.TRACE_STATUS + status_str-->(str) Status string, only used with typedefs.TRACE_STATUS.STATUS_TRACING Returns a tuple of (None, "") if fails to gather info """ - trace_status_file = SysUtils.get_trace_instructions_status_file(currentpid, breakpoint) + trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) try: output = pickle.load(open(trace_status_file, "rb")) except: @@ -1851,8 +1851,8 @@ def cancel_trace_instructions(breakpoint): Args: breakpoint (str): breakpoint number, must be returned from trace_instructions() """ - status_info = (type_defs.TRACE_STATUS.STATUS_CANCELED, "") - trace_status_file = SysUtils.get_trace_instructions_status_file(currentpid, breakpoint) + status_info = (typedefs.TRACE_STATUS.STATUS_CANCELED, "") + trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) pickle.dump(status_info, open(trace_status_file, "wb")) @@ -1871,7 +1871,7 @@ def call_function_from_inferior(expression): call_function_from_inferior("printf('123')") returns ("$26","3") """ result = execute_func_temporary_interruption(send_command, f"call (void*(*)(char*, int)) {expression}") - filtered_result = common_regexes.convenience_variable.search(result) + filtered_result = regexes.convenience_variable.search(result) if filtered_result: return filtered_result.group(1), filtered_result.group(2) return False, False @@ -1886,7 +1886,7 @@ def find_entry_point(): None: If fails to find an entry point """ result = send_command("info file") - filtered_result = common_regexes.entry_point.search(result) + filtered_result = regexes.entry_point.search(result) if filtered_result: return filtered_result.group(1) @@ -1944,7 +1944,7 @@ def dissect_code(region_list, discard_invalid_strings=True): Args: region_list (list): A list of (start_address, end_address) -> (str, str) - Can be returned from functions like SysUtils.filter_regions + Can be returned from functions like utils.filter_regions discard_invalid_strings (bool): Entries that can't be decoded as utf-8 won't be included in referenced strings """ send_command("pince-dissect-code", send_with_file=True, file_contents_send=(region_list, discard_invalid_strings)) @@ -1967,7 +1967,7 @@ def get_dissect_code_status(): Returns a tuple of ("", "", "", 0, 0, 0) if fails to gather info """ - dissect_code_status_file = SysUtils.get_dissect_code_status_file(currentpid) + dissect_code_status_file = utils.get_dissect_code_status_file(currentpid) try: output = pickle.load(open(dissect_code_status_file, "rb")) except: @@ -2012,22 +2012,22 @@ def get_dissect_code_data(referenced_strings=True, referenced_jumps=True, refere """ dict_list = [] if referenced_strings: - dict_list.append(shelve.open(SysUtils.get_referenced_strings_file(currentpid), "r")) + dict_list.append(shelve.open(utils.get_referenced_strings_file(currentpid), "r")) if referenced_jumps: - dict_list.append(shelve.open(SysUtils.get_referenced_jumps_file(currentpid), "r")) + dict_list.append(shelve.open(utils.get_referenced_jumps_file(currentpid), "r")) if referenced_calls: - dict_list.append(shelve.open(SysUtils.get_referenced_calls_file(currentpid), "r")) + dict_list.append(shelve.open(utils.get_referenced_calls_file(currentpid), "r")) return dict_list #:tag:Tools -def search_referenced_strings(searched_str, value_index=type_defs.VALUE_INDEX.INDEX_STRING_UTF8, case_sensitive=False, +def search_referenced_strings(searched_str, value_index=typedefs.VALUE_INDEX.INDEX_STRING_UTF8, case_sensitive=False, enable_regex=False): """Searches for given str in the referenced strings Args: searched_str (str): String that will be searched - value_index (int): Can be a member of type_defs.VALUE_INDEX + value_index (int): Can be a member of typedefs.VALUE_INDEX case_sensitive (bool): If True, search will be case sensitive enable_regex (bool): If True, searched_str will be treated as a regex expression @@ -2096,6 +2096,6 @@ def complete_command(gdb_command): """ returned_list = [] for item in send_command("complete " + gdb_command, cli_output=True).splitlines(): - if not common_regexes.max_completions_reached.search(item): + if not regexes.max_completions_reached.search(item): returned_list.append(item) return returned_list diff --git a/libpince/gdb_python_scripts/GDBCommandExtensions.py b/libpince/gdb_python_scripts/gdbextensions.py similarity index 82% rename from libpince/gdb_python_scripts/GDBCommandExtensions.py rename to libpince/gdb_python_scripts/gdbextensions.py index 69076f49..d4414ca6 100644 --- a/libpince/gdb_python_scripts/GDBCommandExtensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -23,13 +23,13 @@ PINCE_PATH = gdbvalue.string() sys.path.append(PINCE_PATH) # Adds the PINCE directory to PYTHONPATH to import libraries from PINCE -from libpince.gdb_python_scripts import ScriptUtils -from libpince import SysUtils, type_defs, common_regexes +from libpince.gdb_python_scripts import gdbutils +from libpince import utils, typedefs, regexes inferior = gdb.selected_inferior() pid = inferior.pid -recv_file = SysUtils.get_ipc_from_pince_file(pid) -send_file = SysUtils.get_ipc_to_pince_file(pid) +recv_file = utils.get_ipc_from_pince_file(pid) +send_file = utils.get_ipc_to_pince_file(pid) lib = None @@ -53,7 +53,7 @@ def send_to_pince(contents_send): pickle.dump(contents_send, open(send_file, "wb")) -ScriptUtils.gdbinit() +gdbutils.gdbinit() class IgnoreErrors(gdb.Command): @@ -102,9 +102,9 @@ def __init__(self): super(ReadRegisters, self).__init__("pince-read-registers", gdb.COMMAND_USER) def invoke(self, arg, from_tty): - registers = ScriptUtils.get_general_registers() - registers.update(ScriptUtils.get_flag_registers()) - registers.update(ScriptUtils.get_segment_registers()) + registers = gdbutils.get_general_registers() + registers.update(gdbutils.get_flag_registers()) + registers.update(gdbutils.get_segment_registers()) send_to_pince(registers) @@ -113,7 +113,7 @@ def __init__(self): super(ReadFloatRegisters, self).__init__("pince-read-float-registers", gdb.COMMAND_USER) def invoke(self, arg, from_tty): - send_to_pince(ScriptUtils.get_float_registers()) + send_to_pince(gdbutils.get_float_registers()) class GetStackTraceInfo(gdb.Command): @@ -122,18 +122,18 @@ def __init__(self): def invoke(self, arg, from_tty): stacktrace_info_list = [] - if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: + if gdbutils.current_arch == typedefs.INFERIOR_ARCH.ARCH_64: sp_register = "rsp" else: sp_register = "esp" - stack_pointer = ScriptUtils.examine_expression(f"${sp_register}").address + stack_pointer = gdbutils.examine_expression(f"${sp_register}").address if not stack_pointer: print(f"Cannot get the value of ${sp_register}") send_to_pince(stacktrace_info_list) return stack_pointer = int(stack_pointer, 16) result = gdb.execute("bt", from_tty, to_string=True) - max_frame = common_regexes.max_frame_count.findall(result)[-1] + max_frame = regexes.max_frame_count.findall(result)[-1] # +1 because frame numbers start from 0 for item in range(int(max_frame) + 1): @@ -141,12 +141,12 @@ def invoke(self, arg, from_tty): result = gdb.execute(f"info frame {item}", from_tty, to_string=True) except: break - frame_address = common_regexes.frame_address.search(result).group(1) + frame_address = regexes.frame_address.search(result).group(1) difference = hex(int(frame_address, 16) - stack_pointer) frame_address_with_difference = frame_address + "(" + sp_register + "+" + difference + ")" - return_address = common_regexes.return_address.search(result) + return_address = regexes.return_address.search(result) if return_address: - return_address_with_info = ScriptUtils.examine_expression(return_address.group(1)).all + return_address_with_info = gdbutils.examine_expression(return_address.group(1)).all else: return_address_with_info = "<>" stacktrace_info_list.append([return_address_with_info, frame_address_with_difference]) @@ -159,7 +159,7 @@ def __init__(self): def invoke(self, arg, from_tty): stack_info_list = [] - if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: + if gdbutils.current_arch == typedefs.INFERIOR_ARCH.ARCH_64: chunk_size = 8 int_format = "Q" sp_register = "rsp" @@ -167,13 +167,13 @@ def invoke(self, arg, from_tty): chunk_size = 4 int_format = "I" sp_register = "esp" - sp_address = ScriptUtils.examine_expression(f"${sp_register}").address + sp_address = gdbutils.examine_expression(f"${sp_register}").address if not sp_address: print(f"Cannot get the value of ${sp_register}") send_to_pince(stack_info_list) return sp_address = int(sp_address, 16) - with open(ScriptUtils.mem_file, "rb") as FILE: + with open(gdbutils.mem_file, "rb") as FILE: try: old_position = FILE.seek(sp_address) except (OSError, ValueError): @@ -198,7 +198,7 @@ def invoke(self, arg, from_tty): except (OSError, ValueError): pointer_data = "" else: - symbol = ScriptUtils.examine_expression(hex_repr).symbol + symbol = gdbutils.examine_expression(hex_repr).symbol if not symbol: pointer_data = "(str)" + read_pointer.decode("utf-8", "ignore") else: @@ -214,7 +214,7 @@ def __init__(self): def invoke(self, arg, from_tty): return_address_list = [] result = gdb.execute("bt", from_tty, to_string=True) - max_frame = common_regexes.max_frame_count.findall(result)[-1] + max_frame = regexes.max_frame_count.findall(result)[-1] # +1 because frame numbers start from 0 for item in range(int(max_frame) + 1): @@ -222,9 +222,9 @@ def invoke(self, arg, from_tty): result = gdb.execute(f"info frame {item}", from_tty, to_string=True) except: break - return_address = common_regexes.return_address.search(result) + return_address = regexes.return_address.search(result) if return_address: - return_address_with_info = ScriptUtils.examine_expression(return_address.group(1)).all + return_address_with_info = gdbutils.examine_expression(return_address.group(1)).all else: return_address_with_info = "<>" return_address_list.append(return_address_with_info) @@ -238,7 +238,7 @@ def __init__(self): def invoke(self, arg, from_tty): frame_number = receive_from_pince() result = gdb.execute("bt", from_tty, to_string=True) - max_frame = common_regexes.max_frame_count.findall(result)[-1] + max_frame = regexes.max_frame_count.findall(result)[-1] if 0 <= int(frame_number) <= int(max_frame): frame_info = gdb.execute("info frame " + frame_number, from_tty, to_string=True) else: @@ -253,13 +253,13 @@ def __init__(self): def invoke(self, arg, from_tty): breakpoints = arg - current_pc_int = int(SysUtils.extract_address(str(gdb.parse_and_eval("$pc"))), 16) + current_pc_int = int(utils.extract_address(str(gdb.parse_and_eval("$pc"))), 16) try: disas_output = gdb.execute("disas $pc-30,$pc", to_string=True) # Just before the line "End of assembler dump" last_instruction = disas_output.splitlines()[-2] - previous_pc_address = SysUtils.extract_address(last_instruction) + previous_pc_address = utils.extract_address(last_instruction) except: previous_pc_address = hex(current_pc_int) global track_watchpoint_dict @@ -269,14 +269,14 @@ def invoke(self, arg, from_tty): if breakpoints not in track_watchpoint_dict: track_watchpoint_dict[breakpoints] = OrderedDict() count = 1 - register_info = ScriptUtils.get_general_registers() - register_info.update(ScriptUtils.get_flag_registers()) - register_info.update(ScriptUtils.get_segment_registers()) - float_info = ScriptUtils.get_float_registers() + register_info = gdbutils.get_general_registers() + register_info.update(gdbutils.get_flag_registers()) + register_info.update(gdbutils.get_segment_registers()) + float_info = gdbutils.get_float_registers() disas_info = gdb.execute("disas " + previous_pc_address + ",+40", to_string=True).replace("=>", " ") track_watchpoint_dict[breakpoints][current_pc_int] = [count, previous_pc_address, register_info, float_info, disas_info] - track_watchpoint_file = SysUtils.get_track_watchpoint_file(pid, breakpoints) + track_watchpoint_file = utils.get_track_watchpoint_file(pid, breakpoints) pickle.dump(track_watchpoint_dict[breakpoints], open(track_watchpoint_file, "wb")) @@ -297,7 +297,7 @@ def invoke(self, arg, from_tty): if not register_expression in track_breakpoint_dict[breakpoint_number]: track_breakpoint_dict[breakpoint_number][register_expression] = OrderedDict() try: - address = ScriptUtils.examine_expression(register_expression).address + address = gdbutils.examine_expression(register_expression).address except: address = None if address: @@ -305,7 +305,7 @@ def invoke(self, arg, from_tty): track_breakpoint_dict[breakpoint_number][register_expression][address] = 1 else: track_breakpoint_dict[breakpoint_number][register_expression][address] += 1 - track_breakpoint_file = SysUtils.get_track_breakpoint_file(pid, breakpoint_number) + track_breakpoint_file = utils.get_track_breakpoint_file(pid, breakpoint_number) pickle.dump(track_breakpoint_dict[breakpoint_number], open(track_breakpoint_file, "wb")) @@ -335,7 +335,7 @@ def invoke(self, arg, from_tty): (breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_general_registers, collect_flag_registers, collect_segment_registers, collect_float_registers) = eval(arg) gdb.execute("delete " + breakpoint) - trace_status_file = SysUtils.get_trace_instructions_status_file(pid, breakpoint) + trace_status_file = utils.get_trace_instructions_status_file(pid, breakpoint) # The reason we don't use a tree class is to make the tree json-compatible # tree format-->[node1, node2, node3, ...] @@ -350,27 +350,27 @@ def invoke(self, arg, from_tty): for x in range(max_trace_count): try: output = pickle.load(open(trace_status_file, "rb")) - if output[0] == type_defs.TRACE_STATUS.STATUS_CANCELED: + if output[0] == typedefs.TRACE_STATUS.STATUS_CANCELED: break except: pass line_info = gdb.execute("x/i $pc", to_string=True).splitlines()[0].split(maxsplit=1)[1] collect_dict = OrderedDict() if collect_general_registers: - collect_dict.update(ScriptUtils.get_general_registers()) + collect_dict.update(gdbutils.get_general_registers()) if collect_flag_registers: - collect_dict.update(ScriptUtils.get_flag_registers()) + collect_dict.update(gdbutils.get_flag_registers()) if collect_segment_registers: - collect_dict.update(ScriptUtils.get_segment_registers()) + collect_dict.update(gdbutils.get_segment_registers()) if collect_float_registers: - collect_dict.update(ScriptUtils.get_float_registers()) + collect_dict.update(gdbutils.get_float_registers()) current_index += 1 tree.append([(line_info, collect_dict), current_root_index, []]) tree[current_root_index][2].append(current_index) # Add a child - status_info = (type_defs.TRACE_STATUS.STATUS_TRACING, + status_info = (typedefs.TRACE_STATUS.STATUS_TRACING, line_info + "\n(" + str(x + 1) + "/" + str(max_trace_count) + ")") pickle.dump(status_info, open(trace_status_file, "wb")) - if common_regexes.trace_instructions_ret.search(line_info): + if regexes.trace_instructions_ret.search(line_info): if tree[current_root_index][1] is None: # If no parents exist current_index += 1 tree.append([("", None), None, [current_root_index]]) @@ -379,8 +379,8 @@ def invoke(self, arg, from_tty): root_index = current_root_index # set new root else: current_root_index = tree[current_root_index][1] # current_node=current_node.parent - elif step_mode == type_defs.STEP_MODE.SINGLE_STEP: - if common_regexes.trace_instructions_call.search(line_info): + elif step_mode == typedefs.STEP_MODE.SINGLE_STEP: + if regexes.trace_instructions_call.search(line_info): current_root_index = current_index if stop_condition: try: @@ -388,15 +388,15 @@ def invoke(self, arg, from_tty): break except: pass - if step_mode == type_defs.STEP_MODE.SINGLE_STEP: + if step_mode == typedefs.STEP_MODE.SINGLE_STEP: gdb.execute("stepi", to_string=True) - elif step_mode == type_defs.STEP_MODE.STEP_OVER: + elif step_mode == typedefs.STEP_MODE.STEP_OVER: gdb.execute("nexti", to_string=True) - status_info = (type_defs.TRACE_STATUS.STATUS_PROCESSING, "") + status_info = (typedefs.TRACE_STATUS.STATUS_PROCESSING, "") pickle.dump(status_info, open(trace_status_file, "wb")) - trace_instructions_file = SysUtils.get_trace_instructions_file(pid, breakpoint) + trace_instructions_file = utils.get_trace_instructions_file(pid, breakpoint) json.dump((tree, root_index), open(trace_instructions_file, "w")) - status_info = (type_defs.TRACE_STATUS.STATUS_FINISHED, "") + status_info = (typedefs.TRACE_STATUS.STATUS_FINISHED, "") pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: gdb.execute("c&") @@ -461,17 +461,17 @@ def is_memory_valid(self, int_address, discard_invalid_strings=False): return True def invoke(self, arg, from_tty): - if ScriptUtils.current_arch == type_defs.INFERIOR_ARCH.ARCH_64: + if gdbutils.current_arch == typedefs.INFERIOR_ARCH.ARCH_64: disas_option = distorm3.Decode64Bits else: disas_option = distorm3.Decode32Bits - referenced_strings_dict = shelve.open(SysUtils.get_referenced_strings_file(pid), writeback=True) - referenced_jumps_dict = shelve.open(SysUtils.get_referenced_jumps_file(pid), writeback=True) - referenced_calls_dict = shelve.open(SysUtils.get_referenced_calls_file(pid), writeback=True) + referenced_strings_dict = shelve.open(utils.get_referenced_strings_file(pid), writeback=True) + referenced_jumps_dict = shelve.open(utils.get_referenced_jumps_file(pid), writeback=True) + referenced_calls_dict = shelve.open(utils.get_referenced_calls_file(pid), writeback=True) region_list, discard_invalid_strings = receive_from_pince() - dissect_code_status_file = SysUtils.get_dissect_code_status_file(pid) + dissect_code_status_file = utils.get_dissect_code_status_file(pid) region_count = len(region_list) - self.memory = open(ScriptUtils.mem_file, "rb") + self.memory = open(gdbutils.mem_file, "rb") # Has the best record of 111 secs. Tested on Torchlight 2 with Intel i7-4702MQ CPU and 8GB RAM buffer = 0x10000 # Aligned to 2**16 @@ -509,12 +509,12 @@ def invoke(self, arg, from_tty): if isinstance(instruction, bytes): instruction = instruction.decode() if instruction.startswith("J") or instruction.startswith("LOOP"): - found = common_regexes.dissect_code_valid_address.search(instruction) + found = regexes.dissect_code_valid_address.search(instruction) if found: - referenced_address_str = common_regexes.hex_number.search(found.group(0)).group(0) + referenced_address_str = regexes.hex_number.search(found.group(0)).group(0) referenced_address_int = int(referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): - instruction_only = common_regexes.alphanumerics.search(instruction).group(0).casefold() + instruction_only = regexes.alphanumerics.search(instruction).group(0).casefold() try: referenced_jumps_dict[referenced_address_str][instruction_offset] = instruction_only except KeyError: @@ -522,9 +522,9 @@ def invoke(self, arg, from_tty): referenced_jumps_dict[referenced_address_str][instruction_offset] = instruction_only ref_jmp_count += 1 elif instruction.startswith("CALL"): - found = common_regexes.dissect_code_valid_address.search(instruction) + found = regexes.dissect_code_valid_address.search(instruction) if found: - referenced_address_str = common_regexes.hex_number.search(found.group(0)).group(0) + referenced_address_str = regexes.hex_number.search(found.group(0)).group(0) referenced_address_int = int(referenced_address_str, 16) if self.is_memory_valid(referenced_address_int): try: @@ -534,9 +534,9 @@ def invoke(self, arg, from_tty): referenced_calls_dict[referenced_address_str].add(instruction_offset) ref_call_count += 1 else: - found = common_regexes.dissect_code_valid_address.search(instruction) + found = regexes.dissect_code_valid_address.search(instruction) if found: - referenced_address_str = common_regexes.hex_number.search(found.group(0)).group(0) + referenced_address_str = regexes.hex_number.search(found.group(0)).group(0) referenced_address_int = int(referenced_address_str, 16) if self.is_memory_valid(referenced_address_int, discard_invalid_strings): try: @@ -564,10 +564,10 @@ def invoke(self, arg, from_tty): except Exception as e: print("An exception occurred while trying to compile the given regex\n", str(e)) return - str_dict = shelve.open(SysUtils.get_referenced_calls_file(pid), "r") + str_dict = shelve.open(utils.get_referenced_calls_file(pid), "r") returned_list = [] for index, item in enumerate(str_dict): - symbol = ScriptUtils.examine_expression(item).all + symbol = gdbutils.examine_expression(item).all if not symbol: continue if enable_regex: @@ -594,9 +594,9 @@ def invoke(self, arg, from_tty): contents_recv = receive_from_pince() # contents_recv format: [expression1, expression2, ...] - regions = SysUtils.get_regions(pid) + regions = utils.get_regions(pid) for expression in contents_recv: - result_tuple = ScriptUtils.examine_expression(expression, regions) + result_tuple = gdbutils.examine_expression(expression, regions) data_read_list.append(result_tuple) send_to_pince(data_read_list) @@ -619,7 +619,7 @@ def invoke(self, arg, from_tty): output = "" gdb.execute("set case-sensitive auto") for line in output.splitlines(): - non_debugging = common_regexes.info_functions_non_debugging.search(line) + non_debugging = regexes.info_functions_non_debugging.search(line) if non_debugging: function_list.append((non_debugging.group(1), non_debugging.group(2))) else: diff --git a/libpince/gdb_python_scripts/ScriptUtils.py b/libpince/gdb_python_scripts/gdbutils.py similarity index 80% rename from libpince/gdb_python_scripts/ScriptUtils.py rename to libpince/gdb_python_scripts/gdbutils.py index 6eb5c990..61243882 100644 --- a/libpince/gdb_python_scripts/ScriptUtils.py +++ b/libpince/gdb_python_scripts/gdbutils.py @@ -23,19 +23,19 @@ GDBINIT_AA_PATH = gdb.parse_and_eval("$GDBINIT_AA_PATH").string() sys.path.append(PINCE_PATH) # Adds the PINCE directory to PYTHONPATH to import libraries from PINCE -from libpince import SysUtils, type_defs, common_regexes +from libpince import utils, typedefs, regexes inferior = gdb.selected_inferior() pid = inferior.pid -inferior_name = SysUtils.get_process_name(pid) +inferior_name = utils.get_process_name(pid) mem_file = "/proc/" + str(pid) + "/mem" void_ptr = gdb.lookup_type("void").pointer() if str(gdb.parse_and_eval("$rax")) == "void": - current_arch = type_defs.INFERIOR_ARCH.ARCH_32 + current_arch = typedefs.INFERIOR_ARCH.ARCH_32 else: - current_arch = type_defs.INFERIOR_ARCH.ARCH_64 + current_arch = typedefs.INFERIOR_ARCH.ARCH_64 # Use this function instead of the .gdbinit file @@ -66,10 +66,10 @@ def wrapper(*args, **kwargs): def get_general_registers(): contents_send = OrderedDict() - if current_arch == type_defs.INFERIOR_ARCH.ARCH_64: - general_register_list = type_defs.REGISTERS.GENERAL_64 + if current_arch == typedefs.INFERIOR_ARCH.ARCH_64: + general_register_list = typedefs.REGISTERS.GENERAL_64 else: - general_register_list = type_defs.REGISTERS.GENERAL_32 + general_register_list = typedefs.REGISTERS.GENERAL_32 for item in general_register_list: contents_send[item] = examine_expression("$" + item).address return contents_send @@ -98,17 +98,17 @@ def get_flag_registers(): def get_segment_registers(): contents_send = OrderedDict() - for item in type_defs.REGISTERS.SEGMENT: + for item in typedefs.REGISTERS.SEGMENT: contents_send[item] = examine_expression("$" + item).address return contents_send def get_float_registers(): contents_send = OrderedDict() - for register in type_defs.REGISTERS.FLOAT.ST: + for register in typedefs.REGISTERS.FLOAT.ST: value = gdb.parse_and_eval("$" + register) contents_send[register] = str(value) - for register in type_defs.REGISTERS.FLOAT.XMM: + for register in typedefs.REGISTERS.FLOAT.XMM: value = gdb.parse_and_eval("$" + register + ".v4_float") contents_send[register] = str(value) return contents_send @@ -119,20 +119,20 @@ def examine_expression(expression, regions=None): value = gdb.parse_and_eval(expression).cast(void_ptr) except Exception as e: if regions: # this check comes first for optimization - offset = common_regexes.offset_expression.search(expression) + offset = regexes.offset_expression.search(expression) if offset: offset = offset.group(0) expression = expression.split(offset[0])[0] else: offset = "+0" - index = common_regexes.index.search(expression) + index = regexes.index.search(expression) if index: expression = expression[:index.start()] index = int(index.group(1)) else: index = 0 count = 0 - if expression == inferior_name or common_regexes.file_with_extension.search(expression): + if expression == inferior_name or regexes.file_with_extension.search(expression): for address, _, _, _, _, _, path in regions: file_name = os.path.split(path)[1] if expression in file_name: @@ -142,11 +142,11 @@ def examine_expression(expression, regions=None): address = hex(eval(address+offset)) except Exception as e: print(e) - return type_defs.tuple_examine_expression(None, None, None) - return type_defs.tuple_examine_expression(address+file_name, address, file_name) + return typedefs.tuple_examine_expression(None, None, None) + return typedefs.tuple_examine_expression(address+file_name, address, file_name) else: count += 1 print(e) - return type_defs.tuple_examine_expression(None, None, None) - result = common_regexes.address_with_symbol.search(str(value)) - return type_defs.tuple_examine_expression(*result.groups()) + return typedefs.tuple_examine_expression(None, None, None) + result = regexes.address_with_symbol.search(str(value)) + return typedefs.tuple_examine_expression(*result.groups()) diff --git a/libpince/Injection/.gitignore b/libpince/injection/.gitignore similarity index 100% rename from libpince/Injection/.gitignore rename to libpince/injection/.gitignore diff --git a/libpince/Injection/Notes.txt b/libpince/injection/Notes.txt similarity index 100% rename from libpince/Injection/Notes.txt rename to libpince/injection/Notes.txt diff --git a/libpince/Injection/example.c b/libpince/injection/example.c similarity index 100% rename from libpince/Injection/example.c rename to libpince/injection/example.c diff --git a/libpince/common_regexes.py b/libpince/regexes.py similarity index 89% rename from libpince/common_regexes.py rename to libpince/regexes.py index 866e696e..32751ebc 100644 --- a/libpince/common_regexes.py +++ b/libpince/regexes.py @@ -19,7 +19,7 @@ # The comments near regular expressions shows the expected gdb output, hope it helps to the future developers -# --------------------------------------------GDB_Engine---------------------------------------------------------------- +# --------------------------------------------debugcore---------------------------------------------------------------- gdb_state_observe = compile(r"^\*(stopped.+)|^\*(running)", MULTILINE) gdb_error = compile(r"\^error") @@ -35,7 +35,7 @@ breakpoint_number = compile(r"(?:number|bkptno)=\"(\d+)\"") convenience_variable = compile(r'"(\$\d+)\s+=\s+(.*)"') # "$26 = 3" entry_point = compile(r"Entry\s+point:\s+" + hex_number_grouped.pattern) -# The command will always start with the word "source", check GDB_Engine.send_command function for the cause +# The command will always start with the word "source", check debugcore.send_command function for the cause gdb_command_source = lambda command_file: compile(r"&\".*source\s" + command_file + r"\\n\"") # &"command\n" # 0x00007fd81d4c7400 <__printf+0>:\t48 81 ec d8 00 00 00\tsub rsp,0xd8\n disassemble_output = compile(r""" @@ -46,7 +46,7 @@ info_functions_non_debugging = compile(hex_number_grouped.pattern + r"\s+(.*)") max_completions_reached = compile(r"\*\*\*\s+List\s+may\s+be\s+truncated,\s+max-completions\s+reached\.\s+\*\*\*") -# --------------------------------------------SysUtils------------------------------------------------------------------ +# --------------------------------------------utils------------------------------------------------------------------ instruction_follow = compile(r"(j|call|loop).*\s+" + hex_number_grouped.pattern) docstring_variable = compile(r"(\w+)\s*=") @@ -70,7 +70,7 @@ reference_mark = compile(r"\{\d*\}") -# --------------------------------------------GDBCommandExtensions------------------------------------------------------ +# --------------------------------------------gdbextensions------------------------------------------------------ max_frame_count = compile(r"#(\d+)\s+.*") frame_address = compile(r"frame\s+at\s+" + hex_number_grouped.pattern) # frame at 0x7ffe1e989950 diff --git a/libpince/type_defs.py b/libpince/typedefs.py similarity index 97% rename from libpince/type_defs.py rename to libpince/typedefs.py index 19fd087e..ff46e5dc 100644 --- a/libpince/type_defs.py +++ b/libpince/typedefs.py @@ -29,13 +29,13 @@ class PATHS: class IPC_PATHS: - PINCE_IPC_PATH = "/dev/shm/PINCE-connection/" # Use SysUtils.get_ipc_path() - IPC_FROM_PINCE_PATH = "/from_PINCE_file" # Use SysUtils.get_ipc_from_pince_file() - IPC_TO_PINCE_PATH = "/to_PINCE_file" # Use SysUtils.get_ipc_to_pince_file() + PINCE_IPC_PATH = "/dev/shm/PINCE-connection/" # Use utils.get_ipc_path() + IPC_FROM_PINCE_PATH = "/from_PINCE_file" # Use utils.get_ipc_from_pince_file() + IPC_TO_PINCE_PATH = "/to_PINCE_file" # Use utils.get_ipc_to_pince_file() class USER_PATHS: - # Use SysUtils.get_user_path() to make use of these + # Use utils.get_user_path() to make use of these CONFIG_PATH = ".config/" ROOT_PATH = CONFIG_PATH + "PINCE/PINCE_USER_FILES/" @@ -335,7 +335,7 @@ class ENDIANNESS: } # first value is the length and the second one is the type -# Check ScriptUtils for an exemplary usage +# Check gdbutils for an exemplary usage index_to_valuetype_dict = { VALUE_INDEX.INDEX_INT8: [1, "B"], VALUE_INDEX.INDEX_INT16: [2, "H"], @@ -350,7 +350,7 @@ class ENDIANNESS: VALUE_INDEX.INDEX_AOB: [None, None] } -# Check ScriptUtils for an exemplary usage +# Check gdbutils for an exemplary usage index_to_struct_pack_dict = { VALUE_INDEX.INDEX_INT8: "B", VALUE_INDEX.INDEX_INT16: "H", diff --git a/libpince/SysUtils.py b/libpince/utils.py similarity index 91% rename from libpince/SysUtils.py rename to libpince/utils.py index 9dd017ff..03ec9de4 100644 --- a/libpince/SysUtils.py +++ b/libpince/utils.py @@ -17,7 +17,7 @@ """ import os, shutil, sys, binascii, pickle, json, traceback, re, pwd, pathlib, distorm3 -from . import type_defs, common_regexes +from . import typedefs, regexes from keystone import Ks, KsError, KS_ARCH_X86, KS_MODE_32, KS_MODE_64 from collections import OrderedDict from importlib.machinery import SourceFileLoader @@ -36,7 +36,7 @@ def get_process_list(): """ process_list = [] for line in os.popen("ps -eo pid:11,user,comm").read().splitlines(): - info = common_regexes.ps.match(line) + info = regexes.ps.match(line) if info: process_list.append(info.groups()) return process_list @@ -86,7 +86,7 @@ def get_regions(pid): with open("/proc/"+str(pid)+"/maps") as f: regions = [] for line in f.read().splitlines(): - regions.append(common_regexes.maps.match(line).groups()) + regions.append(regexes.maps.match(line).groups()) return regions @@ -137,7 +137,7 @@ def get_region_info(pid, address): end = int(end, 16) file_name = os.path.split(path)[1] if start <= address < end: - return type_defs.tuple_region_info(start, end, perms, file_name) + return typedefs.tuple_region_info(start, end, perms, file_name) #:tag:Processes @@ -242,8 +242,8 @@ def get_libpince_directory(): str: A string pointing to the libpince directory Note: - In fact this function returns the directory where SysUtils in and considering the fact that SysUtils resides in - libpince, it works. So, please don't move out SysUtils outside of libpince folder! + In fact this function returns the directory where utils in and considering the fact that utils resides in + libpince, it works. So, please don't move out utils outside of libpince folder! """ return os.path.dirname(os.path.realpath(__file__)) @@ -290,9 +290,9 @@ def create_ipc_path(pid): delete_ipc_path(pid) is_path_valid(get_ipc_path(pid), "create") - # Opening the command file with 'w' each time GDB_Engine.send_command() gets invoked slows down the process + # Opening the command file with 'w' each time debugcore.send_command() gets invoked slows down the process # Instead, here we create the command file for only once when IPC path gets initialized - # Then, open the command file with 'r' in GDB_Engine.send_command() to get a better performance + # Then, open the command file with 'r' in debugcore.send_command() to get a better performance command_file = get_gdb_command_file(pid) open(command_file, "w").close() @@ -307,7 +307,7 @@ def get_ipc_path(pid): Returns: str: Path of IPC directory """ - return type_defs.IPC_PATHS.PINCE_IPC_PATH + str(pid) + return typedefs.IPC_PATHS.PINCE_IPC_PATH + str(pid) #:tag:GDBCommunication @@ -532,7 +532,7 @@ def get_ipc_from_pince_file(pid): Returns: str: Path of IPC file """ - return get_ipc_path(pid) + type_defs.IPC_PATHS.IPC_FROM_PINCE_PATH + return get_ipc_path(pid) + typedefs.IPC_PATHS.IPC_FROM_PINCE_PATH #:tag:GDBCommunication @@ -545,7 +545,7 @@ def get_ipc_to_pince_file(pid): Returns: str: Path of IPC file """ - return get_ipc_path(pid) + type_defs.IPC_PATHS.IPC_TO_PINCE_PATH + return get_ipc_path(pid) + typedefs.IPC_PATHS.IPC_TO_PINCE_PATH #:tag:ValueType @@ -554,7 +554,7 @@ def parse_string(string, value_index): Args: string (str): String that'll be parsed - value_index (int): Determines the type of data. Can be a member of type_defs.VALUE_INDEX + value_index (int): Determines the type of data. Can be a member of typedefs.VALUE_INDEX Returns: str: If the value_index is INDEX_STRING @@ -564,7 +564,7 @@ def parse_string(string, value_index): None: If the string is not parsable by using the parameter value_index Examples: - string="42 DE AD BE EF 24",value_index=type_defs.VALUE_INDEX.INDEX_AOB--▼ + string="42 DE AD BE EF 24",value_index=typedefs.VALUE_INDEX.INDEX_AOB--▼ returned_list=[66, 222, 173, 190, 239, 36] """ string = str(string) @@ -576,12 +576,12 @@ def parse_string(string, value_index): except: print(str(value_index) + " can't be converted to int") return - if type_defs.VALUE_INDEX.is_string(value_index): + if typedefs.VALUE_INDEX.is_string(value_index): return string string = string.strip() - if value_index is type_defs.VALUE_INDEX.INDEX_AOB: + if value_index is typedefs.VALUE_INDEX.INDEX_AOB: try: - string_list = common_regexes.whitespaces.split(string) + string_list = regexes.whitespaces.split(string) for item in string_list: if len(item) > 2: print(string + " can't be parsed as array of bytes") @@ -591,7 +591,7 @@ def parse_string(string, value_index): except: print(string + " can't be parsed as array of bytes") return - elif value_index is type_defs.VALUE_INDEX.INDEX_FLOAT32 or value_index is type_defs.VALUE_INDEX.INDEX_FLOAT64: + elif value_index is typedefs.VALUE_INDEX.INDEX_FLOAT32 or value_index is typedefs.VALUE_INDEX.INDEX_FLOAT64: try: string = float(string) except: @@ -610,13 +610,13 @@ def parse_string(string, value_index): except: print(string + " can't be parsed as integer or hexadecimal") return - if value_index is type_defs.VALUE_INDEX.INDEX_INT8: + if value_index is typedefs.VALUE_INDEX.INDEX_INT8: string = string % 0x100 # 256 - elif value_index is type_defs.VALUE_INDEX.INDEX_INT16: + elif value_index is typedefs.VALUE_INDEX.INDEX_INT16: string = string % 0x10000 # 65536 - elif value_index is type_defs.VALUE_INDEX.INDEX_INT32: + elif value_index is typedefs.VALUE_INDEX.INDEX_INT32: string = string % 0x100000000 # 4294967296 - elif value_index is type_defs.VALUE_INDEX.INDEX_INT64: + elif value_index is typedefs.VALUE_INDEX.INDEX_INT64: string = string % 0x10000000000000000 # 18446744073709551616 return string @@ -633,7 +633,7 @@ def instruction_follow_address(string): str: Hex address None: If no hex address is found or no location changing instructions found """ - result = common_regexes.instruction_follow.search(string) + result = regexes.instruction_follow.search(string) if result: return result.group(2) @@ -649,7 +649,7 @@ def extract_address(string): str: Hex address None: If no hex address is found """ - result = common_regexes.hex_number.search(string) + result = regexes.hex_number.search(string) if result: return result.group(0) @@ -661,16 +661,16 @@ def modulo_address(int_address, arch_type): Args: int_address (int): Self-explanatory - arch_type (int): Architecture type (x86, x64). Can be a member of type_defs.INFERIOR_ARCH + arch_type (int): Architecture type (x86, x64). Can be a member of typedefs.INFERIOR_ARCH Returns: int: Modulo of the given integer based on the given architecture type """ - if arch_type == type_defs.INFERIOR_ARCH.ARCH_32: + if arch_type == typedefs.INFERIOR_ARCH.ARCH_32: return int_address % 0x100000000 - elif arch_type == type_defs.INFERIOR_ARCH.ARCH_64: + elif arch_type == typedefs.INFERIOR_ARCH.ARCH_64: return int_address % 0x10000000000000000 - raise Exception("arch_type must be a member of type_defs.INFERIOR_ARCH") + raise Exception("arch_type must be a member of typedefs.INFERIOR_ARCH") #:tag:Utilities @@ -680,15 +680,15 @@ def get_opcodes(address, aob, inferior_arch): Args: address (int): The address where the opcode starts from aob (str): Bytes of the opcode as an array of bytes - inferior_arch (int): Architecture type (x86, x64). Can be a member of type_defs.INFERIOR_ARCH + inferior_arch (int): Architecture type (x86, x64). Can be a member of typedefs.INFERIOR_ARCH Returns: str: Opcodes, multiple entries are separated with ; None: If there was an error """ - if inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64: + if inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64: disas_option = distorm3.Decode64Bits - elif inferior_arch == type_defs.INFERIOR_ARCH.ARCH_32: + elif inferior_arch == typedefs.INFERIOR_ARCH.ARCH_32: disas_option = distorm3.Decode32Bits try: bytecode = bytes.fromhex(aob.replace(" ", "")) @@ -705,14 +705,14 @@ def assemble(instructions, address, inferior_arch): Args: instructions (str): A string of instructions, multiple entries separated by ; address (int): Address of the instruction - inferior_arch (int): Can be a member of type_defs.INFERIOR_ARCH + inferior_arch (int): Can be a member of typedefs.INFERIOR_ARCH Returns: tuple: A tuple of (list, int) --> Assembled bytes (list of int) and instruction count (int) None: If there was an error """ try: - if inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64: + if inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64: return ks_64.asm(instructions, address) else: return ks_32.asm(instructions, address) @@ -725,7 +725,7 @@ def aob_to_str(list_of_bytes, encoding="ascii"): """Converts given array of hex strings to str Args: - list_of_bytes (list): Must be returned from GDB_Engine.hex_dump() + list_of_bytes (list): Must be returned from debugcore.hex_dump() encoding (str): See here-->https://docs.python.org/3/library/codecs.html#standard-encodings Returns: @@ -785,11 +785,11 @@ def str_to_aob(string, encoding="ascii"): #:tag:GDBExpressions def split_symbol(symbol_string): - """Splits symbol part of type_defs.tuple_function_info into smaller fractions + """Splits symbol part of typedefs.tuple_function_info into smaller fractions Fraction count depends on the the symbol_string. See Examples section for demonstration Args: - symbol_string (str): symbol part of type_defs.tuple_function_info + symbol_string (str): symbol part of typedefs.tuple_function_info Returns: list: A list containing parts of the splitted symbol @@ -811,9 +811,9 @@ def split_symbol(symbol_string): # searching for balanced parentheses works because apparently no demangled symbol can finish with <.*> # XXX: run this code to test while attached to a process and open a detailed issue if you get a result """ - from libpince import GDB_Engine + from libpince import debugcore import re - result=GDB_Engine.search_functions("") + result=debugcore.search_functions("") for address, symbol in result: if re.search("<.*>[^()]+$", symbol): print(symbol) @@ -942,7 +942,7 @@ def get_variable_comments(modules, search_for=""): docstring_list.append(current_line) else: while True: - stripped_current_line = common_regexes.docstring_variable.search(current_line) + stripped_current_line = regexes.docstring_variable.search(current_line) if stripped_current_line: variable = stripped_current_line.group(1) break @@ -965,7 +965,7 @@ def get_tags(modules, tag_to_string, search_for=""): Args: modules (list): A list of modules tag_to_string (dict): A dictionary that holds tag descriptions in this format-->{tag:tag_description} - Check type_defs.tag_to_string for an example + Check typedefs.tag_to_string for an example search_for (str): String that will be searched in tags Returns: @@ -999,7 +999,7 @@ def func_name(...) while True: row += 1 current_line = lines[row].strip() - stripped_current_line = common_regexes.docstring_function_or_variable.search(current_line) + stripped_current_line = regexes.docstring_function_or_variable.search(current_line) if stripped_current_line: for item in stripped_current_line.groups(): if item: @@ -1038,9 +1038,9 @@ def get_module_name(module): #:tag:Utilities def init_user_files(): """Initializes user files""" - for directory in type_defs.USER_PATHS.get_init_directories(): + for directory in typedefs.USER_PATHS.get_init_directories(): is_path_valid(get_user_path(directory), "create") - for file in type_defs.USER_PATHS.get_init_files(): + for file in typedefs.USER_PATHS.get_init_files(): file = get_user_path(file) try: open(file).close() @@ -1076,7 +1076,7 @@ def get_user_path(user_path): """Returns the specified user path for the current user Args: - user_path (str): Can be a member of type_defs.USER_PATHS + user_path (str): Can be a member of typedefs.USER_PATHS Returns: str: Specified user path of the current user @@ -1118,7 +1118,7 @@ def execute_script(file_path): #:tag:Utilities def parse_response(response, line_num=0): """Parses the given GDB/MI output. Wraps gdbmiparser.parse_response - GDB_Engine.send_command returns an additional "^done" output because of the "source" command + debugcore.send_command returns an additional "^done" output because of the "source" command This function is used to get rid of that output before parsing Args: diff --git a/run_tests.py b/run_tests.py index ab3baaf0..4efea2e7 100644 --- a/run_tests.py +++ b/run_tests.py @@ -17,7 +17,7 @@ along with this program. If not, see . """ import unittest, argparse -from libpince import GDB_Engine, SysUtils +from libpince import debugcore, utils desc = 'Runs all unit tests by creating or attaching to a process' ex = 'Example of Usage:' \ @@ -34,7 +34,7 @@ args = parser.parse_args() if args.a: - process_list = SysUtils.search_processes(args.a) + process_list = utils.search_processes(args.a) if not process_list: parser.error("There's no process with the name " + args.a) if len(process_list) > 1: @@ -43,15 +43,15 @@ print("There are more than one process with the name " + args.a) exit() pid = process_list[0][0] - if not GDB_Engine.can_attach(pid): + if not debugcore.can_attach(pid): parser.error("Failed to attach to the process with pid " + pid) - GDB_Engine.attach(pid) + debugcore.attach(pid) elif args.c: - if not GDB_Engine.create_process(args.c, args.o, args.l): + if not debugcore.create_process(args.c, args.o, args.l): parser.error("Couldn't create the process with current args") else: parser.error("Provide at least one of these arguments: -a or -c") -unittest.main(module="tests.GDB_Engine_tests", exit=False, argv=[""]) -unittest.main(module="tests.SysUtils_tests", exit=False, argv=[""]) +unittest.main(module="tests.debugcore_tests", exit=False, argv=[""]) +unittest.main(module="tests.utils_tests", exit=False, argv=[""]) unittest.main(module="tests.guiutils_tests", exit=False, argv=[""]) -GDB_Engine.detach() +debugcore.detach() diff --git a/tests/common_defs.py b/tests/common_defs.py deleted file mode 100644 index 13b99f6c..00000000 --- a/tests/common_defs.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -Copyright (C) 2016-2017 Korcan Karaokçu - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" -# This source file will be used for things that are shared between test modules diff --git a/tests/GDB_Engine_tests.py b/tests/debugcore_tests.py similarity index 72% rename from tests/GDB_Engine_tests.py rename to tests/debugcore_tests.py index d2447abe..4f82a04a 100644 --- a/tests/GDB_Engine_tests.py +++ b/tests/debugcore_tests.py @@ -15,14 +15,14 @@ along with this program. If not, see . """ import unittest -from libpince import GDB_Engine, type_defs, common_regexes +from libpince import debugcore, typedefs, regexes -class GDB_Engine_tests(unittest.TestCase): +class debugcore_tests(unittest.TestCase): def test_read_registers(self): - register_dict = GDB_Engine.read_registers() - if GDB_Engine.inferior_arch == type_defs.INFERIOR_ARCH.ARCH_64: + register_dict = debugcore.read_registers() + if debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64: test_register = "rax" else: test_register = "eax" - self.assertRegex(register_dict[test_register], common_regexes.hex_number.pattern) + self.assertRegex(register_dict[test_register], regexes.hex_number.pattern) diff --git a/tests/SysUtils_tests.py b/tests/utils_tests.py similarity index 79% rename from tests/SysUtils_tests.py rename to tests/utils_tests.py index 75350cf7..fae912c8 100644 --- a/tests/SysUtils_tests.py +++ b/tests/utils_tests.py @@ -15,9 +15,9 @@ along with this program. If not, see . """ import unittest -from libpince import SysUtils +from libpince import utils -class SysUtils_tests(unittest.TestCase): +class utils_tests(unittest.TestCase): def test_split_symbol(self): - self.assertListEqual(SysUtils.split_symbol("func(param)@plt"), ["func", "func(param)", "func(param)@plt"]) + self.assertListEqual(utils.split_symbol("func(param)@plt"), ["func", "func(param)", "func(param)@plt"]) From 2fc7d5b298a6684702202f2ddb88d0ee44470f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 25 Dec 2023 20:53:20 +0300 Subject: [PATCH 292/487] Update translations --- i18n/ts/it_IT.ts | 47 +++++++++++++++++++++++------------- i18n/ts/zh_CN.ts | 63 +++++++++++++++++++++++++++++------------------- 2 files changed, 68 insertions(+), 42 deletions(-) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 02f44a47..3a6ccb07 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -10,28 +10,30 @@ - Base Address: + Type: - Add Offset + Endianness: + - Remove Offset + Hex - + - Pointer + Signed + - Type: + Length: @@ -41,14 +43,23 @@ - - Length - Lunghezza + Base Address: + - Endianness: + Add Offset + + + + + Remove Offset + + + + + Description: @@ -59,8 +70,9 @@ Indirizzo: + - Description: + Pointer @@ -130,15 +142,21 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin + Type - Select the new type + Endianness + + + Length + Lunghezza + @@ -160,11 +178,6 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Hex Edit - - - Length: - - Refresh diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 248dc5eb..df9175ea 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -10,29 +10,31 @@ - Base Address: - 基址: + Type: + 类型: - Add Offset - 添加偏移量 + Endianness: + 字节序: + - Remove Offset - 移除偏移量 + Hex + 十六进制 - + - Pointer - 指针 + Signed + + - Type: - 类型: + Length: + 长度: @@ -41,15 +43,24 @@ 以零终止 - - Length - 长度 + Base Address: + 基址: - Endianness: - 字节序: + Add Offset + 添加偏移量 + + + + Remove Offset + 移除偏移量 + + + + Description: + 备注: @@ -59,9 +70,10 @@ 地址: + - Description: - 备注: + Pointer + 指针 @@ -131,14 +143,20 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin 多个条目用分号(;)分隔 + Type 类型 - Select the new type - 选择一个新类型 + Endianness + + + + + Length + 长度 @@ -161,11 +179,6 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Hex Edit 十六进制编辑 - - - Length: - 长度: - Refresh From b1df3cde8e5c9942b1e6643b07038d130547a7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 26 Dec 2023 13:33:03 +0300 Subject: [PATCH 293/487] Fix #231 --- PINCE.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 325709e2..64c12704 100755 --- a/PINCE.py +++ b/PINCE.py @@ -110,7 +110,13 @@ def get_locale(): utils.get_user_path(typedefs.USER_PATHS.CONFIG_PATH)) settings = QSettings() translator = QTranslator() - locale = settings.value("General/locale", type=str) + try: + locale = settings.value("General/locale", type=str) + except SystemError: + # We're reading the settings for the first time here + # If there's an error due to python objects, clear settings + settings.clear() + locale = None if not locale: locale = get_locale() translator.load(f'i18n/qm/{locale}.qm') @@ -440,8 +446,7 @@ def __init__(self): self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) self.settings = QSettings() - settings_path = self.settings.fileName() - if not utils.is_path_valid(settings_path): + if not utils.is_path_valid(self.settings.fileName()): self.set_default_settings() try: settings_version = self.settings.value("Misc/version", type=str) @@ -450,13 +455,13 @@ def __init__(self): settings_version = None if settings_version != current_settings_version: print("Settings version mismatch, rolling back to the default configuration") - os.remove(settings_path) + self.settings.clear() self.set_default_settings() try: self.apply_settings() except Exception as e: print("An exception occurred while loading settings, rolling back to the default configuration\n", e) - os.remove(settings_path) + self.settings.clear() self.set_default_settings() try: debugcore.init_gdb(gdb_path) From 0a874b37f7c00b152ac8734093fc256af47708d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 26 Dec 2023 21:24:02 +0300 Subject: [PATCH 294/487] Use setSizeConstraint with fixed size instead of setMaximumSize --- GUI/AddAddressManuallyDialog.py | 1 + GUI/AddAddressManuallyDialog.ui | 3 +++ GUI/EditTypeDialog.py | 2 ++ GUI/EditTypeDialog.ui | 11 +++++++++++ PINCE.py | 2 -- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 2388232f..25520f41 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -14,6 +14,7 @@ def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(273, 431) self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetFixedSize) self.gridLayout.setObjectName("gridLayout") self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index cf9ba47b..8056dc7a 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -14,6 +14,9 @@ Add Address Manually + + QLayout::SetFixedSize + diff --git a/GUI/EditTypeDialog.py b/GUI/EditTypeDialog.py index 10bc1a1b..f3af1042 100644 --- a/GUI/EditTypeDialog.py +++ b/GUI/EditTypeDialog.py @@ -12,7 +12,9 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") + Dialog.resize(343, 163) self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetFixedSize) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") diff --git a/GUI/EditTypeDialog.ui b/GUI/EditTypeDialog.ui index 34a88392..3c912f7c 100644 --- a/GUI/EditTypeDialog.ui +++ b/GUI/EditTypeDialog.ui @@ -2,10 +2,21 @@ Dialog + + + 0 + 0 + 343 + 163 + + Type + + QLayout::SetFixedSize + diff --git a/PINCE.py b/PINCE.py index 64c12704..25a9dde8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1745,7 +1745,6 @@ class ManualAddressDialogForm(QDialog, ManualAddressDialog): def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", value_type=None): super().__init__(parent=parent) self.setupUi(self) - self.setMaximumSize(100, 100) vt = typedefs.ValueType() if not value_type else value_type self.lineEdit_Length.setValidator(QHexValidator(99, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) @@ -1981,7 +1980,6 @@ def __init__(self, parent=None, value_type=None): super().__init__(parent=parent) self.setupUi(self) vt = typedefs.ValueType() if not value_type else value_type - self.setMaximumSize(100, 100) self.lineEdit_Length.setValidator(QHexValidator(99, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) From f1db6012b66c04d059659176adf87a1d86977852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 27 Dec 2023 02:57:23 +0300 Subject: [PATCH 295/487] Revert to adjustSize from setSizeConstraint --- GUI/AddAddressManuallyDialog.py | 8 -------- GUI/AddAddressManuallyDialog.ui | 18 +----------------- GUI/EditTypeDialog.py | 1 - GUI/EditTypeDialog.ui | 3 --- PINCE.py | 9 ++++++--- 5 files changed, 7 insertions(+), 32 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 25520f41..ac5dfcd5 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -14,7 +14,6 @@ def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(273, 431) self.gridLayout = QtWidgets.QGridLayout(Dialog) - self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetFixedSize) self.gridLayout.setObjectName("gridLayout") self.verticalLayout_3 = QtWidgets.QVBoxLayout() self.verticalLayout_3.setObjectName("verticalLayout_3") @@ -24,12 +23,6 @@ def setupUi(self, Dialog): self.label_5.setObjectName("label_5") self.horizontalLayout_3.addWidget(self.label_5) self.comboBox_ValueType = QtWidgets.QComboBox(parent=Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.comboBox_ValueType.sizePolicy().hasHeightForWidth()) - self.comboBox_ValueType.setSizePolicy(sizePolicy) - self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout_3.addWidget(self.comboBox_ValueType) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -182,7 +175,6 @@ def setupUi(self, Dialog): self.gridLayout.addWidget(self.checkBox_IsPointer, 3, 0, 1, 1) self.retranslateUi(Dialog) - self.comboBox_ValueType.setCurrentIndex(-1) self.buttonBox.accepted.connect(Dialog.accept) # type: ignore self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 8056dc7a..56a0afcc 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -14,9 +14,6 @@ Add Address Manually - - QLayout::SetFixedSize - @@ -29,20 +26,7 @@ - - - - 0 - 0 - - - - -1 - - - QComboBox::AdjustToContents - - + diff --git a/GUI/EditTypeDialog.py b/GUI/EditTypeDialog.py index f3af1042..5521ffad 100644 --- a/GUI/EditTypeDialog.py +++ b/GUI/EditTypeDialog.py @@ -14,7 +14,6 @@ def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(343, 163) self.gridLayout = QtWidgets.QGridLayout(Dialog) - self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetFixedSize) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") diff --git a/GUI/EditTypeDialog.ui b/GUI/EditTypeDialog.ui index 3c912f7c..8e024ceb 100644 --- a/GUI/EditTypeDialog.ui +++ b/GUI/EditTypeDialog.ui @@ -14,9 +14,6 @@ Type - - QLayout::SetFixedSize - diff --git a/PINCE.py b/PINCE.py index 25a9dde8..9189fb02 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1858,9 +1858,6 @@ def update_value(self): self.lineEdit_Address.setText(address_text) else: address = debugcore.examine_expression(self.lineEdit_Address.text()).address - if not address: - self.label_Value.setText("??") - return if self.checkBox_Hex.isChecked(): value_repr = typedefs.VALUE_REPR.HEX elif self.checkBox_Signed.isChecked(): @@ -1873,6 +1870,8 @@ def update_value(self): endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) value = debugcore.read_memory(address, address_type, length, zero_terminate, value_repr, endian) self.label_Value.setText("??" if value is None else str(value)) + app.processEvents() + self.adjustSize() def comboBox_ValueType_current_index_changed(self): if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): @@ -2011,6 +2010,8 @@ def __init__(self, parent=None, value_type=None): self.checkBox_Signed.setChecked(False) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) self.checkBox_Hex.stateChanged.connect(self.repr_changed) + app.processEvents() + self.adjustSize() def comboBox_ValueType_current_index_changed(self): if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): @@ -2021,6 +2022,8 @@ def comboBox_ValueType_current_index_changed(self): self.checkBox_ZeroTerminate.hide() else: self.widget_Length.hide() + app.processEvents() + self.adjustSize() def repr_changed(self): if self.checkBox_Hex.isChecked(): From 20d2b5487eeed35f1e9c7c607a397a5b74793e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 27 Dec 2023 13:24:39 +0300 Subject: [PATCH 296/487] Adjust ManualAddressDialog resizing --- GUI/AddAddressManuallyDialog.py | 22 +---------- GUI/AddAddressManuallyDialog.ui | 66 +++++++-------------------------- PINCE.py | 12 ++++-- 3 files changed, 24 insertions(+), 76 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index ac5dfcd5..93897d95 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -62,11 +62,6 @@ def setupUi(self, Dialog): self.label_Length.setObjectName("label_Length") self.horizontalLayout_Length.addWidget(self.label_Length) self.lineEdit_Length = QtWidgets.QLineEdit(parent=self.widget_Length) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_Length.sizePolicy().hasHeightForWidth()) - self.lineEdit_Length.setSizePolicy(sizePolicy) self.lineEdit_Length.setMaximumSize(QtCore.QSize(60, 16777215)) self.lineEdit_Length.setInputMask("") self.lineEdit_Length.setText("10") @@ -96,15 +91,8 @@ def setupUi(self, Dialog): self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.lineEdit_PtrStartAddress = QtWidgets.QLineEdit(parent=self.widget_Pointer) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_PtrStartAddress.sizePolicy().hasHeightForWidth()) - self.lineEdit_PtrStartAddress.setSizePolicy(sizePolicy) self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem4) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") @@ -114,6 +102,8 @@ def setupUi(self, Dialog): self.pushButton_RemoveOffset = QtWidgets.QPushButton(parent=self.widget_Pointer) self.pushButton_RemoveOffset.setObjectName("pushButton_RemoveOffset") self.horizontalLayout_5.addWidget(self.pushButton_RemoveOffset) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_5.addItem(spacerItem4) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_5) self.verticalLayout_4.addLayout(self.verticalLayout_Pointers) self.gridLayout.addWidget(self.widget_Pointer, 7, 0, 1, 1) @@ -148,12 +138,6 @@ def setupUi(self, Dialog): self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.lineEdit_Address = QtWidgets.QLineEdit(parent=Dialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_Address.sizePolicy().hasHeightForWidth()) - self.lineEdit_Address.setSizePolicy(sizePolicy) - self.lineEdit_Address.setMinimumSize(QtCore.QSize(100, 0)) self.lineEdit_Address.setText("") self.lineEdit_Address.setObjectName("lineEdit_Address") self.horizontalLayout.addWidget(self.lineEdit_Address) @@ -166,8 +150,6 @@ def setupUi(self, Dialog): self.label_Value.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_Value.setObjectName("label_Value") self.horizontalLayout.addWidget(self.label_Value) - spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem6) self.verticalLayout_2.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) self.checkBox_IsPointer = QtWidgets.QCheckBox(parent=Dialog) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 56a0afcc..babbffc6 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -139,12 +139,6 @@ - - - 0 - 0 - - 60 @@ -226,27 +220,7 @@ - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + @@ -266,6 +240,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -342,18 +329,6 @@ - - - 0 - 0 - - - - - 100 - 0 - - @@ -376,19 +351,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - diff --git a/PINCE.py b/PINCE.py index 9189fb02..47caef3f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -31,7 +31,7 @@ QKeyEvent, QRegularExpressionValidator, QShortcut, QColorConstants from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ - QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame + QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ QLocale @@ -1820,16 +1820,18 @@ def addOffsetLayout(self, should_update=True): offsetLayout.setContentsMargins(0, 3, 0, 3) offsetFrame.setLayout(offsetLayout) buttonLeft = QPushButton("<", offsetFrame) - buttonLeft.setFixedSize(70, 30) + buttonLeft.setFixedWidth(40) offsetLayout.addWidget(buttonLeft) offsetText = QLineEdit(offsetFrame) - offsetText.setFixedSize(70, 30) offsetText.setText(hex(0)) offsetText.textChanged.connect(self.update_value) offsetLayout.addWidget(offsetText) buttonRight = QPushButton(">", offsetFrame) - buttonRight.setFixedSize(70, 30) + buttonRight.setFixedWidth(40) offsetLayout.addWidget(buttonRight) + # TODO: Replace this spacer with address calculation per offset + spacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding) + offsetLayout.addItem(spacer) buttonLeft.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opSub)) buttonRight.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opAdd)) @@ -1870,8 +1872,10 @@ def update_value(self): endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) value = debugcore.read_memory(address, address_type, length, zero_terminate, value_repr, endian) self.label_Value.setText("??" if value is None else str(value)) + old_width = self.width() app.processEvents() self.adjustSize() + self.resize(old_width, self.minimumHeight()) def comboBox_ValueType_current_index_changed(self): if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): From bebcda88426231192cf581603cdeafd2ae8049cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 27 Dec 2023 13:41:09 +0300 Subject: [PATCH 297/487] Fix lineEdit_Length width for EditTypeDialog --- PINCE.py | 1 + 1 file changed, 1 insertion(+) diff --git a/PINCE.py b/PINCE.py index 47caef3f..b696fea5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1984,6 +1984,7 @@ def __init__(self, parent=None, value_type=None): self.setupUi(self) vt = typedefs.ValueType() if not value_type else value_type self.lineEdit_Length.setValidator(QHexValidator(99, self)) + self.lineEdit_Length.setFixedWidth(40) guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): From 9ed09e992546cb9f774df150dbe5b609110ec8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 27 Dec 2023 15:04:24 +0300 Subject: [PATCH 298/487] Remove is_path_valid function It's badly designed and decreases readability --- PINCE.py | 2 +- libpince/utils.py | 38 +++++++++++--------------------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/PINCE.py b/PINCE.py index b696fea5..b9fb16d6 100755 --- a/PINCE.py +++ b/PINCE.py @@ -446,7 +446,7 @@ def __init__(self): self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) self.settings = QSettings() - if not utils.is_path_valid(self.settings.fileName()): + if not os.path.exists(self.settings.fileName()): self.set_default_settings() try: settings_version = self.settings.value("Misc/version", type=str) diff --git a/libpince/utils.py b/libpince/utils.py index 03ec9de4..7af174ab 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -201,7 +201,7 @@ def is_process_valid(pid): Returns: bool: True if the process is still running, False if not """ - return is_path_valid("/proc/%d" % pid) + return os.path.exists("/proc/%d" % pid) #:tag:Utilities @@ -248,28 +248,6 @@ def get_libpince_directory(): return os.path.dirname(os.path.realpath(__file__)) -#:tag:Utilities -def is_path_valid(dest_path, issue_path=""): - """Check if the given path is valid - - Args: - dest_path (str): Path - issue_path (str): If this parameter is passed as "delete", given path will be deleted if it's valid. - If this parameter is passed as "create", given path path will be created if it's not valid. - - Returns: - bool: True if path is valid, False if not - """ - if os.path.exists(dest_path): - if issue_path == "delete": - shutil.rmtree(dest_path) - return True - else: - if issue_path == "create": - os.makedirs(dest_path) - return False - - #:tag:GDBCommunication def delete_ipc_path(pid): """Deletes the IPC directory of given pid @@ -277,7 +255,9 @@ def delete_ipc_path(pid): Args: pid (int,str): PID of the process """ - is_path_valid(get_ipc_path(pid), "delete") + path = get_ipc_path(pid) + if os.path.exists(path): + shutil.rmtree(path) #:tag:GDBCommunication @@ -287,8 +267,10 @@ def create_ipc_path(pid): Args: pid (int,str): PID of the process """ - delete_ipc_path(pid) - is_path_valid(get_ipc_path(pid), "create") + path = get_ipc_path(pid) + if os.path.exists(path): + shutil.rmtree(path) + os.makedirs(path) # Opening the command file with 'w' each time debugcore.send_command() gets invoked slows down the process # Instead, here we create the command file for only once when IPC path gets initialized @@ -1039,7 +1021,9 @@ def get_module_name(module): def init_user_files(): """Initializes user files""" for directory in typedefs.USER_PATHS.get_init_directories(): - is_path_valid(get_user_path(directory), "create") + path = get_user_path(directory) + if not os.path.exists(path): + os.makedirs(path) for file in typedefs.USER_PATHS.get_init_files(): file = get_user_path(file) try: From c23724b2656df27225f66702ab6ba9ef4def579b Mon Sep 17 00:00:00 2001 From: Jake <32206266+jakerosado@users.noreply.github.com> Date: Thu, 28 Dec 2023 08:58:26 -0500 Subject: [PATCH 299/487] Add theme option (#230) * Add theme option * Add system default theme option and failsafe * Match update 6703bad * Refactor themes * Refactor themes with suggested changes --------- Co-authored-by: Jake Rosado --- GUI/Settings/themes.py | 232 +++++++++++++++++++++++++++++++++++++++++ GUI/SettingsDialog.py | 12 +++ GUI/SettingsDialog.ui | 27 +++++ PINCE.py | 25 +++++ 4 files changed, 296 insertions(+) create mode 100644 GUI/Settings/themes.py diff --git a/GUI/Settings/themes.py b/GUI/Settings/themes.py new file mode 100644 index 00000000..920f2910 --- /dev/null +++ b/GUI/Settings/themes.py @@ -0,0 +1,232 @@ +from PyQt6.QtGui import QColor, QPalette + +theme_list = [ + "Dark", + "Light", + "System Default", + "Wong (Colorblind Friendly)" +] + +grp_dict = { + "ACTIVE": QPalette.ColorGroup.Active, + "INACTIVE": QPalette.ColorGroup.Inactive, + "DISABLED": QPalette.ColorGroup.Disabled +} + +role_dict = { + "WINDOW_TEXT": QPalette.ColorRole.WindowText, + "BUTTON": QPalette.ColorRole.Button, + "LIGHT": QPalette.ColorRole.Light, + "MID_LIGHT": QPalette.ColorRole.Midlight, + "DARK": QPalette.ColorRole.Dark, + "MID": QPalette.ColorRole.Mid, + "TEXT": QPalette.ColorRole.Text, + "BRIGHT_TEXT": QPalette.ColorRole.BrightText, + "BUTTON_TEXT": QPalette.ColorRole.ButtonText, + "BASE": QPalette.ColorRole.Base, + "WINDOW": QPalette.ColorRole.Window, + "SHADOW": QPalette.ColorRole.Shadow, + "HIGHLIGHT": QPalette.ColorRole.Highlight, + "HIGHLIGHTED_TEXT": QPalette.ColorRole.HighlightedText, + "LINK": QPalette.ColorRole.Link, + "LINK_VISITED": QPalette.ColorRole.LinkVisited, + "ALTERNATE_BASE": QPalette.ColorRole.AlternateBase, + "TOOLTIP_BASE": QPalette.ColorRole.ToolTipBase, + "TOOLTIP_TEXT": QPalette.ColorRole.ToolTipText, + "PLACEHOLDER_TEXT": QPalette.ColorRole.PlaceholderText +} + + +# TODO: Previewing themes in settings window would drastically increase usability +def change_theme(new_theme): + """Update app theme based on user choice in settings window + + Args: + new_theme (str): Predefined theme chosen from theme_list + + Returns: + QPalette: Complete color palette swap for the app + """ + match new_theme: + case "Dark": + dup_dict = { + "WINDOW_TEXT": "#FFFFFF", + "BUTTON": "#241F31", + "LIGHT": "#80FFFFFF", + "MID_LIGHT": "#2D263D", + "DARK": "#80000000", + "MID": "#000000", + "TEXT": "#FFFFFF", + "BRIGHT_TEXT": "#FFFFFF", + "BUTTON_TEXT": "#FFFFFF", + "BASE": "#000000", + "WINDOW": "#241F31", + "SHADOW": "#000000", + "HIGHLIGHT": "#308CC6", + "HIGHLIGHTED_TEXT": "#FFFFFF", + "LINK": "#0000FF", + "LINK_VISITED": "#FF00FF", + "ALTERNATE_BASE": "#120F18", + "TOOLTIP_BASE": "#FFFFDC", + "TOOLTIP_TEXT": "#000000", + "PLACEHOLDER_TEXT": "#80FFFFFF" + } + + dark_dict = { + "ACTIVE": dup_dict, + "INACTIVE": dup_dict, + "DISABLED": { + "WINDOW_TEXT": "#80FFFFFF", + "BUTTON": "#241F31", + "LIGHT": "#362E49", + "MID_LIGHT": "#2D263D", + "DARK": "#120F18", + "MID": "#181521", + "TEXT": "#120F18", + "BRIGHT_TEXT": "#FFFFFF", + "BUTTON_TEXT": "#80FFFFFF", + "BASE": "#241F31", + "WINDOW": "#241F31", + "SHADOW": "#000000", + "HIGHLIGHT": "#919191", + "HIGHLIGHTED_TEXT": "#FFFFFF", + "LINK": "#0000FF", + "LINK_VISITED": "#FF00FF", + "ALTERNATE_BASE": "#241F31", + "TOOLTIP_BASE": "#FFFFDC", + "TOOLTIP_TEXT": "#000000", + "PLACEHOLDER_TEXT": "#80FFFFFF" + }, + } + dark_palette = update_theme(dark_dict) + return dark_palette + case "Light": + dup_dict = { + "WINDOW_TEXT": "#000000", + "BUTTON": "#EFEFEF", + "LIGHT": "#FFFFFF", + "MID_LIGHT": "#CACACA", + "DARK": "#5E5C64", + "MID": "#B8B8B8", + "TEXT": "#000000", + "BRIGHT_TEXT": "#FFFFFF", + "BUTTON_TEXT": "#000000", + "BASE": "#FFFFFF", + "WINDOW": "#EFEFEF", + "SHADOW": "#767676", + "HIGHLIGHT": "#308CC6", + "HIGHLIGHTED_TEXT": "#FFFFFF", + "LINK": "#0000FF", + "LINK_VISITED": "#FF00FF", + "ALTERNATE_BASE": "#F7F7F7", + "TOOLTIP_BASE": "#FFFFDC", + "TOOLTIP_TEXT": "#000000", + "PLACEHOLDER_TEXT": "#80000000" + } + + light_dict = { + "ACTIVE": dup_dict, + "INACTIVE": dup_dict, + "DISABLED": { + "WINDOW_TEXT": "#BEBEBE", + "BUTTON": "#EFEFEF", + "LIGHT": "#FFFFFF", + "MID_LIGHT": "#CACACA", + "DARK": "#BEBEBE", + "MID": "#B8B8B8", + "TEXT": "#BEBEBE", + "BRIGHT_TEXT": "#FFFFFF", + "BUTTON_TEXT": "#BEBEBE", + "BASE": "#EFEFEF", + "WINDOW": "#EFEFEF", + "SHADOW": "#B1B1B1", + "HIGHLIGHT": "#919191", + "HIGHLIGHTED_TEXT": "#FFFFFF", + "LINK": "#0000FF", + "LINK_VISITED": "#FF00FF", + "ALTERNATE_BASE": "#F7F7F7", + "TOOLTIP_BASE": "#FFFFDC", + "TOOLTIP_TEXT": "#000000", + "PLACEHOLDER_TEXT": "#80000000" + }, + } + light_palette = update_theme(light_dict) + return light_palette + case "System Default": + sys_default = QPalette() + return sys_default + case "Wong (Colorblind Friendly)": + dup_dict = { + "WINDOW_TEXT": "#000000", + "BUTTON": "#E69F00", + "LIGHT": "#FFFFFF", + "MID_LIGHT": "#000000", + "DARK": "#000000", + "MID": "#000000", + "TEXT": "#000000", + "BRIGHT_TEXT": "#FFFFFF", + "BUTTON_TEXT": "#000000", + "BASE": "#E69F00", + "WINDOW": "#009E73", + "SHADOW": "#009E73", + "HIGHLIGHT": "#0072B2", + "HIGHLIGHTED_TEXT": "#FFFFFF", + "LINK": "#56B4E9", + "LINK_VISITED": "#CC79A7", + "ALTERNATE_BASE": "#E69F00", + "TOOLTIP_BASE": "#FFFFDC", + "TOOLTIP_TEXT": "#000000", + "PLACEHOLDER_TEXT": "#80000000" + } + + wong_dict = { + "ACTIVE": dup_dict, + "INACTIVE": dup_dict, + "DISABLED": { + "WINDOW_TEXT": "#80000000", + "BUTTON": "#E69F00", + "LIGHT": "#FFFFFF", + "MID_LIGHT": "#FFFFFF", + "DARK": "#FFFFFF", + "MID": "#FFFFFF", + "TEXT": "#FFFFFF", + "BRIGHT_TEXT": "#000000", + "BUTTON_TEXT": "#80000000", + "BASE": "#E69F00", + "WINDOW": "#000000", + "SHADOW": "#F0E442", + "HIGHLIGHT": "#919191", + "HIGHLIGHTED_TEXT": "#000000", + "LINK": "#56b4E9", + "LINK_VISITED": "#CC79A7", + "ALTERNATE_BASE": "#919191", + "TOOLTIP_BASE": "#000000", + "TOOLTIP_TEXT": "#FFFFFF", + "PLACEHOLDER_TEXT": "#80000000" + }, + } + wong_palette = update_theme(wong_dict) + return wong_palette + case _: + print("There was an error parsing themes.") + + +def update_theme(cur_dict): + """Recursive function to parameterize theme dictionary and return palette + + Args: + cur_dict (dict): Self-explanatory + + Return: + QPalette: Self-explanatory + """ + new_palette = QPalette() + + for group in cur_dict: + cur_grp = grp_dict[group] + + for color in cur_dict[group]: + cur_role = role_dict[color] + new_palette.setColor(cur_grp, cur_role, QColor(cur_dict[group][color])) + + return new_palette diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index db0996d2..a18234fd 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -164,6 +164,17 @@ def setupUi(self, Dialog): spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_15.addItem(spacerItem3) self.verticalLayout_5.addLayout(self.horizontalLayout_15) + self.horizontalLayout_17 = QtWidgets.QHBoxLayout() + self.horizontalLayout_17.setObjectName("horizontalLayout_17") + self.label_14 = QtWidgets.QLabel(parent=self.page) + self.label_14.setObjectName("label_14") + self.horizontalLayout_17.addWidget(self.label_14) + self.comboBox_Theme = QtWidgets.QComboBox(parent=self.page) + self.comboBox_Theme.setObjectName("comboBox_Theme") + self.horizontalLayout_17.addWidget(self.comboBox_Theme) + spacerItem15 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_17.addItem(spacerItem15) + self.verticalLayout_5.addLayout(self.horizontalLayout_17) spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_5.addItem(spacerItem4) self.gridLayout_2.addLayout(self.verticalLayout_5, 0, 0, 1, 1) @@ -362,6 +373,7 @@ def retranslateUi(self, Dialog): self.checkBox_AutoAttachRegex.setText(_translate("Dialog", "Regex")) self.label_13.setText(_translate("Dialog", "Language")) self.label_11.setText(_translate("Dialog", "Logo")) + self.label_14.setText(_translate("Dialog", "Theme")) self.label_3.setText(_translate("Dialog", "Functions")) self.label_4.setText(_translate("Dialog", "Hotkey")) self.pushButton_ClearHotkey.setText(_translate("Dialog", "Clear")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 09bc7001..6502dd4f 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -338,6 +338,33 @@ Patterns at former positions have higher priority if regex is off + + + + + + Theme + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/PINCE.py b/PINCE.py index b9fb16d6..a3febb7c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -41,6 +41,8 @@ from libpince import utils, debugcore, typedefs from libpince.libscanmem.scanmem import Scanmem +from GUI.Settings.themes import change_theme +from GUI.Settings.themes import theme_list from GUI.Utils import guiutils from GUI.MainWindow import Ui_MainWindow as MainWindow @@ -94,6 +96,7 @@ ("简体中文", "zh_CN") ] + def get_locale(): system_locale = QLocale.system().name() for _, locale in language_list: @@ -101,6 +104,7 @@ def get_locale(): return locale return language_list[0][1] + if __name__ == '__main__': app = QApplication(sys.argv) app.setOrganizationName("PINCE") @@ -135,6 +139,7 @@ def get_locale(): auto_attach_regex = bool locale = str logo_path = str +theme = str class Hotkeys: @@ -317,9 +322,11 @@ def get_hotkeys(): # Placeholder number, may have to be changed in the future threadpool.setMaxThreadCount(10) + class WorkerSignals(QObject): finished = pyqtSignal() + class Worker(QRunnable): def __init__(self, fn, *args, **kwargs): super(Worker, self).__init__() @@ -470,6 +477,11 @@ def __init__(self): else: self.apply_after_init() self.memory_view_window = MemoryViewWindowForm(self) + try: + app.setPalette(change_theme(theme)) + except Exception as e: + app.setPalette(change_theme("System Default")) + print("An exception occurred while setting color palette, using system theme\n", e) self.about_widget = AboutWidgetForm() self.await_exit_thread = AwaitProcessExit() self.await_exit_thread.process_exited.connect(self.on_inferior_exit) @@ -561,6 +573,7 @@ def set_default_settings(self): self.settings.setValue("auto_attach_regex", False) self.settings.setValue("locale", get_locale()) self.settings.setValue("logo_path", "ozgurozbek/pince_small_transparent.png") + self.settings.setValue("theme", "System Default") self.settings.endGroup() self.settings.beginGroup("Hotkeys") for hotkey in Hotkeys.get_hotkeys(): @@ -606,6 +619,7 @@ def apply_settings(self): global auto_attach_regex global locale global logo_path + global theme global code_injection_method global bring_disassemble_to_front global instructions_per_scroll @@ -621,6 +635,7 @@ def apply_settings(self): locale = self.settings.value("General/locale", type=str) logo_path = self.settings.value("General/logo_path", type=str) app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) + theme = self.settings.value("General/theme", type=str) debugcore.set_gdb_output_mode(gdb_output_mode) for hotkey in Hotkeys.get_hotkeys(): hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) @@ -2304,6 +2319,10 @@ def accept(self): if locale != new_locale: QMessageBox.information(self, tr.INFO, tr.LANG_RESET) self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) + new_theme = theme_list[self.comboBox_Theme.currentIndex()] + self.settings.setValue("General/theme", self.comboBox_Theme.currentText()) + if theme != new_theme: + app.setPalette(change_theme(new_theme)) for hotkey in Hotkeys.get_hotkeys(): self.settings.setValue("Hotkeys/" + hotkey.name, self.hotkey_to_value[hotkey.name]) if self.radioButton_SimpleDLopenCall.isChecked(): @@ -2342,6 +2361,12 @@ def config_gui(self): self.comboBox_Language.addItem(lang) if loc == cur_loc: self.comboBox_Language.setCurrentIndex(self.comboBox_Language.count()-1) + self.comboBox_Theme.clear() + cur_theme = self.settings.value("General/theme", type=str) + for thm in theme_list: + self.comboBox_Theme.addItem(thm) + if thm == cur_theme: + self.comboBox_Theme.setCurrentIndex(self.comboBox_Theme.count()-1) logo_directory = utils.get_logo_directory() logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") self.comboBox_Logo.clear() From f209bf92643ec91b11389f3c9659531070525817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 28 Dec 2023 17:26:25 +0300 Subject: [PATCH 300/487] Hotfix theme settings --- PINCE.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/PINCE.py b/PINCE.py index a3febb7c..4564f527 100755 --- a/PINCE.py +++ b/PINCE.py @@ -130,7 +130,7 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "26" # Increase version by one if you change settings +current_settings_version = "27" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -477,11 +477,6 @@ def __init__(self): else: self.apply_after_init() self.memory_view_window = MemoryViewWindowForm(self) - try: - app.setPalette(change_theme(theme)) - except Exception as e: - app.setPalette(change_theme("System Default")) - print("An exception occurred while setting color palette, using system theme\n", e) self.about_widget = AboutWidgetForm() self.await_exit_thread = AwaitProcessExit() self.await_exit_thread.process_exited.connect(self.on_inferior_exit) @@ -636,6 +631,7 @@ def apply_settings(self): logo_path = self.settings.value("General/logo_path", type=str) app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) theme = self.settings.value("General/theme", type=str) + app.setPalette(change_theme(theme)) debugcore.set_gdb_output_mode(gdb_output_mode) for hotkey in Hotkeys.get_hotkeys(): hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) @@ -2319,10 +2315,7 @@ def accept(self): if locale != new_locale: QMessageBox.information(self, tr.INFO, tr.LANG_RESET) self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) - new_theme = theme_list[self.comboBox_Theme.currentIndex()] self.settings.setValue("General/theme", self.comboBox_Theme.currentText()) - if theme != new_theme: - app.setPalette(change_theme(new_theme)) for hotkey in Hotkeys.get_hotkeys(): self.settings.setValue("Hotkeys/" + hotkey.name, self.hotkey_to_value[hotkey.name]) if self.radioButton_SimpleDLopenCall.isChecked(): From 16d6d3ef5a0b402d54c866f523b39c8a47cb4fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 28 Dec 2023 21:14:39 +0300 Subject: [PATCH 301/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 133c74e5..751d4ce8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ The rules are about the same with PEP-8, with some changes. While they are not s - Variables: snake_case - Functions: snake_case - Constants: SCREAMING_SNAKE_CASE - - Modules: Not yet specified, a bit random at the moment, will be addressed later on + - Modules: flatcase - Standalone scripts: snake_case - Variable naming for Qt: - Classes: PascalCase @@ -219,4 +219,3 @@ Implement a flexible input field for the execution count. For instance, 2^x only - Add ability to include non-absolute calls for dissect code feature(i.e call rax). Should be considered after the first version release. Might be useful for multi-breakpoint related features - Provide information about absolute addresses in disassemble screen - All tables that hold large amount of data should only update the visible rows(check ```disassemble_check_viewport``` for an example) -- Add different kinds of themes and the ability to change between them on runtime. Implement dark theme first. Also add the ability to create a custom theme and modify the existing ones From 7d9c3329f436d42c7807cc6da4952b80f1e9241f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 29 Dec 2023 15:35:23 +0300 Subject: [PATCH 302/487] Preview logo and theme changes in settings --- GUI/Settings/themes.py | 1 - PINCE.py | 25 ++++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/GUI/Settings/themes.py b/GUI/Settings/themes.py index 920f2910..591e656e 100644 --- a/GUI/Settings/themes.py +++ b/GUI/Settings/themes.py @@ -37,7 +37,6 @@ } -# TODO: Previewing themes in settings window would drastically increase usability def change_theme(new_theme): """Update app theme based on user choice in settings window diff --git a/PINCE.py b/PINCE.py index 4564f527..f0e43e34 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2248,6 +2248,7 @@ def __init__(self, set_default_settings_func, parent=None): self.settings = QSettings() self.set_default_settings = set_default_settings_func self.hotkey_to_value = {} # Dict[str:str]-->Dict[Hotkey.name:settings_value] + self.handle_signals_data = None self.listWidget_Options.currentRowChanged.connect(self.change_display) icons_directory = guiutils.get_icons_directory() self.pushButton_GDBPath.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) @@ -2258,9 +2259,9 @@ def __init__(self, set_default_settings_func, parent=None): self.pushButton_GDBPath.clicked.connect(self.pushButton_GDBPath_clicked) self.checkBox_AutoUpdateAddressTable.stateChanged.connect(self.checkBox_AutoUpdateAddressTable_state_changed) self.checkBox_AutoAttachRegex.stateChanged.connect(self.checkBox_AutoAttachRegex_state_changed) - self.checkBox_AutoAttachRegex_state_changed() + self.comboBox_Logo.currentIndexChanged.connect(self.comboBox_Logo_current_index_changed) + self.comboBox_Theme.currentIndexChanged.connect(self.comboBox_Theme_current_index_changed) self.pushButton_HandleSignals.clicked.connect(self.pushButton_HandleSignals_clicked) - self.handle_signals_data = None self.config_gui() def accept(self): @@ -2335,7 +2336,14 @@ def accept(self): self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) if self.handle_signals_data is not None: self.settings.setValue("Debug/ignored_signals", ",".join(self.handle_signals_data)) - super(SettingsDialogForm, self).accept() + super().accept() + + def reject(self): + logo_path = self.settings.value("General/logo_path", type=str) + app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) + theme = self.settings.value("General/theme", type=str) + app.setPalette(change_theme(theme)) + super().reject() def config_gui(self): self.checkBox_AutoUpdateAddressTable.setChecked( @@ -2354,18 +2362,22 @@ def config_gui(self): self.comboBox_Language.addItem(lang) if loc == cur_loc: self.comboBox_Language.setCurrentIndex(self.comboBox_Language.count()-1) + self.comboBox_Theme.blockSignals(True) self.comboBox_Theme.clear() cur_theme = self.settings.value("General/theme", type=str) for thm in theme_list: self.comboBox_Theme.addItem(thm) if thm == cur_theme: self.comboBox_Theme.setCurrentIndex(self.comboBox_Theme.count()-1) + self.comboBox_Theme.blockSignals(False) logo_directory = utils.get_logo_directory() logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") + self.comboBox_Logo.blockSignals(True) self.comboBox_Logo.clear() for logo in logo_list: self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) self.comboBox_Logo.setCurrentIndex(logo_list.index(self.settings.value("General/logo_path", type=str))) + self.comboBox_Logo.blockSignals(False) self.listWidget_Functions.clear() self.hotkey_to_value.clear() for hotkey in Hotkeys.get_hotkeys(): @@ -2423,6 +2435,13 @@ def checkBox_AutoAttachRegex_state_changed(self): self.lineEdit_AutoAttachList.setPlaceholderText(tr.SEPARATE_PROCESSES_WITH.format(";")) self.lineEdit_AutoAttachList.setToolTip("") + def comboBox_Logo_current_index_changed(self): + logo_path = self.comboBox_Logo.currentText() + app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) + + def comboBox_Theme_current_index_changed(self): + app.setPalette(change_theme(self.comboBox_Theme.currentText())) + def pushButton_GDBPath_clicked(self): current_path = self.lineEdit_GDBPath.text() file_path = QFileDialog.getOpenFileName(self, tr.SELECT_GDB_BINARY, os.path.dirname(current_path))[0] From a6b8beea83d4187974e0161a78607e82d1bf05bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 29 Dec 2023 20:10:39 +0300 Subject: [PATCH 303/487] Rename theme functions and update docstrings --- GUI/Settings/themes.py | 34 +++++++++++++++------------------- PINCE.py | 8 ++++---- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/GUI/Settings/themes.py b/GUI/Settings/themes.py index 591e656e..db82b1c0 100644 --- a/GUI/Settings/themes.py +++ b/GUI/Settings/themes.py @@ -37,16 +37,16 @@ } -def change_theme(new_theme): - """Update app theme based on user choice in settings window +def get_theme(theme_name): + """Returns a customized theme based on the specified theme choice Args: - new_theme (str): Predefined theme chosen from theme_list + theme_name (str): Predefined theme chosen from theme_list Returns: QPalette: Complete color palette swap for the app """ - match new_theme: + match theme_name: case "Dark": dup_dict = { "WINDOW_TEXT": "#FFFFFF", @@ -97,8 +97,7 @@ def change_theme(new_theme): "PLACEHOLDER_TEXT": "#80FFFFFF" }, } - dark_palette = update_theme(dark_dict) - return dark_palette + return apply_palette(dark_dict) case "Light": dup_dict = { "WINDOW_TEXT": "#000000", @@ -149,11 +148,9 @@ def change_theme(new_theme): "PLACEHOLDER_TEXT": "#80000000" }, } - light_palette = update_theme(light_dict) - return light_palette + return apply_palette(light_dict) case "System Default": - sys_default = QPalette() - return sys_default + return QPalette() case "Wong (Colorblind Friendly)": dup_dict = { "WINDOW_TEXT": "#000000", @@ -204,28 +201,27 @@ def change_theme(new_theme): "PLACEHOLDER_TEXT": "#80000000" }, } - wong_palette = update_theme(wong_dict) - return wong_palette + return apply_palette(wong_dict) case _: - print("There was an error parsing themes.") + print("There was an error parsing themes") -def update_theme(cur_dict): - """Recursive function to parameterize theme dictionary and return palette +def apply_palette(theme_dict): + """Creates a palette based on the given theme dictionary Args: - cur_dict (dict): Self-explanatory + theme_dict (dict): See the usage in get_theme Return: QPalette: Self-explanatory """ new_palette = QPalette() - for group in cur_dict: + for group in theme_dict: cur_grp = grp_dict[group] - for color in cur_dict[group]: + for color in theme_dict[group]: cur_role = role_dict[color] - new_palette.setColor(cur_grp, cur_role, QColor(cur_dict[group][color])) + new_palette.setColor(cur_grp, cur_role, QColor(theme_dict[group][color])) return new_palette diff --git a/PINCE.py b/PINCE.py index f0e43e34..0baf1d43 100755 --- a/PINCE.py +++ b/PINCE.py @@ -41,7 +41,7 @@ from libpince import utils, debugcore, typedefs from libpince.libscanmem.scanmem import Scanmem -from GUI.Settings.themes import change_theme +from GUI.Settings.themes import get_theme from GUI.Settings.themes import theme_list from GUI.Utils import guiutils @@ -631,7 +631,7 @@ def apply_settings(self): logo_path = self.settings.value("General/logo_path", type=str) app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) theme = self.settings.value("General/theme", type=str) - app.setPalette(change_theme(theme)) + app.setPalette(get_theme(theme)) debugcore.set_gdb_output_mode(gdb_output_mode) for hotkey in Hotkeys.get_hotkeys(): hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) @@ -2342,7 +2342,7 @@ def reject(self): logo_path = self.settings.value("General/logo_path", type=str) app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) theme = self.settings.value("General/theme", type=str) - app.setPalette(change_theme(theme)) + app.setPalette(get_theme(theme)) super().reject() def config_gui(self): @@ -2440,7 +2440,7 @@ def comboBox_Logo_current_index_changed(self): app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) def comboBox_Theme_current_index_changed(self): - app.setPalette(change_theme(self.comboBox_Theme.currentText())) + app.setPalette(get_theme(self.comboBox_Theme.currentText())) def pushButton_GDBPath_clicked(self): current_path = self.lineEdit_GDBPath.text() From a2fa462d6a9adb77c4cad853891c497508154b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 31 Dec 2023 14:46:52 +0300 Subject: [PATCH 304/487] Create TMP_PATH and move gdb logs there --- libpince/debugcore.py | 3 +++ libpince/typedefs.py | 1 + libpince/utils.py | 28 +++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 0cde1176..a16f3bdf 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -461,6 +461,7 @@ def init_gdb(gdb_path=typedefs.PATHS.GDB_PATH): # Temporary IPC_PATH, this little hack is needed because send_command requires a valid IPC_PATH utils.create_ipc_path(currentpid) + utils.create_tmp_path(currentpid) breakpoint_on_hit_dict.clear() chained_breakpoints.clear() @@ -558,6 +559,7 @@ def attach(pid, gdb_path=typedefs.PATHS.GDB_PATH): currentpid = pid mem_file = "/proc/" + str(currentpid) + "/mem" utils.create_ipc_path(pid) + utils.create_tmp_path(pid) send_command("attach " + str(pid)) set_pince_paths() init_referenced_dicts(pid) @@ -612,6 +614,7 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=typedefs. currentpid = int(pid) mem_file = "/proc/" + str(currentpid) + "/mem" utils.create_ipc_path(pid) + utils.create_tmp_path(pid) set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() diff --git a/libpince/typedefs.py b/libpince/typedefs.py index ff46e5dc..fc35ee6c 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -26,6 +26,7 @@ class CONST_TIME: class PATHS: GDB_PATH = "/bin/gdb" + TMP_PATH = "/tmp/PINCE/" class IPC_PATHS: diff --git a/libpince/utils.py b/libpince/utils.py index 7af174ab..1a699bbe 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -279,6 +279,19 @@ def create_ipc_path(pid): open(command_file, "w").close() +#:tag:GDBCommunication +def create_tmp_path(pid): + """Creates the tmp directory of given pid + + Args: + pid (int,str): PID of the process + """ + path = get_tmp_path(pid) + if os.path.exists(path): + shutil.rmtree(path) + os.makedirs(path) + + #:tag:GDBCommunication def get_ipc_path(pid): """Get the IPC directory of given pid @@ -292,6 +305,19 @@ def get_ipc_path(pid): return typedefs.IPC_PATHS.PINCE_IPC_PATH + str(pid) +#:tag:GDBCommunication +def get_tmp_path(pid): + """Get the tmp directory of given pid + + Args: + pid (int): PID of the process + + Returns: + str: Path of tmp directory + """ + return typedefs.PATHS.TMP_PATH + str(pid) + + #:tag:GDBCommunication def get_logging_file(pid): """Get the path of gdb logfile of given pid @@ -302,7 +328,7 @@ def get_logging_file(pid): Returns: str: Path of gdb logfile """ - return get_ipc_path(pid) + "/gdb_log.txt" + return get_tmp_path(pid) + "/gdb_log.txt" #:tag:GDBCommunication From 3f89c68e2ee09202860d30f748ba8751e5091e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 31 Dec 2023 17:32:47 +0300 Subject: [PATCH 305/487] Merge paths and rename redundant members in typedefs --- GUI/Labels/FlagRegisterLabel.py | 2 +- GUI/Labels/RegisterLabel.py | 2 +- GUI/Utils/guiutils.py | 2 +- PINCE.py | 89 +++--- libpince/debugcore.py | 71 ++--- libpince/gdb_python_scripts/gdbextensions.py | 12 +- libpince/typedefs.py | 268 +++++++++---------- libpince/utils.py | 32 +-- 8 files changed, 235 insertions(+), 243 deletions(-) diff --git a/GUI/Labels/FlagRegisterLabel.py b/GUI/Labels/FlagRegisterLabel.py index 333d811e..dca90ac4 100644 --- a/GUI/Labels/FlagRegisterLabel.py +++ b/GUI/Labels/FlagRegisterLabel.py @@ -39,7 +39,7 @@ def enterEvent(self, QEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return registers = debugcore.read_registers() current_flag = self.objectName().lower() diff --git a/GUI/Labels/RegisterLabel.py b/GUI/Labels/RegisterLabel.py index a808e5b5..b829b3e2 100644 --- a/GUI/Labels/RegisterLabel.py +++ b/GUI/Labels/RegisterLabel.py @@ -39,7 +39,7 @@ def enterEvent(self, QEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) def mouseDoubleClickEvent(self, QMouseEvent): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return registers = debugcore.read_registers() current_register = self.objectName().lower() diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index 6ecf9bbc..df2fb948 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -85,7 +85,7 @@ def resize_to_contents(QTableWidget): #:tag:GUI -def fill_value_combobox(QCombobox, current_index=typedefs.VALUE_INDEX.INDEX_INT32): +def fill_value_combobox(QCombobox, current_index=typedefs.VALUE_INDEX.INT32): """Fills the given QCombobox with value_index strings Args: diff --git a/PINCE.py b/PINCE.py index 0baf1d43..9810101c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -111,7 +111,7 @@ def get_locale(): app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") app.setApplicationName("PINCE") QSettings.setPath(QSettings.Format.NativeFormat, QSettings.Scope.UserScope, - utils.get_user_path(typedefs.USER_PATHS.CONFIG_PATH)) + utils.get_user_path(typedefs.USER_PATHS.CONFIG)) settings = QSettings() translator = QTranslator() try: @@ -413,9 +413,9 @@ def run(self): while True: with debugcore.status_changed_condition: debugcore.status_changed_condition.wait() - if debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_STOPPED: + if debugcore.inferior_status == typedefs.INFERIOR_STATUS.STOPPED: self.process_stopped.emit() - elif debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + elif debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: self.process_running.emit() @@ -575,14 +575,14 @@ def set_default_settings(self): self.settings.setValue(hotkey.name, hotkey.default) self.settings.endGroup() self.settings.beginGroup("CodeInjection") - self.settings.setValue("code_injection_method", typedefs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL) + self.settings.setValue("code_injection_method", typedefs.INJECTION_METHOD.DLOPEN) self.settings.endGroup() self.settings.beginGroup("Disassemble") self.settings.setValue("bring_disassemble_to_front", False) self.settings.setValue("instructions_per_scroll", 2) self.settings.endGroup() self.settings.beginGroup("Debug") - self.settings.setValue("gdb_path", typedefs.PATHS.GDB_PATH) + self.settings.setValue("gdb_path", typedefs.PATHS.GDB) self.settings.setValue("gdb_logging", False) self.settings.setValue("ignored_signals", "1,1,1,0") self.settings.endGroup() @@ -806,7 +806,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): value_text = selected_row.text(VALUE_COL) encoding, option = typedefs.string_index_to_encoding_dict[value_type.value_index] byte_len = len(value_text.encode(encoding, option)) - elif value_type.value_index == typedefs.VALUE_INDEX.INDEX_AOB: + elif value_type.value_index == typedefs.VALUE_INDEX.AOB: byte_len = value_type.length else: byte_len = typedefs.index_to_valuetype_dict[value_type.value_index][0] @@ -1166,7 +1166,7 @@ def comboBox_ValueType_init(self): self.comboBox_ValueType.clear() for value_index, value_text in typedefs.scan_index_to_text_dict.items(): self.comboBox_ValueType.addItem(value_text, value_index) - self.comboBox_ValueType.setCurrentIndex(typedefs.SCAN_INDEX.INDEX_INT32) + self.comboBox_ValueType.setCurrentIndex(typedefs.SCAN_INDEX.INT32) self.comboBox_ValueType_current_index_changed() # :doc: @@ -1186,7 +1186,7 @@ def validate_search(self, search_for, search_for2): # none of these should be possible to be true at the same time scan_index = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) - if scan_index >= typedefs.SCAN_INDEX.INDEX_FLOAT_ANY and scan_index <= typedefs.SCAN_INDEX.INDEX_FLOAT64: + if scan_index >= typedefs.SCAN_INDEX.FLOAT_ANY and scan_index <= typedefs.SCAN_INDEX.FLOAT64: # Adjust to locale whatever the input if QLocale.system().decimalPoint() == ".": search_for = search_for.replace(",", ".") @@ -1194,7 +1194,7 @@ def validate_search(self, search_for, search_for2): else: search_for = search_for.replace(".", ",") search_for2 = search_for2.replace(".", ",") - elif scan_index == typedefs.SCAN_INDEX.INDEX_STRING: + elif scan_index == typedefs.SCAN_INDEX.STRING: search_for = "\" " + search_for elif self.checkBox_Hex.isChecked(): if not search_for.startswith("0x"): @@ -1270,9 +1270,9 @@ def scan_callback(self): self.QWidget_Toolbox.setEnabled(True) def _scan_to_length(self, type_index): - if type_index == typedefs.SCAN_INDEX.INDEX_AOB: + if type_index == typedefs.SCAN_INDEX.AOB: return self.lineEdit_Scan.text().count(" ") + 1 - if type_index == typedefs.SCAN_INDEX.INDEX_STRING: + if type_index == typedefs.SCAN_INDEX.STRING: return len(self.lineEdit_Scan.text()) return 0 @@ -1319,7 +1319,7 @@ def pushButton_AttachProcess_clicked(self): self.processwindow.show() def pushButton_Open_clicked(self): - pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES_PATH) + pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES) file_paths = QFileDialog.getOpenFileNames(self, tr.OPEN_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_paths: return @@ -1333,7 +1333,7 @@ def pushButton_Open_clicked(self): self.treeWidget_AddressTable.topLevelItemCount()) def pushButton_Save_clicked(self): - pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES_PATH) + pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES) file_path = QFileDialog.getSaveFileName(self, tr.SAVE_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_path: return @@ -1346,7 +1346,7 @@ def pushButton_Save_clicked(self): # Returns: a bool value indicates whether the operation succeeded. def attach_to_pid(self, pid): attach_result = debugcore.attach(pid, gdb_path) - if attach_result == typedefs.ATTACH_RESULT.ATTACH_SUCCESSFUL: + if attach_result == typedefs.ATTACH_RESULT.SUCCESSFUL: self.apply_after_init() scanmem.pid(pid) self.on_new_process() @@ -1780,7 +1780,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.show() self.checkBox_ZeroTerminate.setChecked(vt.zero_terminate) - elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.AOB: self.widget_Length.show() try: length = str(length) @@ -1892,7 +1892,7 @@ def comboBox_ValueType_current_index_changed(self): if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() self.checkBox_ZeroTerminate.show() - elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.AOB: self.widget_Length.show() self.checkBox_ZeroTerminate.hide() else: @@ -2007,7 +2007,7 @@ def __init__(self, parent=None, value_type=None): self.lineEdit_Length.setText(length) self.checkBox_ZeroTerminate.show() self.checkBox_ZeroTerminate.setChecked(vt.zero_terminate) - elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.AOB: self.widget_Length.show() try: length = str(length) @@ -2033,7 +2033,7 @@ def comboBox_ValueType_current_index_changed(self): if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() self.checkBox_ZeroTerminate.show() - elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.INDEX_AOB: + elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.AOB: self.widget_Length.show() self.checkBox_ZeroTerminate.hide() else: @@ -2156,7 +2156,7 @@ class InputDialogForm(QDialog, InputDialog): # that points the current index of the QComboBox, for instance: ["0", "1", 1] will create a QCombobox with the items # "0" and "1" then will set current index to 1 (which is the item "1") # label_alignment is optional - def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typedefs.VALUE_INDEX.INDEX_INT32, + def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typedefs.VALUE_INDEX.INT32, buttons=(QDialogButtonBox.StandardButton.Ok, QDialogButtonBox.StandardButton.Cancel)): super().__init__(parent=parent) self.setupUi(self) @@ -2320,9 +2320,9 @@ def accept(self): for hotkey in Hotkeys.get_hotkeys(): self.settings.setValue("Hotkeys/" + hotkey.name, self.hotkey_to_value[hotkey.name]) if self.radioButton_SimpleDLopenCall.isChecked(): - injection_method = typedefs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL + injection_method = typedefs.INJECTION_METHOD.DLOPEN elif self.radioButton_AdvancedInjection.isChecked(): - injection_method = typedefs.INJECTION_METHOD.ADVANCED_INJECTION + injection_method = typedefs.INJECTION_METHOD.ADVANCED self.settings.setValue("CodeInjection/code_injection_method", injection_method) self.settings.setValue("Disassemble/bring_disassemble_to_front", self.checkBox_BringDisassembleToFront.isChecked()) @@ -2384,9 +2384,9 @@ def config_gui(self): self.listWidget_Functions.addItem(hotkey.desc) self.hotkey_to_value[hotkey.name] = self.settings.value("Hotkeys/" + hotkey.name) injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) - if injection_method == typedefs.INJECTION_METHOD.SIMPLE_DLOPEN_CALL: + if injection_method == typedefs.INJECTION_METHOD.DLOPEN: self.radioButton_SimpleDLopenCall.setChecked(True) - elif injection_method == typedefs.INJECTION_METHOD.ADVANCED_INJECTION: + elif injection_method == typedefs.INJECTION_METHOD.ADVANCED: self.radioButton_AdvancedInjection.setChecked(True) self.checkBox_BringDisassembleToFront.setChecked( self.settings.value("Disassemble/bring_disassemble_to_front", type=bool)) @@ -2889,7 +2889,7 @@ def toggle_watchpoint(self, address, watchpoint_type=typedefs.WATCHPOINT_TYPE.BO watchpoint_dialog = InputDialogForm(item_list=[(tr.ENTER_WATCHPOINT_LENGTH, "")]) if watchpoint_dialog.exec(): user_input = watchpoint_dialog.get_values() - user_input_int = utils.parse_string(user_input, typedefs.VALUE_INDEX.INDEX_INT32) + user_input_int = utils.parse_string(user_input, typedefs.VALUE_INDEX.INT32) if user_input_int is None: QMessageBox.information(self, tr.ERROR, tr.PARSE_ERROR_INT.format(user_input)) return @@ -2988,7 +2988,7 @@ def exec_hex_view_add_address_dialog(self): if debugcore.currentpid == -1: return selected_address = self.tableView_HexView_Hex.get_selected_address() - vt = typedefs.ValueType(typedefs.VALUE_INDEX.INDEX_AOB) + vt = typedefs.ValueType(typedefs.VALUE_INDEX.AOB) manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), value_type=vt) if manual_address_dialog.exec(): desc, address, vt = manual_address_dialog.get_values() @@ -3401,7 +3401,7 @@ def update_registers(self): self.FS.set_value(registers["fs"]) def update_stacktrace(self): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return stack_trace_info = debugcore.get_stacktrace_info() self.tableWidget_StackTrace.setRowCount(0) @@ -3452,7 +3452,7 @@ def copy_to_clipboard(row, column): pass def update_stack(self): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return stack_info = debugcore.get_stack_info() self.tableWidget_Stack.setRowCount(0) @@ -4157,13 +4157,13 @@ def __init__(self, parent=None): def update_stacktrace(self): self.listWidget_ReturnAddresses.clear() - if debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return return_addresses = debugcore.get_stack_frame_return_addresses() self.listWidget_ReturnAddresses.addItems(return_addresses) def update_frame_info(self, index): - if debugcore.inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: self.textBrowser_Info.setText(tr.PROCESS_RUNNING) return frame_info = debugcore.get_stack_frame_info(index) @@ -4615,10 +4615,10 @@ def __init__(self, address, breakpoint, parent=None): super().__init__(parent=parent) self.setupUi(self) self.status_to_text = { - typedefs.TRACE_STATUS.STATUS_IDLE: tr.WAITING_FOR_BREAKPOINT, - typedefs.TRACE_STATUS.STATUS_CANCELED: tr.TRACING_CANCELED, - typedefs.TRACE_STATUS.STATUS_PROCESSING: tr.PROCESSING_DATA, - typedefs.TRACE_STATUS.STATUS_FINISHED: tr.TRACING_COMPLETED + typedefs.TRACE_STATUS.IDLE: tr.WAITING_FOR_BREAKPOINT, + typedefs.TRACE_STATUS.CANCELED: tr.TRACING_CANCELED, + typedefs.TRACE_STATUS.PROCESSING: tr.PROCESSING_DATA, + typedefs.TRACE_STATUS.FINISHED: tr.TRACING_COMPLETED } self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) guiutils.center(self) @@ -4640,11 +4640,10 @@ def __init__(self, address, breakpoint, parent=None): def change_status(self): status_info = debugcore.get_trace_instructions_status(self.breakpoint) - if status_info[0] == typedefs.TRACE_STATUS.STATUS_FINISHED or \ - status_info[0] == typedefs.TRACE_STATUS.STATUS_PROCESSING: + if status_info[0] == typedefs.TRACE_STATUS.FINISHED or status_info[0] == typedefs.TRACE_STATUS.PROCESSING: self.close() return - if status_info[0] == typedefs.TRACE_STATUS.STATUS_TRACING: + if status_info[0] == typedefs.TRACE_STATUS.TRACING: self.label_StatusText.setText(status_info[1]) else: self.label_StatusText.setText(self.status_to_text[status_info[0]]) @@ -4657,11 +4656,9 @@ def closeEvent(self, QCloseEvent): self.adjustSize() app.processEvents() status_info = debugcore.get_trace_instructions_status(self.breakpoint) - if status_info[0] == typedefs.TRACE_STATUS.STATUS_TRACING or \ - status_info[0] == typedefs.TRACE_STATUS.STATUS_PROCESSING: + if status_info[0] == typedefs.TRACE_STATUS.TRACING or status_info[0] == typedefs.TRACE_STATUS.PROCESSING: debugcore.cancel_trace_instructions(self.breakpoint) - while debugcore.get_trace_instructions_status(self.breakpoint)[0] \ - != typedefs.TRACE_STATUS.STATUS_FINISHED: + while debugcore.get_trace_instructions_status(self.breakpoint)[0] != typedefs.TRACE_STATUS.FINISHED: sleep(0.1) app.processEvents() debugcore.delete_breakpoint(self.address) @@ -4742,7 +4739,7 @@ def show_trace_info(self, trace_data=None): self.treeWidget_InstructionInfo.expandAll() def save_file(self): - trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) + trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS) file_path = QFileDialog.getSaveFileName(self, tr.SAVE_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] if file_path: file_path = utils.append_file_extension(file_path, "trace") @@ -4750,7 +4747,7 @@ def save_file(self): QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) def load_file(self): - trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS_PATH) + trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS) file_path = QFileDialog.getOpenFileName(self, tr.OPEN_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] if file_path: content = utils.load_file(file_path) @@ -4912,7 +4909,7 @@ def set_valid(self, valid): def lineEdit_Bytes_text_edited(self): bytes_aob = self.lineEdit_Bytes.text() - if utils.parse_string(bytes_aob, typedefs.VALUE_INDEX.INDEX_AOB): + if utils.parse_string(bytes_aob, typedefs.VALUE_INDEX.AOB): address = int(self.lineEdit_Address.text(), 0) instruction = utils.get_opcodes(address, bytes_aob, debugcore.inferior_arch) if instruction: @@ -4990,7 +4987,7 @@ def lineEdit_HexView_selection_changed(self): def lineEdit_HexView_text_edited(self): aob_string = self.lineEdit_HexView.text() - if not utils.parse_string(aob_string, typedefs.VALUE_INDEX.INDEX_AOB): + if not utils.parse_string(aob_string, typedefs.VALUE_INDEX.AOB): self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") return aob_array = aob_string.split() @@ -5032,7 +5029,7 @@ def accept(self): QMessageBox.information(self, tr.ERROR, tr.IS_INVALID_EXPRESSION.format(expression)) return value = self.lineEdit_HexView.text() - debugcore.write_memory(address, typedefs.VALUE_INDEX.INDEX_AOB, value) + debugcore.write_memory(address, typedefs.VALUE_INDEX.AOB, value) super(HexEditDialogForm, self).accept() @@ -5621,7 +5618,7 @@ class ReferencedStringsWidgetForm(QWidget, ReferencedStringsWidget): def __init__(self, parent=None): super().__init__() self.setupUi(self) - guiutils.fill_value_combobox(self.comboBox_ValueType, typedefs.VALUE_INDEX.INDEX_STRING_UTF8) + guiutils.fill_value_combobox(self.comboBox_ValueType, typedefs.VALUE_INDEX.STRING_UTF8) self.parent = lambda: parent global instances instances.append(self) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index a16f3bdf..4a631fba 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -203,10 +203,10 @@ def send_command(command, control=False, cli_output=False, send_with_file=False, raise typedefs.GDBInitializeException gdb_output = "" if send_with_file: - send_file = utils.get_ipc_from_pince_file(currentpid) + send_file = utils.get_from_pince_file(currentpid) pickle.dump(file_contents_send, open(send_file, "wb")) if recv_with_file or cli_output: - recv_file = utils.get_ipc_to_pince_file(currentpid) + recv_file = utils.get_to_pince_file(currentpid) # Truncating the recv_file because we wouldn't like to see output of previous command in case of errors open(recv_file, "w").close() @@ -285,9 +285,9 @@ def check_inferior_status(): if bp_num and breakpoint_on_hit_dict.get(bp_num.group(1), -1) != typedefs.BREAKPOINT_ON_HIT.BREAK: return stop_reason = typedefs.STOP_REASON.DEBUG - inferior_status = typedefs.INFERIOR_STATUS.INFERIOR_STOPPED + inferior_status = typedefs.INFERIOR_STATUS.STOPPED else: - inferior_status = typedefs.INFERIOR_STATUS.INFERIOR_RUNNING + inferior_status = typedefs.INFERIOR_STATUS.RUNNING if old_status != inferior_status: with status_changed_condition: status_changed_condition.notify_all() @@ -335,11 +335,11 @@ def execute_func_temporary_interruption(func, *args, **kwargs): ???: Result of the given function. Return type depends on the given function """ old_status = inferior_status - if old_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if old_status == typedefs.INFERIOR_STATUS.RUNNING: interrupt_inferior(typedefs.STOP_REASON.PAUSE) wait_for_stop() result = func(*args, **kwargs) - if old_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + if old_status == typedefs.INFERIOR_STATUS.RUNNING: continue_inferior() return result @@ -371,7 +371,7 @@ def wait_for_stop(timeout=1): timeout (float): Timeout time in seconds """ remaining_time = timeout - while inferior_status == typedefs.INFERIOR_STATUS.INFERIOR_RUNNING: + while inferior_status == typedefs.INFERIOR_STATUS.RUNNING: sleep(typedefs.CONST_TIME.GDB_INPUT_SLEEP) remaining_time -= typedefs.CONST_TIME.GDB_INPUT_SLEEP if remaining_time < 0: @@ -440,7 +440,7 @@ def unignore_signal(signal_name): #:tag:GDBCommunication -def init_gdb(gdb_path=typedefs.PATHS.GDB_PATH): +def init_gdb(gdb_path=typedefs.PATHS.GDB): """Spawns gdb and initializes/resets some of the global variables Args: @@ -482,8 +482,8 @@ def init_gdb(gdb_path=typedefs.PATHS.GDB_PATH): gdb_initialized = True set_logging(False) send_command("source ./gdbinit_venv") - send_command("source " + utils.get_user_path(typedefs.USER_PATHS.GDBINIT_PATH)) - utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_PATH)) + send_command("source " + utils.get_user_path(typedefs.USER_PATHS.GDBINIT)) + utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT)) #:tag:GDBCommunication @@ -507,7 +507,7 @@ def set_pince_paths(): """ libpince_dir = utils.get_libpince_directory() pince_dir = os.path.dirname(libpince_dir) - gdbinit_aa_dir = utils.get_user_path(typedefs.USER_PATHS.GDBINIT_AA_PATH) + gdbinit_aa_dir = utils.get_user_path(typedefs.USER_PATHS.GDBINIT_AA) send_command('set $GDBINIT_AA_PATH=' + '"' + gdbinit_aa_dir + '"') send_command('set $PINCE_PATH=' + '"' + pince_dir + '"') send_command("source gdb_python_scripts/gdbextensions.py") @@ -525,7 +525,7 @@ def init_referenced_dicts(pid): #:tag:Debug -def attach(pid, gdb_path=typedefs.PATHS.GDB_PATH): +def attach(pid, gdb_path=typedefs.PATHS.GDB): """Attaches gdb to the target and initializes some of the global variables Args: @@ -564,12 +564,12 @@ def attach(pid, gdb_path=typedefs.PATHS.GDB_PATH): set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() - utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_AA_PATH)) - return typedefs.ATTACH_RESULT.ATTACH_SUCCESSFUL + utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_AA)) + return typedefs.ATTACH_RESULT.SUCCESSFUL #:tag:Debug -def create_process(process_path, args="", ld_preload_path="", gdb_path=typedefs.PATHS.GDB_PATH): +def create_process(process_path, args="", ld_preload_path="", gdb_path=typedefs.PATHS.GDB): """Creates a new process for debugging and initializes some of the global variables Current process will be detached even if the create_process call fails Make sure to save your data before calling this monstrosity @@ -618,7 +618,7 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=typedefs. set_pince_paths() init_referenced_dicts(pid) inferior_arch = get_inferior_arch() - utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_AA_PATH)) + utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT_AA)) return True @@ -701,6 +701,7 @@ def inject_with_dlopen_call(library_path): Returns: bool: Result of the injection """ + # TODO: Merge injection functions and rename them to inject_so once advanced injection is implemented injectionpath = '"' + library_path + '"' result = call_function_from_inferior("dlopen(" + injectionpath + ", 1)")[1] if result == "0" or not result: @@ -726,9 +727,9 @@ def read_pointer(pointer_type): raise TypeError("Passed non-PointerType to read_pointer!") if inferior_arch == typedefs.INFERIOR_ARCH.ARCH_32: - value_index = typedefs.VALUE_INDEX.INDEX_INT32 + value_index = typedefs.VALUE_INDEX.INT32 else: - value_index = typedefs.VALUE_INDEX.INDEX_INT64 + value_index = typedefs.VALUE_INDEX.INT64 # Simple addresses first, examine_expression takes much longer time, especially for larger tables try: @@ -773,9 +774,9 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re address (str, int): Can be a hex string or an integer. value_index (int): Determines the type of data read. Can be a member of typedefs.VALUE_INDEX length (int): Length of the data that'll be read. Must be greater than 0. Only used when the value_index is - INDEX_STRING or INDEX_AOB. Ignored otherwise + STRING or AOB. Ignored otherwise zero_terminate (bool): If True, data will be split when a null character has been read. Only used when - value_index is INDEX_STRING. Ignored otherwise + value_index is STRING. Ignored otherwise value_repr (int): Can be a member of typedefs.VALUE_REPR. Only usable with integer types endian (int): Can be a member of typedefs.ENDIANNESS mem_handle (BinaryIO): A file handle that points to the memory file of the current process @@ -783,8 +784,8 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re Don't forget to close the handle after you're done if you use this parameter manually Returns: - str: If the value_index is INDEX_STRING or INDEX_AOB, also when value_repr is HEX - float: If the value_index is INDEX_FLOAT32 or INDEX_FLOAT64 + str: If the value_index is STRING or AOB, also when value_repr is HEX + float: If the value_index is FLOAT32 or FLOAT64 int: If the value_index is anything else None: If an error occurs while reading the given address """ @@ -810,7 +811,7 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re # print("length must be greater than 0") return expected_length = length * typedefs.string_index_to_multiplier_dict.get(value_index, 1) - elif value_index is typedefs.VALUE_INDEX.INDEX_AOB: + elif value_index is typedefs.VALUE_INDEX.AOB: try: expected_length = int(length) except: @@ -845,7 +846,7 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re else: returned_string = returned_string.split('\x00')[0] return returned_string[0:length] - elif value_index is typedefs.VALUE_INDEX.INDEX_AOB: + elif value_index is typedefs.VALUE_INDEX.AOB: return " ".join(format(n, '02x') for n in data_read) else: is_integer = typedefs.VALUE_INDEX.is_integer(value_index) @@ -886,7 +887,7 @@ def write_memory(address, value_index, value, endian=typedefs.ENDIANNESS.HOST): return encoding, option = typedefs.string_index_to_encoding_dict.get(value_index, (None, None)) if encoding is None: - if value_index is typedefs.VALUE_INDEX.INDEX_AOB: + if value_index is typedefs.VALUE_INDEX.AOB: write_data = bytearray(write_data) else: data_type = typedefs.index_to_struct_pack_dict.get(value_index, -1) @@ -1297,7 +1298,7 @@ def nop_instruction(start_address, length_of_instr): modified_instructions_dict[start_address] = old_aob nop_aob = '90 ' * length_of_instr - write_memory(start_address, typedefs.VALUE_INDEX.INDEX_AOB, nop_aob) + write_memory(start_address, typedefs.VALUE_INDEX.AOB, nop_aob) #:tag:MemoryRW @@ -1317,7 +1318,7 @@ def modify_instruction(start_address, array_of_bytes): global modified_instructions_dict if start_address not in modified_instructions_dict: modified_instructions_dict[start_address] = old_aob - write_memory(start_address, typedefs.VALUE_INDEX.INDEX_AOB, array_of_bytes) + write_memory(start_address, typedefs.VALUE_INDEX.AOB, array_of_bytes) #:tag:MemoryRW @@ -1332,7 +1333,7 @@ def restore_instruction(start_address): """ global modified_instructions_dict array_of_bytes = modified_instructions_dict.pop(start_address) - write_memory(start_address, typedefs.VALUE_INDEX.INDEX_AOB, array_of_bytes) + write_memory(start_address, typedefs.VALUE_INDEX.AOB, array_of_bytes) #:tag:BreakWatchpoints @@ -1441,7 +1442,7 @@ def hardware_breakpoint_available(): #:tag:BreakWatchpoints -def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE_BP, +def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE, on_hit=typedefs.BREAKPOINT_ON_HIT.BREAK): """Adds a breakpoint at the address evaluated by the given expression. Uses a software breakpoint if all hardware breakpoint slots are being used @@ -1463,13 +1464,13 @@ def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE if check_address_in_breakpoints(str_address): print("breakpoint/watchpoint for address " + str_address + " is already set") return - if breakpoint_type == typedefs.BREAKPOINT_TYPE.HARDWARE_BP: + if breakpoint_type == typedefs.BREAKPOINT_TYPE.HARDWARE: if hardware_breakpoint_available(): output = send_command("hbreak *" + str_address) else: print("All hardware breakpoint slots are being used, using a software breakpoint instead") output = send_command("break *" + str_address) - elif breakpoint_type == typedefs.BREAKPOINT_TYPE.SOFTWARE_BP: + elif breakpoint_type == typedefs.BREAKPOINT_TYPE.SOFTWARE: output = send_command("break *" + str_address) if regexes.breakpoint_created.search(output): global breakpoint_on_hit_dict @@ -1786,7 +1787,7 @@ def trace_instructions(expression, max_trace_count=1000, trigger_condition="", s if not breakpoint: return modify_breakpoint(expression, typedefs.BREAKPOINT_MODIFY.CONDITION, condition=trigger_condition) - contents_send = (typedefs.TRACE_STATUS.STATUS_IDLE, "") + contents_send = (typedefs.TRACE_STATUS.IDLE, "") trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) pickle.dump(contents_send, open(trace_status_file, "wb")) param_str = ( @@ -1835,7 +1836,7 @@ def get_trace_instructions_status(breakpoint): tuple:(status_id, status_str) status_id-->(int) A member of typedefs.TRACE_STATUS - status_str-->(str) Status string, only used with typedefs.TRACE_STATUS.STATUS_TRACING + status_str-->(str) Status string, only used with typedefs.TRACE_STATUS.TRACING Returns a tuple of (None, "") if fails to gather info """ @@ -1854,7 +1855,7 @@ def cancel_trace_instructions(breakpoint): Args: breakpoint (str): breakpoint number, must be returned from trace_instructions() """ - status_info = (typedefs.TRACE_STATUS.STATUS_CANCELED, "") + status_info = (typedefs.TRACE_STATUS.CANCELED, "") trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) pickle.dump(status_info, open(trace_status_file, "wb")) @@ -2024,7 +2025,7 @@ def get_dissect_code_data(referenced_strings=True, referenced_jumps=True, refere #:tag:Tools -def search_referenced_strings(searched_str, value_index=typedefs.VALUE_INDEX.INDEX_STRING_UTF8, case_sensitive=False, +def search_referenced_strings(searched_str, value_index=typedefs.VALUE_INDEX.STRING_UTF8, case_sensitive=False, enable_regex=False): """Searches for given str in the referenced strings diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index d4414ca6..7dc86b65 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -28,8 +28,8 @@ inferior = gdb.selected_inferior() pid = inferior.pid -recv_file = utils.get_ipc_from_pince_file(pid) -send_file = utils.get_ipc_to_pince_file(pid) +recv_file = utils.get_from_pince_file(pid) +send_file = utils.get_to_pince_file(pid) lib = None @@ -350,7 +350,7 @@ def invoke(self, arg, from_tty): for x in range(max_trace_count): try: output = pickle.load(open(trace_status_file, "rb")) - if output[0] == typedefs.TRACE_STATUS.STATUS_CANCELED: + if output[0] == typedefs.TRACE_STATUS.CANCELED: break except: pass @@ -367,7 +367,7 @@ def invoke(self, arg, from_tty): current_index += 1 tree.append([(line_info, collect_dict), current_root_index, []]) tree[current_root_index][2].append(current_index) # Add a child - status_info = (typedefs.TRACE_STATUS.STATUS_TRACING, + status_info = (typedefs.TRACE_STATUS.TRACING, line_info + "\n(" + str(x + 1) + "/" + str(max_trace_count) + ")") pickle.dump(status_info, open(trace_status_file, "wb")) if regexes.trace_instructions_ret.search(line_info): @@ -392,11 +392,11 @@ def invoke(self, arg, from_tty): gdb.execute("stepi", to_string=True) elif step_mode == typedefs.STEP_MODE.STEP_OVER: gdb.execute("nexti", to_string=True) - status_info = (typedefs.TRACE_STATUS.STATUS_PROCESSING, "") + status_info = (typedefs.TRACE_STATUS.PROCESSING, "") pickle.dump(status_info, open(trace_status_file, "wb")) trace_instructions_file = utils.get_trace_instructions_file(pid, breakpoint) json.dump((tree, root_index), open(trace_instructions_file, "w")) - status_info = (typedefs.TRACE_STATUS.STATUS_FINISHED, "") + status_info = (typedefs.TRACE_STATUS.FINISHED, "") pickle.dump(status_info, open(trace_status_file, "wb")) if not stop_after_trace: gdb.execute("c&") diff --git a/libpince/typedefs.py b/libpince/typedefs.py index fc35ee6c..7f18fd39 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -25,41 +25,36 @@ class CONST_TIME: class PATHS: - GDB_PATH = "/bin/gdb" - TMP_PATH = "/tmp/PINCE/" - - -class IPC_PATHS: - PINCE_IPC_PATH = "/dev/shm/PINCE-connection/" # Use utils.get_ipc_path() - IPC_FROM_PINCE_PATH = "/from_PINCE_file" # Use utils.get_ipc_from_pince_file() - IPC_TO_PINCE_PATH = "/to_PINCE_file" # Use utils.get_ipc_to_pince_file() + GDB = "/bin/gdb" + TMP = "/tmp/PINCE/" # Use utils.get_tmp_path() + IPC = "/dev/shm/PINCE_IPC/" # Use utils.get_ipc_path() + FROM_PINCE = "/from_PINCE" # Use utils.get_from_pince_file() + TO_PINCE = "/to_PINCE" # Use utils.get_to_pince_file() class USER_PATHS: # Use utils.get_user_path() to make use of these - - CONFIG_PATH = ".config/" - ROOT_PATH = CONFIG_PATH + "PINCE/PINCE_USER_FILES/" - TRACE_INSTRUCTIONS_PATH = ROOT_PATH + "TraceInstructions/" - CHEAT_TABLES_PATH = ROOT_PATH + "CheatTables/" - GDBINIT_PATH = ROOT_PATH + "gdbinit" - GDBINIT_AA_PATH = ROOT_PATH + "gdbinit_after_attach" - PINCEINIT_PATH = ROOT_PATH + "pinceinit.py" - PINCEINIT_AA_PATH = ROOT_PATH + "pinceinit_after_attach.py" + CONFIG = ".config/" + ROOT = CONFIG + "PINCE/PINCE_USER_FILES/" + TRACE_INSTRUCTIONS = ROOT + "TraceInstructions/" + CHEAT_TABLES = ROOT + "CheatTables/" + GDBINIT = ROOT + "gdbinit" + GDBINIT_AA = ROOT + "gdbinit_after_attach" + PINCEINIT = ROOT + "pinceinit.py" + PINCEINIT_AA = ROOT + "pinceinit_after_attach.py" @staticmethod def get_init_directories(): - return USER_PATHS.ROOT_PATH, USER_PATHS.TRACE_INSTRUCTIONS_PATH, USER_PATHS.CHEAT_TABLES_PATH + return USER_PATHS.ROOT, USER_PATHS.TRACE_INSTRUCTIONS, USER_PATHS.CHEAT_TABLES @staticmethod def get_init_files(): - return USER_PATHS.GDBINIT_PATH, USER_PATHS.GDBINIT_AA_PATH, USER_PATHS.PINCEINIT_PATH, \ - USER_PATHS.PINCEINIT_AA_PATH + return USER_PATHS.GDBINIT, USER_PATHS.GDBINIT_AA, USER_PATHS.PINCEINIT, USER_PATHS.PINCEINIT_AA class INFERIOR_STATUS: - INFERIOR_RUNNING = 1 - INFERIOR_STOPPED = 2 + RUNNING = 1 + STOPPED = 2 class INFERIOR_ARCH: @@ -68,13 +63,13 @@ class INFERIOR_ARCH: class INJECTION_METHOD: - SIMPLE_DLOPEN_CALL = 1 - ADVANCED_INJECTION = 2 + DLOPEN = 1 + ADVANCED = 2 class BREAKPOINT_TYPE: - HARDWARE_BP = 1 - SOFTWARE_BP = 2 + HARDWARE = 1 + SOFTWARE = 2 class WATCHPOINT_TYPE: @@ -105,11 +100,11 @@ class STEP_MODE: class TRACE_STATUS: - STATUS_IDLE = 1 - STATUS_TRACING = 2 - STATUS_CANCELED = 3 - STATUS_PROCESSING = 4 - STATUS_FINISHED = 5 + IDLE = 1 + TRACING = 2 + CANCELED = 3 + PROCESSING = 4 + FINISHED = 5 class STOP_REASON: @@ -119,7 +114,7 @@ class STOP_REASON: class ATTACH_RESULT: ATTACH_SELF = 1 - ATTACH_SUCCESSFUL = 2 + SUCCESSFUL = 2 PROCESS_NOT_VALID = 3 ALREADY_DEBUGGING = 4 ALREADY_TRACED = 5 @@ -157,50 +152,49 @@ class VALUE_REPR: class VALUE_INDEX: # Beginning of the integer indexes, new integer indexes should be added between 0 and 3 - INDEX_INT8 = 0 - INDEX_INT16 = 1 - INDEX_INT32 = 2 - INDEX_INT64 = 3 + INT8 = 0 + INT16 = 1 + INT32 = 2 + INT64 = 3 # Ending of the integer indexes - INDEX_FLOAT32 = 4 - INDEX_FLOAT64 = 5 + FLOAT32 = 4 + FLOAT64 = 5 # Beginning of the string indexes, new string indexes should be added between 6 and 9 - INDEX_STRING_ASCII = 6 - INDEX_STRING_UTF8 = 7 - INDEX_STRING_UTF16 = 8 - INDEX_STRING_UTF32 = 9 + STRING_ASCII = 6 + STRING_UTF8 = 7 + STRING_UTF16 = 8 + STRING_UTF32 = 9 # Ending of the string indexes - INDEX_AOB = 10 # Array of Bytes + AOB = 10 # Array of Bytes @staticmethod def is_integer(value_index): - return VALUE_INDEX.INDEX_INT8 <= value_index <= VALUE_INDEX.INDEX_INT64 + return VALUE_INDEX.INT8 <= value_index <= VALUE_INDEX.INT64 @staticmethod def is_string(value_index): - return VALUE_INDEX.INDEX_STRING_ASCII <= value_index <= VALUE_INDEX.INDEX_STRING_UTF32 + return VALUE_INDEX.STRING_ASCII <= value_index <= VALUE_INDEX.STRING_UTF32 @staticmethod def has_length(value_index): - return VALUE_INDEX.INDEX_STRING_ASCII <= value_index <= VALUE_INDEX.INDEX_STRING_UTF32 or \ - value_index == VALUE_INDEX.INDEX_AOB + return VALUE_INDEX.STRING_ASCII <= value_index <= VALUE_INDEX.STRING_UTF32 or value_index == VALUE_INDEX.AOB class SCAN_INDEX: - INDEX_INT_ANY = 0 - INDEX_INT8 = 1 - INDEX_INT16 = 2 - INDEX_INT32 = 3 - INDEX_INT64 = 4 - INDEX_FLOAT_ANY = 5 - INDEX_FLOAT32 = 6 - INDEX_FLOAT64 = 7 - INDEX_ANY = 8 - INDEX_STRING = 9 - INDEX_AOB = 10 # Array of Bytes + INT_ANY = 0 + INT8 = 1 + INT16 = 2 + INT32 = 3 + INT64 = 4 + FLOAT_ANY = 5 + FLOAT32 = 6 + FLOAT64 = 7 + ANY = 8 + STRING = 9 + AOB = 10 # Array of Bytes # GDB already provides breakpoint info in english, no need to make these translatable @@ -214,17 +208,17 @@ class SCAN_INDEX: # Represents the texts at indexes in the address table # TODO: This class is mostly an UI helper, maybe integrate it into the the UI completely in the future? index_to_text_dict = collections.OrderedDict([ - (VALUE_INDEX.INDEX_INT8, "Int8"), - (VALUE_INDEX.INDEX_INT16, "Int16"), - (VALUE_INDEX.INDEX_INT32, "Int32"), - (VALUE_INDEX.INDEX_INT64, "Int64"), - (VALUE_INDEX.INDEX_FLOAT32, "Float32"), - (VALUE_INDEX.INDEX_FLOAT64, "Float64"), - (VALUE_INDEX.INDEX_STRING_ASCII, "String_ASCII"), - (VALUE_INDEX.INDEX_STRING_UTF8, "String_UTF8"), - (VALUE_INDEX.INDEX_STRING_UTF16, "String_UTF16"), - (VALUE_INDEX.INDEX_STRING_UTF32, "String_UTF32"), - (VALUE_INDEX.INDEX_AOB, "ByteArray") + (VALUE_INDEX.INT8, "Int8"), + (VALUE_INDEX.INT16, "Int16"), + (VALUE_INDEX.INT32, "Int32"), + (VALUE_INDEX.INT64, "Int64"), + (VALUE_INDEX.FLOAT32, "Float32"), + (VALUE_INDEX.FLOAT64, "Float64"), + (VALUE_INDEX.STRING_ASCII, "String_ASCII"), + (VALUE_INDEX.STRING_UTF8, "String_UTF8"), + (VALUE_INDEX.STRING_UTF16, "String_UTF16"), + (VALUE_INDEX.STRING_UTF32, "String_UTF32"), + (VALUE_INDEX.AOB, "ByteArray") ]) text_to_index_dict = collections.OrderedDict() @@ -232,53 +226,53 @@ class SCAN_INDEX: text_to_index_dict[index_to_text_dict[key]] = key scanmem_result_to_index_dict = collections.OrderedDict([ - ("I8", VALUE_INDEX.INDEX_INT8), - ("I8u", VALUE_INDEX.INDEX_INT8), - ("I8s", VALUE_INDEX.INDEX_INT8), - ("I16", VALUE_INDEX.INDEX_INT16), - ("I16u", VALUE_INDEX.INDEX_INT16), - ("I16s", VALUE_INDEX.INDEX_INT16), - ("I32", VALUE_INDEX.INDEX_INT32), - ("I32u", VALUE_INDEX.INDEX_INT32), - ("I32s", VALUE_INDEX.INDEX_INT32), - ("I64", VALUE_INDEX.INDEX_INT64), - ("I64u", VALUE_INDEX.INDEX_INT64), - ("I64s", VALUE_INDEX.INDEX_INT64), - ("F32", VALUE_INDEX.INDEX_FLOAT32), - ("F64", VALUE_INDEX.INDEX_FLOAT64), - ("string", VALUE_INDEX.INDEX_STRING_UTF8), - ("bytearray", VALUE_INDEX.INDEX_AOB) + ("I8", VALUE_INDEX.INT8), + ("I8u", VALUE_INDEX.INT8), + ("I8s", VALUE_INDEX.INT8), + ("I16", VALUE_INDEX.INT16), + ("I16u", VALUE_INDEX.INT16), + ("I16s", VALUE_INDEX.INT16), + ("I32", VALUE_INDEX.INT32), + ("I32u", VALUE_INDEX.INT32), + ("I32s", VALUE_INDEX.INT32), + ("I64", VALUE_INDEX.INT64), + ("I64u", VALUE_INDEX.INT64), + ("I64s", VALUE_INDEX.INT64), + ("F32", VALUE_INDEX.FLOAT32), + ("F64", VALUE_INDEX.FLOAT64), + ("string", VALUE_INDEX.STRING_UTF8), + ("bytearray", VALUE_INDEX.AOB) ]) # Represents the texts at indexes in scan combobox # TODO: Same as index_to_text_dict, consider integrating into UI completely scan_index_to_text_dict = collections.OrderedDict([ - (SCAN_INDEX.INDEX_INT_ANY, "Int(any)"), - (SCAN_INDEX.INDEX_INT8, "Int8"), - (SCAN_INDEX.INDEX_INT16, "Int16"), - (SCAN_INDEX.INDEX_INT32, "Int32"), - (SCAN_INDEX.INDEX_INT64, "Int64"), - (SCAN_INDEX.INDEX_FLOAT_ANY, "Float(any)"), - (SCAN_INDEX.INDEX_FLOAT32, "Float32"), - (SCAN_INDEX.INDEX_FLOAT64, "Float64"), - (SCAN_INDEX.INDEX_ANY, "Any(int, float)"), - (SCAN_INDEX.INDEX_STRING, "String"), - (VALUE_INDEX.INDEX_AOB, "ByteArray") + (SCAN_INDEX.INT_ANY, "Int(any)"), + (SCAN_INDEX.INT8, "Int8"), + (SCAN_INDEX.INT16, "Int16"), + (SCAN_INDEX.INT32, "Int32"), + (SCAN_INDEX.INT64, "Int64"), + (SCAN_INDEX.FLOAT_ANY, "Float(any)"), + (SCAN_INDEX.FLOAT32, "Float32"), + (SCAN_INDEX.FLOAT64, "Float64"), + (SCAN_INDEX.ANY, "Any(int, float)"), + (SCAN_INDEX.STRING, "String"), + (VALUE_INDEX.AOB, "ByteArray") ]) # Used in scan_data_type option of scanmem scan_index_to_scanmem_dict = collections.OrderedDict([ - (SCAN_INDEX.INDEX_INT_ANY, "int"), - (SCAN_INDEX.INDEX_INT8, "int8"), - (SCAN_INDEX.INDEX_INT16, "int16"), - (SCAN_INDEX.INDEX_INT32, "int32"), - (SCAN_INDEX.INDEX_INT64, "int64"), - (SCAN_INDEX.INDEX_FLOAT_ANY, "float"), - (SCAN_INDEX.INDEX_FLOAT32, "float32"), - (SCAN_INDEX.INDEX_FLOAT64, "float64"), - (SCAN_INDEX.INDEX_ANY, "number"), - (SCAN_INDEX.INDEX_STRING, "string"), - (VALUE_INDEX.INDEX_AOB, "bytearray") + (SCAN_INDEX.INT_ANY, "int"), + (SCAN_INDEX.INT8, "int8"), + (SCAN_INDEX.INT16, "int16"), + (SCAN_INDEX.INT32, "int32"), + (SCAN_INDEX.INT64, "int64"), + (SCAN_INDEX.FLOAT_ANY, "float"), + (SCAN_INDEX.FLOAT32, "float32"), + (SCAN_INDEX.FLOAT64, "float64"), + (SCAN_INDEX.ANY, "number"), + (SCAN_INDEX.STRING, "string"), + (VALUE_INDEX.AOB, "bytearray") ]) @@ -323,42 +317,42 @@ class ENDIANNESS: BIG = 2 string_index_to_encoding_dict = { - VALUE_INDEX.INDEX_STRING_UTF8: ["utf-8", "surrogateescape"], - VALUE_INDEX.INDEX_STRING_UTF16: ["utf-16", "replace"], - VALUE_INDEX.INDEX_STRING_UTF32: ["utf-32", "replace"], - VALUE_INDEX.INDEX_STRING_ASCII: ["ascii", "replace"], + VALUE_INDEX.STRING_UTF8: ["utf-8", "surrogateescape"], + VALUE_INDEX.STRING_UTF16: ["utf-16", "replace"], + VALUE_INDEX.STRING_UTF32: ["utf-32", "replace"], + VALUE_INDEX.STRING_ASCII: ["ascii", "replace"], } string_index_to_multiplier_dict = { - VALUE_INDEX.INDEX_STRING_UTF8: 2, - VALUE_INDEX.INDEX_STRING_UTF16: 4, - VALUE_INDEX.INDEX_STRING_UTF32: 8, + VALUE_INDEX.STRING_UTF8: 2, + VALUE_INDEX.STRING_UTF16: 4, + VALUE_INDEX.STRING_UTF32: 8, } # first value is the length and the second one is the type # Check gdbutils for an exemplary usage index_to_valuetype_dict = { - VALUE_INDEX.INDEX_INT8: [1, "B"], - VALUE_INDEX.INDEX_INT16: [2, "H"], - VALUE_INDEX.INDEX_INT32: [4, "I"], - VALUE_INDEX.INDEX_INT64: [8, "Q"], - VALUE_INDEX.INDEX_FLOAT32: [4, "f"], - VALUE_INDEX.INDEX_FLOAT64: [8, "d"], - VALUE_INDEX.INDEX_STRING_ASCII: [None, None], - VALUE_INDEX.INDEX_STRING_UTF8: [None, None], - VALUE_INDEX.INDEX_STRING_UTF16: [None, None], - VALUE_INDEX.INDEX_STRING_UTF32: [None, None], - VALUE_INDEX.INDEX_AOB: [None, None] + VALUE_INDEX.INT8: [1, "B"], + VALUE_INDEX.INT16: [2, "H"], + VALUE_INDEX.INT32: [4, "I"], + VALUE_INDEX.INT64: [8, "Q"], + VALUE_INDEX.FLOAT32: [4, "f"], + VALUE_INDEX.FLOAT64: [8, "d"], + VALUE_INDEX.STRING_ASCII: [None, None], + VALUE_INDEX.STRING_UTF8: [None, None], + VALUE_INDEX.STRING_UTF16: [None, None], + VALUE_INDEX.STRING_UTF32: [None, None], + VALUE_INDEX.AOB: [None, None] } # Check gdbutils for an exemplary usage index_to_struct_pack_dict = { - VALUE_INDEX.INDEX_INT8: "B", - VALUE_INDEX.INDEX_INT16: "H", - VALUE_INDEX.INDEX_INT32: "I", - VALUE_INDEX.INDEX_INT64: "Q", - VALUE_INDEX.INDEX_FLOAT32: "f", - VALUE_INDEX.INDEX_FLOAT64: "d" + VALUE_INDEX.INT8: "B", + VALUE_INDEX.INT16: "H", + VALUE_INDEX.INT32: "I", + VALUE_INDEX.INT64: "Q", + VALUE_INDEX.FLOAT32: "f", + VALUE_INDEX.FLOAT64: "d" } # Format: {tag:tag_description} @@ -409,14 +403,14 @@ def __init__(self, value, freeze_type): class ValueType: - def __init__(self, value_index=VALUE_INDEX.INDEX_INT32, length=10, zero_terminate=True, + def __init__(self, value_index=VALUE_INDEX.INT32, length=10, zero_terminate=True, value_repr=VALUE_REPR.UNSIGNED, endian=ENDIANNESS.HOST): """ Args: value_index (int): Determines the type of data. Can be a member of VALUE_INDEX - length (int): Length of the data. Only used when the value_index is INDEX_STRING or INDEX_AOB + length (int): Length of the data. Only used when the value_index is STRING or AOB zero_terminate (bool): If False, ",NZT" will be appended to the text representation - Only used when value_index is INDEX_STRING. Ignored otherwise. "NZT" stands for "Not Zero Terminate" + Only used when value_index is STRING. Ignored otherwise. "NZT" stands for "Non-Zero Terminate" value_repr (int): Determines how the data is represented. Can be a member of VALUE_REPR endian (int): Determines the endianness. Can be a member of ENDIANNESS """ @@ -436,16 +430,16 @@ def text(self): str: A str generated by given parameters Examples: - value_index=VALUE_INDEX.INDEX_STRING_UTF16, length=15, zero_terminate=False--▼ + value_index=VALUE_INDEX.STRING_UTF16, length=15, zero_terminate=False--▼ returned str="String_UTF16[15],NZT" - value_index=VALUE_INDEX.INDEX_AOB, length=42-->returned str="AoB[42]" + value_index=VALUE_INDEX.AOB, length=42-->returned str="AoB[42]" """ returned_string = index_to_text_dict[self.value_index] if VALUE_INDEX.is_string(self.value_index): returned_string += f"[{self.length}]" if not self.zero_terminate: returned_string += ",NZT" - elif self.value_index == VALUE_INDEX.INDEX_AOB: + elif self.value_index == VALUE_INDEX.AOB: returned_string += f"[{self.length}]" if VALUE_INDEX.is_integer(self.value_index): if self.value_repr == VALUE_REPR.SIGNED: diff --git a/libpince/utils.py b/libpince/utils.py index 1a699bbe..4c9344ac 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -302,7 +302,7 @@ def get_ipc_path(pid): Returns: str: Path of IPC directory """ - return typedefs.IPC_PATHS.PINCE_IPC_PATH + str(pid) + return typedefs.PATHS.IPC + str(pid) #:tag:GDBCommunication @@ -315,7 +315,7 @@ def get_tmp_path(pid): Returns: str: Path of tmp directory """ - return typedefs.PATHS.TMP_PATH + str(pid) + return typedefs.PATHS.TMP + str(pid) #:tag:GDBCommunication @@ -531,7 +531,7 @@ def get_referenced_calls_file(pid): #:tag:GDBCommunication -def get_ipc_from_pince_file(pid): +def get_from_pince_file(pid): """Get the path of IPC file sent to custom gdb commands from PINCE for given pid Args: @@ -540,11 +540,11 @@ def get_ipc_from_pince_file(pid): Returns: str: Path of IPC file """ - return get_ipc_path(pid) + typedefs.IPC_PATHS.IPC_FROM_PINCE_PATH + return get_ipc_path(pid) + typedefs.PATHS.FROM_PINCE #:tag:GDBCommunication -def get_ipc_to_pince_file(pid): +def get_to_pince_file(pid): """Get the path of IPC file sent to PINCE from custom gdb commands for given pid Args: @@ -553,7 +553,7 @@ def get_ipc_to_pince_file(pid): Returns: str: Path of IPC file """ - return get_ipc_path(pid) + typedefs.IPC_PATHS.IPC_TO_PINCE_PATH + return get_ipc_path(pid) + typedefs.PATHS.TO_PINCE #:tag:ValueType @@ -565,14 +565,14 @@ def parse_string(string, value_index): value_index (int): Determines the type of data. Can be a member of typedefs.VALUE_INDEX Returns: - str: If the value_index is INDEX_STRING - list: If the value_index is INDEX_AOB. A list of ints is returned - float: If the value_index is INDEX_FLOAT32 or INDEX_FLOAT64 + str: If the value_index is STRING + list: If the value_index is AOB. A list of ints is returned + float: If the value_index is FLOAT32 or FLOAT64 int: If the value_index is anything else None: If the string is not parsable by using the parameter value_index Examples: - string="42 DE AD BE EF 24",value_index=typedefs.VALUE_INDEX.INDEX_AOB--▼ + string="42 DE AD BE EF 24",value_index=typedefs.VALUE_INDEX.AOB--▼ returned_list=[66, 222, 173, 190, 239, 36] """ string = str(string) @@ -587,7 +587,7 @@ def parse_string(string, value_index): if typedefs.VALUE_INDEX.is_string(value_index): return string string = string.strip() - if value_index is typedefs.VALUE_INDEX.INDEX_AOB: + if value_index == typedefs.VALUE_INDEX.AOB: try: string_list = regexes.whitespaces.split(string) for item in string_list: @@ -599,7 +599,7 @@ def parse_string(string, value_index): except: print(string + " can't be parsed as array of bytes") return - elif value_index is typedefs.VALUE_INDEX.INDEX_FLOAT32 or value_index is typedefs.VALUE_INDEX.INDEX_FLOAT64: + elif value_index == typedefs.VALUE_INDEX.FLOAT32 or value_index == typedefs.VALUE_INDEX.FLOAT64: try: string = float(string) except: @@ -618,13 +618,13 @@ def parse_string(string, value_index): except: print(string + " can't be parsed as integer or hexadecimal") return - if value_index is typedefs.VALUE_INDEX.INDEX_INT8: + if value_index == typedefs.VALUE_INDEX.INT8: string = string % 0x100 # 256 - elif value_index is typedefs.VALUE_INDEX.INDEX_INT16: + elif value_index == typedefs.VALUE_INDEX.INT16: string = string % 0x10000 # 65536 - elif value_index is typedefs.VALUE_INDEX.INDEX_INT32: + elif value_index == typedefs.VALUE_INDEX.INT32: string = string % 0x100000000 # 4294967296 - elif value_index is typedefs.VALUE_INDEX.INDEX_INT64: + elif value_index == typedefs.VALUE_INDEX.INT64: string = string % 0x10000000000000000 # 18446744073709551616 return string From 2cf254b2d5b3d83c31998ce88ad8c0d8e1f36f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 31 Dec 2023 19:43:01 +0300 Subject: [PATCH 306/487] Move dissect code and tracer data to tmp --- PINCE.py | 6 ++++++ libpince/gdb_python_scripts/gdbextensions.py | 4 +--- libpince/utils.py | 8 ++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index 9810101c..7199cff5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4484,6 +4484,9 @@ def closeEvent(self, QCloseEvent): self.update_timer.stop() if not self.stopped: debugcore.delete_breakpoint(self.address) + watchpoint_file = utils.get_track_watchpoint_file(debugcore.currentpid, self.breakpoints) + if os.path.exists(watchpoint_file): + os.remove(watchpoint_file) self.deleteLater() instances.remove(self) @@ -4575,6 +4578,9 @@ def closeEvent(self, QCloseEvent): self.update_values_timer.stop() if not self.stopped: debugcore.delete_breakpoint(self.address) + breakpoint_file = utils.get_track_breakpoint_file(debugcore.currentpid, self.breakpoint) + if os.path.exists(breakpoint_file): + os.remove(breakpoint_file) self.parent().refresh_disassemble_view() self.deleteLater() instances.remove(self) diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 7dc86b65..493f0569 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -472,9 +472,7 @@ def invoke(self, arg, from_tty): dissect_code_status_file = utils.get_dissect_code_status_file(pid) region_count = len(region_list) self.memory = open(gdbutils.mem_file, "rb") - - # Has the best record of 111 secs. Tested on Torchlight 2 with Intel i7-4702MQ CPU and 8GB RAM - buffer = 0x10000 # Aligned to 2**16 + buffer = 0x100000 ref_str_count = len(referenced_strings_dict) ref_jmp_count = len(referenced_jumps_dict) ref_call_count = len(referenced_calls_dict) diff --git a/libpince/utils.py b/libpince/utils.py index 4c9344ac..5a560b15 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -383,7 +383,7 @@ def get_trace_instructions_file(pid, breakpoint): Returns: str: Path of trace instructions file """ - return get_ipc_path(pid) + "/" + breakpoint + "_trace.txt" + return get_tmp_path(pid) + "/" + breakpoint + "_trace.txt" #:tag:Utilities @@ -501,7 +501,7 @@ def get_referenced_strings_file(pid): Returns: str: Path of referenced strings dict file """ - return get_ipc_path(pid) + "/referenced_strings_dict.txt" + return get_tmp_path(pid) + "/referenced_strings_dict.txt" #:tag:Tools @@ -514,7 +514,7 @@ def get_referenced_jumps_file(pid): Returns: str: Path of referenced jumps dict file """ - return get_ipc_path(pid) + "/referenced_jumps_dict.txt" + return get_tmp_path(pid) + "/referenced_jumps_dict.txt" #:tag:Tools @@ -527,7 +527,7 @@ def get_referenced_calls_file(pid): Returns: str: Path of referenced calls dict file """ - return get_ipc_path(pid) + "/referenced_calls_dict.txt" + return get_tmp_path(pid) + "/referenced_calls_dict.txt" #:tag:GDBCommunication From b1ace55470166957d2b6bb505cddf8fd0ab1550c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 31 Dec 2023 20:30:32 +0300 Subject: [PATCH 307/487] Add copy to register context menu --- GUI/Labels/RegisterLabel.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GUI/Labels/RegisterLabel.py b/GUI/Labels/RegisterLabel.py index b829b3e2..7451e454 100644 --- a/GUI/Labels/RegisterLabel.py +++ b/GUI/Labels/RegisterLabel.py @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt6.QtWidgets import QLabel, QMenu +from PyQt6.QtWidgets import QLabel, QMenu, QApplication from PyQt6.QtGui import QCursor from PyQt6.QtCore import Qt from libpince import debugcore, typedefs @@ -53,6 +53,8 @@ def contextMenuEvent(self, QContextMenuEvent): if debugcore.currentpid == -1: return menu = QMenu() + copy = menu.addAction(tr.COPY) + menu.addSeparator() show_in_hex_view = menu.addAction(tr.SHOW_HEXVIEW) show_in_disassembler = menu.addAction(tr.SHOW_DISASSEMBLER) font_size = self.font().pointSize() @@ -69,3 +71,5 @@ def contextMenuEvent(self, QContextMenuEvent): if parent.objectName() == "MainWindow_MemoryView": address = self.text().split("=")[-1] parent.disassemble_expression(address) + elif action == copy: + QApplication.instance().clipboard().setText(self.text().split("=")[1]) From 4c0984c97220e15a9a4fcd86f879966a60bafcd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 1 Jan 2024 16:08:01 +0300 Subject: [PATCH 308/487] Prevent debug related errors when process is running --- GUI/Labels/FlagRegisterLabel.py | 2 ++ GUI/Labels/RegisterLabel.py | 4 ++-- PINCE.py | 25 ++++++++++++++----------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/GUI/Labels/FlagRegisterLabel.py b/GUI/Labels/FlagRegisterLabel.py index dca90ac4..4c15aa01 100644 --- a/GUI/Labels/FlagRegisterLabel.py +++ b/GUI/Labels/FlagRegisterLabel.py @@ -46,5 +46,7 @@ def mouseDoubleClickEvent(self, QMouseEvent): label_text = tr.ENTER_FLAG_VALUE.format(self.objectName()) register_dialog = InputDialogForm(item_list=[(label_text, ["0", "1", int(registers[current_flag])])]) if register_dialog.exec(): + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + return debugcore.set_register_flag(current_flag, register_dialog.get_values()) self.set_value(debugcore.read_registers()[current_flag]) diff --git a/GUI/Labels/RegisterLabel.py b/GUI/Labels/RegisterLabel.py index 7451e454..48baa78f 100644 --- a/GUI/Labels/RegisterLabel.py +++ b/GUI/Labels/RegisterLabel.py @@ -46,12 +46,12 @@ def mouseDoubleClickEvent(self, QMouseEvent): register_dialog = InputDialogForm( item_list=[(tr.ENTER_REGISTER_VALUE.format(self.objectName()), registers[current_register])]) if register_dialog.exec(): + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + return debugcore.set_convenience_variable(current_register, register_dialog.get_values()) self.set_value(debugcore.read_registers()[current_register]) def contextMenuEvent(self, QContextMenuEvent): - if debugcore.currentpid == -1: - return menu = QMenu() copy = menu.addAction(tr.COPY) menu.addSeparator() diff --git a/PINCE.py b/PINCE.py index 7199cff5..9e593020 100755 --- a/PINCE.py +++ b/PINCE.py @@ -684,6 +684,8 @@ def break_hotkey_pressed(self): @utils.ignore_exceptions def continue_hotkey_pressed(self): + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + return debugcore.continue_inferior() @utils.ignore_exceptions @@ -2819,28 +2821,25 @@ def show_trace_window(self): TraceInstructionsWindowForm(prompt_dialog=False) def step_instruction(self): - if debugcore.currentpid == -1: - return - if self.updating_memoryview: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or \ + self.updating_memoryview: return debugcore.step_instruction() def step_over_instruction(self): - if debugcore.currentpid == -1: - return - if self.updating_memoryview: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or \ + self.updating_memoryview: return debugcore.step_over_instruction() def execute_till_return(self): - if debugcore.currentpid == -1: - return - if self.updating_memoryview: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or \ + self.updating_memoryview: return debugcore.execute_till_return() def set_address(self): - if debugcore.currentpid == -1: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return selected_row = guiutils.get_current_row(self.tableWidget_Disassemble) current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() @@ -4008,7 +4007,7 @@ def actionlibpince_triggered(self): libpince_widget.showMaximized() def pushButton_ShowFloatRegisters_clicked(self): - if debugcore.currentpid == -1: + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return self.float_registers_widget = FloatRegisterWidgetForm() self.float_registers_widget.show() @@ -4128,6 +4127,8 @@ def update_registers(self): self.tableWidget_XMM.setItem(row, FLOAT_REGISTERS_VALUE_COL, QTableWidgetItem(float_registers[xmm])) def set_register(self, index): + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + return current_row = index.row() if self.currentWidget() == self.FPU: current_table_widget = self.tableWidget_FPU @@ -4140,6 +4141,8 @@ def set_register(self, index): label_text = tr.ENTER_REGISTER_VALUE.format(current_register.upper()) register_dialog = InputDialogForm(item_list=[(label_text, current_value)]) if register_dialog.exec(): + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + return if self.currentWidget() == self.XMM: current_register += ".v4_float" debugcore.set_convenience_variable(current_register, register_dialog.get_values()) From 8cc8ff851da09ccf2d784431366bde3189952f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 1 Jan 2024 16:38:02 +0300 Subject: [PATCH 309/487] Update process status after reattach --- PINCE.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PINCE.py b/PINCE.py index 9e593020..e54aed9c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -695,6 +695,10 @@ def toggle_attach_hotkey_pressed(self): print("Unable to toggle attach") elif result == typedefs.TOGGLE_ATTACH.DETACHED: self.on_status_detached() + else: + # Attaching back doesn't update the status if the process is already stopped before detachment + with debugcore.status_changed_condition: + debugcore.status_changed_condition.notify_all() @utils.ignore_exceptions def nextscan_hotkey_pressed(self, index): From 9b1039cdc31a31a04ca21a9ec1a420d1abd5ac5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 2 Jan 2024 19:06:46 +0300 Subject: [PATCH 310/487] Fix GUI when detached --- PINCE.py | 36 +++++++++++++++++------------------- libpince/debugcore.py | 4 ++++ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/PINCE.py b/PINCE.py index e54aed9c..f7f55901 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2820,8 +2820,6 @@ def initialize_hex_view(self): guiutils.center_scroll_bar(self.verticalScrollBar_HexView) def show_trace_window(self): - if debugcore.currentpid == -1: - return TraceInstructionsWindowForm(prompt_dialog=False) def step_instruction(self): @@ -3423,14 +3421,10 @@ def set_stack_widget(self, stack_widget): self.update_stacktrace() def tableWidget_StackTrace_context_menu_event(self, event): - if debugcore.currentpid == -1: - return - def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_StackTrace.item(row, column).text()) selected_row = guiutils.get_current_row(self.tableWidget_StackTrace) - menu = QMenu() switch_to_stack = menu.addAction(tr.FULL_STACK) menu.addSeparator() @@ -3440,6 +3434,9 @@ def copy_to_clipboard(row, column): if selected_row == -1: guiutils.delete_menu_entries(menu, [clipboard_menu.menuAction()]) refresh = menu.addAction(f"{tr.REFRESH}[R]") + if debugcore.currentpid == -1: + menu.clear() + menu.addMenu(clipboard_menu) font_size = self.tableWidget_StackTrace.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -3496,8 +3493,6 @@ def tableWidget_Stack_context_menu_event(self, event): def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_Stack.item(row, column).text()) - if debugcore.currentpid == -1: - return selected_row = guiutils.get_current_row(self.tableWidget_Stack) if selected_row == -1: current_address = None @@ -3517,6 +3512,9 @@ def copy_to_clipboard(row, column): show_in_hex = menu.addAction(f"{tr.HEXVIEW_VALUE_POINTER}[Ctrl+H]") if selected_row == -1: guiutils.delete_menu_entries(menu, [clipboard_menu.menuAction(), show_in_disas, show_in_hex]) + if debugcore.currentpid == -1: + menu.clear() + menu.addMenu(clipboard_menu) font_size = self.tableWidget_Stack.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -3722,9 +3720,6 @@ def disassemble_go_back(self): self.tableWidget_Disassemble.travel_history.pop() def tableWidget_Disassemble_context_menu_event(self, event): - if debugcore.currentpid == -1: - return - def copy_to_clipboard(row, column): app.clipboard().setText(self.tableWidget_Disassemble.item(row, column).text()) @@ -3780,6 +3775,8 @@ def copy_all_columns(row): menu.addSeparator() refresh = menu.addAction(f"{tr.REFRESH}[R]") menu.addSeparator() + if debugcore.currentpid == -1: + menu.clear() clipboard_menu = menu.addMenu(tr.COPY_CLIPBOARD) copy_address = clipboard_menu.addAction(tr.COPY_ADDRESS) copy_bytes = clipboard_menu.addAction(tr.COPY_BYTES) @@ -3913,8 +3910,6 @@ def delete_bookmark(self, int_address): self.refresh_disassemble_view() def actionBookmarks_triggered(self): - if debugcore.currentpid == -1: - return bookmark_widget = BookmarkWidgetForm(self) bookmark_widget.show() bookmark_widget.activateWindow() @@ -3939,8 +3934,6 @@ def actionFunctions_triggered(self): functions_info_widget.show() def actionGDB_Log_File_triggered(self): - if debugcore.currentpid == -1: - return log_file_widget = LogFileWidgetForm() log_file_widget.showMaximized() @@ -4005,8 +3998,6 @@ def actionDissect_Code_triggered(self): self.refresh_disassemble_view() def actionlibpince_triggered(self): - if debugcore.currentpid == -1: - return libpince_widget = LibpinceReferenceWidgetForm(is_window=True) libpince_widget.showMaximized() @@ -4039,11 +4030,17 @@ def __init__(self, parent=None): def refresh_table(self): self.listWidget.clear() address_list = [hex(address) for address in self.parent().tableWidget_Disassemble.bookmarks.keys()] - self.listWidget.addItems([item.all for item in debugcore.examine_expressions(address_list)]) + if debugcore.currentpid == -1: + self.listWidget.addItems(address_list) + else: + self.listWidget.addItems([item.all for item in debugcore.examine_expressions(address_list)]) def change_display(self, row): current_address = utils.extract_address(self.listWidget.item(row).text()) - self.lineEdit_Info.setText(debugcore.get_address_info(current_address)) + if debugcore.currentpid == -1: + self.lineEdit_Info.clear() + else: + self.lineEdit_Info.setText(debugcore.get_address_info(current_address)) self.lineEdit_Comment.setText(self.parent().tableWidget_Disassemble.bookmarks[int(current_address, 16)]) def listWidget_item_double_clicked(self, item): @@ -4695,6 +4692,7 @@ def __init__(self, address="", prompt_dialog=True, parent=None): self.actionSave.triggered.connect(self.save_file) self.splitter.setStretchFactor(0, 1) if not prompt_dialog: + self.showMaximized() return prompt_dialog = TraceInstructionsPromptDialogForm() if prompt_dialog.exec(): diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 4a631fba..06bad9d9 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -941,6 +941,8 @@ def examine_expression(expression): typedefs.tuple_examine_expression: Evaluated value, address and symbol in a tuple Any erroneous field will be returned as None instead of str """ + if currentpid == -1: + return typedefs.tuple_examine_expression(None, None, None) return send_command("pince-examine-expressions", send_with_file=True, file_contents_send=[expression], recv_with_file=True)[0] @@ -956,6 +958,8 @@ def examine_expressions(expression_list): """ if not expression_list: return [] + if currentpid == -1: + return [typedefs.tuple_examine_expression(None, None, None) for _ in range(len(expression_list))] return send_command("pince-examine-expressions", send_with_file=True, file_contents_send=expression_list, recv_with_file=True) From df66a3e273016beca9f2b466613a210bce09f401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 2 Jan 2024 21:29:48 +0300 Subject: [PATCH 311/487] Use set_pince_paths in init_gdb --- libpince/debugcore.py | 1 + libpince/gdb_python_scripts/gdbextensions.py | 7 +++---- libpince/gdb_python_scripts/gdbutils.py | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 06bad9d9..31505981 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -482,6 +482,7 @@ def init_gdb(gdb_path=typedefs.PATHS.GDB): gdb_initialized = True set_logging(False) send_command("source ./gdbinit_venv") + set_pince_paths() send_command("source " + utils.get_user_path(typedefs.USER_PATHS.GDBINIT)) utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT)) diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 493f0569..5d0a652e 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import gdb, pickle, json, sys, re, struct, ctypes, os, shelve, distorm3 +import gdb, pickle, json, sys, re, struct, ctypes, os, shelve, distorm3, importlib from collections import OrderedDict # This is some retarded hack @@ -26,11 +26,10 @@ from libpince.gdb_python_scripts import gdbutils from libpince import utils, typedefs, regexes -inferior = gdb.selected_inferior() -pid = inferior.pid +importlib.reload(gdbutils) +pid = gdbutils.pid recv_file = utils.get_from_pince_file(pid) send_file = utils.get_to_pince_file(pid) - lib = None # Format of info_list: [count, previous_pc_address, register_info, float_info, disas_info] diff --git a/libpince/gdb_python_scripts/gdbutils.py b/libpince/gdb_python_scripts/gdbutils.py index 61243882..70cf2738 100644 --- a/libpince/gdb_python_scripts/gdbutils.py +++ b/libpince/gdb_python_scripts/gdbutils.py @@ -27,7 +27,11 @@ inferior = gdb.selected_inferior() pid = inferior.pid -inferior_name = utils.get_process_name(pid) +if pid == 0: + pid = -1 + inferior_name = "" +else: + inferior_name = utils.get_process_name(pid) mem_file = "/proc/" + str(pid) + "/mem" void_ptr = gdb.lookup_type("void").pointer() From 4f6a7366bed1816f491ebda33acadcb1e23e62f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 3 Jan 2024 20:28:51 +0300 Subject: [PATCH 312/487] Handle all signals --- CONTRIBUTING.md | 2 +- GUI/HandleSignalsDialog.py | 26 ++++------ GUI/HandleSignalsDialog.ui | 11 ++-- PINCE.py | 102 ++++++++++++++++++++++++------------- i18n/ts/it_IT.ts | 12 ++++- i18n/ts/zh_CN.ts | 14 ++++- libpince/debugcore.py | 22 +++----- 7 files changed, 117 insertions(+), 72 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 751d4ce8..d7614d59 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -183,7 +183,7 @@ These tasks are ordered by importance but feel free to pick any of them. Further - Use type hints(py 3.5) and variable annotations(py 3.6) when support drops for older systems - Arrows for jump instructions based on disassembled output - Flowcharts based on disassembled output -- Consider implementing a GUI for catching signals and syscalls. This is currently done via GDB Console +- Consider implementing a GUI for catchpoints. This is currently done via GDB Console - Implement speedhack - Implement unrandomizer - Implement pointer-scan diff --git a/GUI/HandleSignalsDialog.py b/GUI/HandleSignalsDialog.py index 9cdf3e3f..bfb9294c 100644 --- a/GUI/HandleSignalsDialog.py +++ b/GUI/HandleSignalsDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'HandleSignalsDialog.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,26 +12,28 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(268, 244) + Dialog.resize(363, 523) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") - self.tableWidget_Signals = QtWidgets.QTableWidget(Dialog) + self.tableWidget_Signals = QtWidgets.QTableWidget(parent=Dialog) self.tableWidget_Signals.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Signals.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Signals.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_Signals.setObjectName("tableWidget_Signals") - self.tableWidget_Signals.setColumnCount(2) + self.tableWidget_Signals.setColumnCount(3) self.tableWidget_Signals.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.tableWidget_Signals.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() self.tableWidget_Signals.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Signals.setHorizontalHeaderItem(2, item) self.tableWidget_Signals.horizontalHeader().setStretchLastSection(True) self.tableWidget_Signals.verticalHeader().setVisible(False) self.tableWidget_Signals.verticalHeader().setDefaultSectionSize(16) self.tableWidget_Signals.verticalHeader().setMinimumSectionSize(16) self.gridLayout.addWidget(self.tableWidget_Signals, 0, 0, 1, 1) - self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") @@ -48,14 +50,6 @@ def retranslateUi(self, Dialog): item = self.tableWidget_Signals.horizontalHeaderItem(0) item.setText(_translate("Dialog", "Signal")) item = self.tableWidget_Signals.horizontalHeaderItem(1) - item.setText(_translate("Dialog", "Ignore")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - Dialog = QtWidgets.QDialog() - ui = Ui_Dialog() - ui.setupUi(Dialog) - Dialog.show() - sys.exit(app.exec()) + item.setText(_translate("Dialog", "Stop & Print")) + item = self.tableWidget_Signals.horizontalHeaderItem(2) + item.setText(_translate("Dialog", "Pass to Program")) diff --git a/GUI/HandleSignalsDialog.ui b/GUI/HandleSignalsDialog.ui index 9a39bc0c..a07fb787 100644 --- a/GUI/HandleSignalsDialog.ui +++ b/GUI/HandleSignalsDialog.ui @@ -6,8 +6,8 @@ 0 0 - 268 - 244 + 363 + 523 @@ -44,7 +44,12 @@ - Ignore + Stop & Print + + + + + Pass to Program diff --git a/PINCE.py b/PINCE.py index f7f55901..df4a4ab2 100755 --- a/PINCE.py +++ b/PINCE.py @@ -37,7 +37,7 @@ QLocale from typing import Final from time import sleep, time -import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect +import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect, json from libpince import utils, debugcore, typedefs from libpince.libscanmem.scanmem import Scanmem @@ -130,7 +130,7 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "27" # Increase version by one if you change settings +current_settings_version = "28" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -201,8 +201,27 @@ def get_hotkeys(): gdb_path = str gdb_logging = bool -ignored_signals = str -signal_list = ["SIGUSR1", "SIGPWR", "SIGXCPU", "SIGSEGV"] +handle_signals = str +# Due to community feedback, these signals are disabled by default: SIGUSR1, SIGUSR2, SIGPWR, SIGXCPU, SIGXFSZ, SIGSYS +# Rest is the same with GDB defaults +default_signals = [ + ["SIGHUP", True, True], ["SIGINT", True, False], ["SIGQUIT", True, True], ["SIGILL", True, True], + ["SIGTRAP", True, False], ["SIGABRT", True, True], ["SIGEMT", True, True], ["SIGFPE", True, True], + ["SIGKILL", True, True], ["SIGBUS", True, True], ["SIGSEGV", True, True], ["SIGSYS", False, True], + ["SIGPIPE", True, True], ["SIGALRM", False, True], ["SIGTERM", True, True], ["SIGURG", False, True], + ["SIGSTOP", True, True], ["SIGTSTP", True, True], ["SIGCONT", True, True], ["SIGCHLD", False, True], + ["SIGTTIN", True, True], ["SIGTTOU", True, True], ["SIGIO", False, True], ["SIGXCPU", False, True], + ["SIGXFSZ", False, True], ["SIGVTALRM", False, True], ["SIGPROF", False, True], ["SIGWINCH", False, True], + ["SIGLOST", True, True], ["SIGUSR1", False, True], ["SIGUSR2", False, True], ["SIGPWR", False, True], + ["SIGPOLL", False, True], ["SIGWIND", True, True], ["SIGPHONE", True, True], ["SIGWAITING", False, True], + ["SIGLWP", False, True], ["SIGDANGER", True, True], ["SIGGRANT", True, True], ["SIGRETRACT", True, True], + ["SIGMSG", True, True], ["SIGSOUND", True, True], ["SIGSAK", True, True], ["SIGPRIO", False, True], + ["SIGCANCEL", False, True], ["SIGINFO", True, True], ["EXC_BAD_ACCESS", True, True], + ["EXC_BAD_INSTRUCTION", True, True], ["EXC_ARITHMETIC", True, True], ["EXC_EMULATION", True, True], + ["EXC_SOFTWARE", True, True], ["EXC_BREAKPOINT", True, True], ["SIGLIBRT", False, True] +] +for x in range(33, 128): # Add signals SIG33-SIG127 + default_signals.append([f"SIG{x}", True, True]) # represents the index of columns in instructions restore table INSTR_ADDR_COL = 0 @@ -584,7 +603,7 @@ def set_default_settings(self): self.settings.beginGroup("Debug") self.settings.setValue("gdb_path", typedefs.PATHS.GDB) self.settings.setValue("gdb_logging", False) - self.settings.setValue("ignored_signals", "1,1,1,0") + self.settings.setValue("handle_signals", json.dumps(default_signals)) self.settings.endGroup() self.settings.beginGroup("Misc") self.settings.setValue("version", current_settings_version) @@ -593,18 +612,15 @@ def set_default_settings(self): def apply_after_init(self): global gdb_logging - global ignored_signals + global handle_signals global exp_cache exp_cache.clear() gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) - ignored_signals = self.settings.value("Debug/ignored_signals", type=str) + handle_signals = self.settings.value("Debug/handle_signals", type=str) debugcore.set_logging(gdb_logging) - for index, ignore_status in enumerate(ignored_signals.split(",")): - if ignore_status == "1": - debugcore.ignore_signal(signal_list[index]) - else: - debugcore.unignore_signal(signal_list[index]) + for signal, stop, pass_to_program in json.loads(handle_signals): + debugcore.handle_signal(signal, stop, pass_to_program) def apply_settings(self): global update_table @@ -2254,7 +2270,7 @@ def __init__(self, set_default_settings_func, parent=None): self.settings = QSettings() self.set_default_settings = set_default_settings_func self.hotkey_to_value = {} # Dict[str:str]-->Dict[Hotkey.name:settings_value] - self.handle_signals_data = None + self.handle_signals_data = "" self.listWidget_Options.currentRowChanged.connect(self.change_display) icons_directory = guiutils.get_icons_directory() self.pushButton_GDBPath.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) @@ -2340,8 +2356,8 @@ def accept(self): debugcore.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) - if self.handle_signals_data is not None: - self.settings.setValue("Debug/ignored_signals", ",".join(self.handle_signals_data)) + if self.handle_signals_data: + self.settings.setValue("Debug/handle_signals", self.handle_signals_data) super().accept() def reject(self): @@ -2424,7 +2440,7 @@ def pushButton_ResetSettings_clicked(self): confirm_dialog = InputDialogForm(item_list=[(tr.RESET_DEFAULT_SETTINGS,)]) if confirm_dialog.exec(): self.set_default_settings() - self.handle_signals_data = None + self.handle_signals_data = "" self.config_gui() def checkBox_AutoUpdateAddressTable_state_changed(self): @@ -2455,8 +2471,8 @@ def pushButton_GDBPath_clicked(self): self.lineEdit_GDBPath.setText(file_path) def pushButton_HandleSignals_clicked(self): - if self.handle_signals_data is None: - self.handle_signals_data = self.settings.value("Debug/ignored_signals", type=str).split(",") + if not self.handle_signals_data: + self.handle_signals_data = self.settings.value("Debug/handle_signals", type=str) signal_dialog = HandleSignalsDialogForm(self.handle_signals_data) if signal_dialog.exec(): self.handle_signals_data = signal_dialog.get_values() @@ -2466,31 +2482,47 @@ class HandleSignalsDialogForm(QDialog, HandleSignalsDialog): def __init__(self, signal_data, parent=None): super().__init__(parent=parent) self.setupUi(self) - self.tableWidget_Signals.setRowCount(len(signal_list)) - for index, state in enumerate(signal_data): - self.tableWidget_Signals.setItem(index, 0, QTableWidgetItem(signal_list[index])) - widget = QWidget() - checkbox = QCheckBox() - layout = QHBoxLayout(widget) - layout.addWidget(checkbox) - layout.setAlignment(Qt.AlignmentFlag.AlignCenter) - layout.setContentsMargins(0, 0, 0, 0) + self.signal_data = json.loads(signal_data) + self.tableWidget_Signals.setRowCount(len(self.signal_data)) + for index, (signal, stop, pass_to_program) in enumerate(self.signal_data): + self.tableWidget_Signals.setItem(index, 0, QTableWidgetItem(signal)) + widget, checkbox = self.create_checkbox_widget() self.tableWidget_Signals.setCellWidget(index, 1, widget) - if state == "1": + if stop: checkbox.setCheckState(Qt.CheckState.Checked) else: checkbox.setCheckState(Qt.CheckState.Unchecked) + widget, checkbox = self.create_checkbox_widget() + self.tableWidget_Signals.setCellWidget(index, 2, widget) + if pass_to_program: + checkbox.setCheckState(Qt.CheckState.Checked) + else: + checkbox.setCheckState(Qt.CheckState.Unchecked) + self.tableWidget_Signals.resizeColumnsToContents() + + + def create_checkbox_widget(self): + widget = QWidget() + checkbox = QCheckBox() + layout = QHBoxLayout(widget) + layout.addWidget(checkbox) + layout.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.setContentsMargins(0, 0, 0, 0) + return widget, checkbox def get_values(self): - final_state = [] - for index in range(len(signal_list)): + signal_data = [] + for index in range(len(self.signal_data)): + current_signal = [] + current_signal.append(self.signal_data[index][0]) widget = self.tableWidget_Signals.cellWidget(index, 1) checkbox = widget.findChild(QCheckBox) - if checkbox.checkState() == Qt.CheckState.Checked: - final_state.append("1") - else: - final_state.append("0") - return final_state + current_signal.append(True if checkbox.checkState() == Qt.CheckState.Checked else False) + widget = self.tableWidget_Signals.cellWidget(index, 2) + checkbox = widget.findChild(QCheckBox) + current_signal.append(True if checkbox.checkState() == Qt.CheckState.Checked else False) + signal_data.append(current_signal) + return json.dumps(signal_data) class ConsoleWidgetForm(QWidget, ConsoleWidget): diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 3a6ccb07..81ea11aa 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -170,7 +170,12 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin - Ignore + Stop & Print + + + + + Pass to Program @@ -290,6 +295,11 @@ Patterns at former positions have higher priority if regex is off Logo + + + Theme + + Functions diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index df9175ea..d5d3e07f 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -171,8 +171,13 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin - Ignore - 忽略 + Stop & Print + + + + + Pass to Program + @@ -292,6 +297,11 @@ Patterns at former positions have higher priority if regex is off Logo 图标 + + + Theme + + Functions diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 31505981..c5f73292 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -420,23 +420,17 @@ def execute_till_return(): #:tag:Debug -def ignore_signal(signal_name): - """Ignores the given signal +def handle_signal(signal_name, stop, pass_to_program): + """Decides on what will GDB do when the process recieves a signal Args: - signal_name (str): Name of the ignored signal + signal_name (str): Name of the signal + stop (bool): Stop the program and print to the console + pass_to_program (bool): Pass signal to program """ - send_command("handle " + signal_name + " nostop noprint") - - -#:tag:Debug -def unignore_signal(signal_name): - """Unignores the given signal - - Args: - signal_name (str): Name of the unignored signal - """ - send_command("handle " + signal_name + " stop print") + stop = "stop print" if stop else "nostop noprint" + pass_to_program = "pass" if pass_to_program else "nopass" + send_command(f"handle {signal_name} {stop} {pass_to_program}") #:tag:GDBCommunication From 1029f4828b2e8fe2624d6a5a73a53b991c0d7338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 4 Jan 2024 13:18:02 +0300 Subject: [PATCH 313/487] Optimize handle_signals --- PINCE.py | 3 +-- libpince/debugcore.py | 14 +++++++++++--- libpince/gdb_python_scripts/gdbextensions.py | 13 +++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index df4a4ab2..8771e4bd 100755 --- a/PINCE.py +++ b/PINCE.py @@ -619,8 +619,7 @@ def apply_after_init(self): gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) handle_signals = self.settings.value("Debug/handle_signals", type=str) debugcore.set_logging(gdb_logging) - for signal, stop, pass_to_program in json.loads(handle_signals): - debugcore.handle_signal(signal, stop, pass_to_program) + debugcore.handle_signals(handle_signals) def apply_settings(self): global update_table diff --git a/libpince/debugcore.py b/libpince/debugcore.py index c5f73292..6d03628b 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -428,9 +428,17 @@ def handle_signal(signal_name, stop, pass_to_program): stop (bool): Stop the program and print to the console pass_to_program (bool): Pass signal to program """ - stop = "stop print" if stop else "nostop noprint" - pass_to_program = "pass" if pass_to_program else "nopass" - send_command(f"handle {signal_name} {stop} {pass_to_program}") + send_command("pince-handle-signals", send_with_file=True, file_contents_send=[signal_name, stop, pass_to_program]) + + +#:tag:Debug +def handle_signals(signal_list): + """Optimized version of handle_signal for multiple signals + + Args: + signal_list (list): A list of the parameters of handle_signal + """ + send_command("pince-handle-signals", send_with_file=True, file_contents_send=signal_list) #:tag:GDBCommunication diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 5d0a652e..dce1a6ca 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -79,6 +79,18 @@ def invoke(self, arg, from_tty): send_to_pince(contents_send) +class HandleSignals(gdb.Command): + def __init__(self): + super().__init__("pince-handle-signals", gdb.COMMAND_USER) + + def invoke(self, arg, from_tty): + signal_data = receive_from_pince() + for signal, stop, pass_to_program in json.loads(signal_data): + stop = "stop print" if stop else "nostop noprint" + pass_to_program = "pass" if pass_to_program else "nopass" + gdb.execute(f"handle {signal} {stop} {pass_to_program}", from_tty, to_string=True) + + class ParseAndEval(gdb.Command): def __init__(self): super(ParseAndEval, self).__init__("pince-parse-and-eval", gdb.COMMAND_USER) @@ -627,6 +639,7 @@ def invoke(self, arg, from_tty): IgnoreErrors() CLIOutput() +HandleSignals() ParseAndEval() ReadRegisters() ReadFloatRegisters() From 9d539c39f21e19622e3a722ffdfaca15f90e8ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 4 Jan 2024 16:57:39 +0300 Subject: [PATCH 314/487] Implement interrupt_signal --- GUI/SettingsDialog.py | 60 ++++++++++++++++++++++++++----------------- GUI/SettingsDialog.ui | 27 +++++++++++++++++++ PINCE.py | 18 ++++++++++--- i18n/ts/it_IT.ts | 5 ++++ i18n/ts/zh_CN.ts | 5 ++++ libpince/debugcore.py | 29 +++++++++++++++++++-- 6 files changed, 115 insertions(+), 29 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index a18234fd..e6070c19 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -172,11 +172,11 @@ def setupUi(self, Dialog): self.comboBox_Theme = QtWidgets.QComboBox(parent=self.page) self.comboBox_Theme.setObjectName("comboBox_Theme") self.horizontalLayout_17.addWidget(self.comboBox_Theme) - spacerItem15 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_17.addItem(spacerItem15) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_17.addItem(spacerItem4) self.verticalLayout_5.addLayout(self.horizontalLayout_17) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_5.addItem(spacerItem4) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_5.addItem(spacerItem5) self.gridLayout_2.addLayout(self.verticalLayout_5, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page) self.page_2 = QtWidgets.QWidget() @@ -207,14 +207,14 @@ def setupUi(self, Dialog): self.verticalLayout_6.addLayout(self.verticalLayout_Hotkey) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") - spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem5) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem6) self.pushButton_ClearHotkey = QtWidgets.QPushButton(parent=self.page_2) self.pushButton_ClearHotkey.setObjectName("pushButton_ClearHotkey") self.horizontalLayout_4.addWidget(self.pushButton_ClearHotkey) self.verticalLayout_6.addLayout(self.horizontalLayout_4) - spacerItem6 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_6.addItem(spacerItem6) + spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_6.addItem(spacerItem7) self.horizontalLayout_5.addLayout(self.verticalLayout_6) self.gridLayout_3.addLayout(self.horizontalLayout_5, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_2) @@ -233,8 +233,8 @@ def setupUi(self, Dialog): self.verticalLayout_8.addWidget(self.label_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") - spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_6.addItem(spacerItem7) + spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_6.addItem(spacerItem8) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setObjectName("verticalLayout_7") self.radioButton_SimpleDLopenCall = QtWidgets.QRadioButton(parent=self.page_3) @@ -248,11 +248,11 @@ def setupUi(self, Dialog): self.horizontalLayout_6.addLayout(self.verticalLayout_7) self.verticalLayout_8.addLayout(self.horizontalLayout_6) self.horizontalLayout_8.addLayout(self.verticalLayout_8) - spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_8.addItem(spacerItem8) + spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_8.addItem(spacerItem9) self.verticalLayout_9.addLayout(self.horizontalLayout_8) - spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_9.addItem(spacerItem9) + spacerItem10 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_9.addItem(spacerItem10) self.gridLayout_4.addLayout(self.verticalLayout_9, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_3) self.page_4 = QtWidgets.QWidget() @@ -276,11 +276,11 @@ def setupUi(self, Dialog): self.lineEdit_InstructionsPerScroll.setObjectName("lineEdit_InstructionsPerScroll") self.horizontalLayout_9.addWidget(self.lineEdit_InstructionsPerScroll) self.horizontalLayout_10.addLayout(self.horizontalLayout_9) - spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_10.addItem(spacerItem10) + spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_10.addItem(spacerItem11) self.verticalLayout_10.addLayout(self.horizontalLayout_10) - spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_10.addItem(spacerItem11) + spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_10.addItem(spacerItem12) self.gridLayout_5.addLayout(self.verticalLayout_10, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_4) self.page_5 = QtWidgets.QWidget() @@ -308,16 +308,27 @@ def setupUi(self, Dialog): self.checkBox_GDBLogging = QtWidgets.QCheckBox(parent=self.page_5) self.checkBox_GDBLogging.setObjectName("checkBox_GDBLogging") self.verticalLayout_11.addWidget(self.checkBox_GDBLogging) + self.horizontalLayout_18 = QtWidgets.QHBoxLayout() + self.horizontalLayout_18.setObjectName("horizontalLayout_18") + self.label_15 = QtWidgets.QLabel(parent=self.page_5) + self.label_15.setObjectName("label_15") + self.horizontalLayout_18.addWidget(self.label_15) + self.comboBox_InterruptSignal = QtWidgets.QComboBox(parent=self.page_5) + self.comboBox_InterruptSignal.setObjectName("comboBox_InterruptSignal") + self.horizontalLayout_18.addWidget(self.comboBox_InterruptSignal) + spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_18.addItem(spacerItem13) + self.verticalLayout_11.addLayout(self.horizontalLayout_18) self.horizontalLayout_16 = QtWidgets.QHBoxLayout() self.horizontalLayout_16.setObjectName("horizontalLayout_16") self.pushButton_HandleSignals = QtWidgets.QPushButton(parent=self.page_5) self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) - spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_16.addItem(spacerItem12) + spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_16.addItem(spacerItem14) self.verticalLayout_11.addLayout(self.horizontalLayout_16) - spacerItem13 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_11.addItem(spacerItem13) + spacerItem15 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_11.addItem(spacerItem15) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) self.horizontalLayout_2.addWidget(self.stackedWidget) @@ -327,8 +338,8 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(parent=Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem14) + spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem16) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -384,5 +395,6 @@ def retranslateUi(self, Dialog): self.label_6.setText(_translate("Dialog", "Instructions shown per scroll")) self.label_7.setText(_translate("Dialog", "GDB Path")) self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) + self.label_15.setText(_translate("Dialog", "Interruption signal")) self.pushButton_HandleSignals.setText(_translate("Dialog", "Handle Signals")) self.pushButton_ResetSettings.setText(_translate("Dialog", "Reset Settings")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 6502dd4f..3caa0df9 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -651,6 +651,33 @@ Patterns at former positions have higher priority if regex is off + + + + + + Interruption signal + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/PINCE.py b/PINCE.py index 8771e4bd..c93c47ec 100755 --- a/PINCE.py +++ b/PINCE.py @@ -130,7 +130,7 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "28" # Increase version by one if you change settings +current_settings_version = "29" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -200,8 +200,9 @@ def get_hotkeys(): instructions_per_scroll = int gdb_path = str gdb_logging = bool - +interrupt_signal = str handle_signals = str + # Due to community feedback, these signals are disabled by default: SIGUSR1, SIGUSR2, SIGPWR, SIGXCPU, SIGXFSZ, SIGSYS # Rest is the same with GDB defaults default_signals = [ @@ -220,7 +221,7 @@ def get_hotkeys(): ["EXC_BAD_INSTRUCTION", True, True], ["EXC_ARITHMETIC", True, True], ["EXC_EMULATION", True, True], ["EXC_SOFTWARE", True, True], ["EXC_BREAKPOINT", True, True], ["SIGLIBRT", False, True] ] -for x in range(33, 128): # Add signals SIG33-SIG127 +for x in range(32, 128): # Add signals SIG32-SIG127 default_signals.append([f"SIG{x}", True, True]) # represents the index of columns in instructions restore table @@ -603,6 +604,7 @@ def set_default_settings(self): self.settings.beginGroup("Debug") self.settings.setValue("gdb_path", typedefs.PATHS.GDB) self.settings.setValue("gdb_logging", False) + self.settings.setValue("interrupt_signal", "SIGINT") self.settings.setValue("handle_signals", json.dumps(default_signals)) self.settings.endGroup() self.settings.beginGroup("Misc") @@ -612,14 +614,17 @@ def set_default_settings(self): def apply_after_init(self): global gdb_logging + global interrupt_signal global handle_signals global exp_cache exp_cache.clear() gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) + interrupt_signal = self.settings.value("Debug/interrupt_signal", type=str) handle_signals = self.settings.value("Debug/handle_signals", type=str) debugcore.set_logging(gdb_logging) debugcore.handle_signals(handle_signals) + debugcore.set_interrupt_signal(interrupt_signal) # Needs to be called after handle_signals def apply_settings(self): global update_table @@ -2355,6 +2360,7 @@ def accept(self): debugcore.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) + self.settings.setValue("Debug/interrupt_signal", self.comboBox_InterruptSignal.currentText()) if self.handle_signals_data: self.settings.setValue("Debug/handle_signals", self.handle_signals_data) super().accept() @@ -2415,6 +2421,12 @@ def config_gui(self): str(self.settings.value("Disassemble/instructions_per_scroll", type=int))) self.lineEdit_GDBPath.setText(str(self.settings.value("Debug/gdb_path", type=str))) self.checkBox_GDBLogging.setChecked(self.settings.value("Debug/gdb_logging", type=bool)) + cur_signal = self.settings.value("Debug/interrupt_signal", type=str) + self.comboBox_InterruptSignal.clear() + self.comboBox_InterruptSignal.addItem("SIGINT") + self.comboBox_InterruptSignal.addItems([f"SIG{x}" for x in range(signal.SIGRTMIN, signal.SIGRTMAX+1)]) + self.comboBox_InterruptSignal.setCurrentIndex(self.comboBox_InterruptSignal.findText(cur_signal)) + self.comboBox_InterruptSignal.setStyleSheet("combobox-popup: 0;") # maxVisibleItems doesn't work otherwise def change_display(self, index): self.stackedWidget.setCurrentIndex(index) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 81ea11aa..79c9df46 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -350,6 +350,11 @@ Patterns at former positions have higher priority if regex is off GDB Logging + + + Interruption signal + + Reset Settings diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index d5d3e07f..13eec778 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -352,6 +352,11 @@ Patterns at former positions have higher priority if regex is off GDB Logging GDB 日志记录 + + + Interruption signal + + Reset Settings diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 6d03628b..4f30d3f4 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -129,6 +129,11 @@ # A string. memory file of the currently attached/created process mem_file = "/proc/" + str(currentpid) + "/mem" +#:tag:Debug +#:doc: +# A string. Determines which signal to use to interrupt the process +interrupt_signal = "SIGINT" + ''' When PINCE was first launched, it used gdb 7.7.1, which is a very outdated version of gdb interpreter-exec mi command of gdb showed some buggy behaviour at that time @@ -388,7 +393,14 @@ def interrupt_inferior(interrupt_reason=typedefs.STOP_REASON.DEBUG): if currentpid == -1: return global stop_reason - send_command("interrupt") + if interrupt_signal == "SIGINT": + send_command("interrupt") + elif inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + sig_num = interrupt_signal[3:] + if sig_num.isnumeric(): + os.system(f"kill -{sig_num} {currentpid}") + else: + os.system(f"kill -s {interrupt_signal} {currentpid}") wait_for_stop() stop_reason = interrupt_reason @@ -419,6 +431,18 @@ def execute_till_return(): send_command("finish&") +#:tag:Debug +def set_interrupt_signal(signal_name): + """Decides on what signal to use to stop the process + + Args: + signal_name (str): Name of the signal + """ + global interrupt_signal + handle_signal(signal_name, True, False) + interrupt_signal = signal_name + + #:tag:Debug def handle_signal(signal_name, stop, pass_to_program): """Decides on what will GDB do when the process recieves a signal @@ -428,7 +452,8 @@ def handle_signal(signal_name, stop, pass_to_program): stop (bool): Stop the program and print to the console pass_to_program (bool): Pass signal to program """ - send_command("pince-handle-signals", send_with_file=True, file_contents_send=[signal_name, stop, pass_to_program]) + params = json.dumps([[signal_name, stop, pass_to_program]]) + send_command("pince-handle-signals", send_with_file=True, file_contents_send=params) #:tag:Debug From 0906e66a107afc99f509a574fc5dece14cb515cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 6 Jan 2024 15:12:00 +0300 Subject: [PATCH 315/487] Replace python objects in settings with json-compatible ones --- PINCE.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/PINCE.py b/PINCE.py index c93c47ec..a3a3f1c6 100755 --- a/PINCE.py +++ b/PINCE.py @@ -130,7 +130,7 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "29" # Increase version by one if you change settings +current_settings_version = "30" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -578,12 +578,14 @@ def __init__(self): self.flashAttachButtonTimer.start(100) self.auto_attach() + # Please refrain from using python specific objects in settings, use json-compatible ones instead + # Using python objects causes issues when filenames change def set_default_settings(self): self.settings.beginGroup("General") self.settings.setValue("auto_update_address_table", True) self.settings.setValue("address_table_update_interval", 500) self.settings.setValue("freeze_interval", 100) - self.settings.setValue("gdb_output_mode", typedefs.gdb_output_mode(True, True, True)) + self.settings.setValue("gdb_output_mode", json.dumps([True, True, True])) self.settings.setValue("auto_attach_list", "") self.settings.setValue("auto_attach_regex", False) self.settings.setValue("locale", get_locale()) @@ -644,7 +646,8 @@ def apply_settings(self): update_table = self.settings.value("General/auto_update_address_table", type=bool) table_update_interval = self.settings.value("General/address_table_update_interval", type=int) freeze_interval = self.settings.value("General/freeze_interval", type=int) - gdb_output_mode = self.settings.value("General/gdb_output_mode", type=tuple) + gdb_output_mode = json.loads(self.settings.value("General/gdb_output_mode", type=str)) + gdb_output_mode = typedefs.gdb_output_mode(*gdb_output_mode) auto_attach_list = self.settings.value("General/auto_attach_list", type=str) auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) locale = self.settings.value("General/locale", type=str) @@ -2325,10 +2328,9 @@ def accept(self): if self.checkBox_AutoUpdateAddressTable.isChecked(): self.settings.setValue("General/address_table_update_interval", current_table_update_interval) self.settings.setValue("General/freeze_interval", current_freeze_interval) - current_gdb_output_mode = typedefs.gdb_output_mode(self.checkBox_OutputModeAsync.isChecked(), - self.checkBox_OutputModeCommand.isChecked(), - self.checkBox_OutputModeCommandInfo.isChecked()) - self.settings.setValue("General/gdb_output_mode", current_gdb_output_mode) + output_mode = [self.checkBox_OutputModeAsync.isChecked(), self.checkBox_OutputModeCommand.isChecked(), + self.checkBox_OutputModeCommandInfo.isChecked()] + self.settings.setValue("General/gdb_output_mode", json.dumps(output_mode)) if self.checkBox_AutoAttachRegex.isChecked(): try: re.compile(self.lineEdit_AutoAttachList.text()) @@ -2378,9 +2380,11 @@ def config_gui(self): self.lineEdit_UpdateInterval.setText( str(self.settings.value("General/address_table_update_interval", type=int))) self.lineEdit_FreezeInterval.setText(str(self.settings.value("General/freeze_interval", type=int))) - self.checkBox_OutputModeAsync.setChecked(self.settings.value("General/gdb_output_mode").async_output) - self.checkBox_OutputModeCommand.setChecked(self.settings.value("General/gdb_output_mode").command_output) - self.checkBox_OutputModeCommandInfo.setChecked(self.settings.value("General/gdb_output_mode").command_info) + output_mode = json.loads(self.settings.value("General/gdb_output_mode", type=str)) + output_mode = typedefs.gdb_output_mode(*output_mode) + self.checkBox_OutputModeAsync.setChecked(output_mode.async_output) + self.checkBox_OutputModeCommand.setChecked(output_mode.command_output) + self.checkBox_OutputModeCommandInfo.setChecked(output_mode.command_info) self.lineEdit_AutoAttachList.setText(self.settings.value("General/auto_attach_list", type=str)) self.checkBox_AutoAttachRegex.setChecked(self.settings.value("General/auto_attach_regex", type=bool)) self.comboBox_Language.clear() From 19e87b0f6ae8a9d26991522ca158b0d3024dd69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 6 Jan 2024 15:28:23 +0300 Subject: [PATCH 316/487] Fix handle_signals design --- PINCE.py | 4 ++-- libpince/debugcore.py | 2 +- libpince/gdb_python_scripts/gdbextensions.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index a3a3f1c6..d9180341 100755 --- a/PINCE.py +++ b/PINCE.py @@ -201,7 +201,7 @@ def get_hotkeys(): gdb_path = str gdb_logging = bool interrupt_signal = str -handle_signals = str +handle_signals = list # Due to community feedback, these signals are disabled by default: SIGUSR1, SIGUSR2, SIGPWR, SIGXCPU, SIGXFSZ, SIGSYS # Rest is the same with GDB defaults @@ -623,7 +623,7 @@ def apply_after_init(self): exp_cache.clear() gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) interrupt_signal = self.settings.value("Debug/interrupt_signal", type=str) - handle_signals = self.settings.value("Debug/handle_signals", type=str) + handle_signals = json.loads(self.settings.value("Debug/handle_signals", type=str)) debugcore.set_logging(gdb_logging) debugcore.handle_signals(handle_signals) debugcore.set_interrupt_signal(interrupt_signal) # Needs to be called after handle_signals diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 4f30d3f4..32e135f6 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -452,7 +452,7 @@ def handle_signal(signal_name, stop, pass_to_program): stop (bool): Stop the program and print to the console pass_to_program (bool): Pass signal to program """ - params = json.dumps([[signal_name, stop, pass_to_program]]) + params = [[signal_name, stop, pass_to_program]] send_command("pince-handle-signals", send_with_file=True, file_contents_send=params) diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index dce1a6ca..089e57a0 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -85,7 +85,7 @@ def __init__(self): def invoke(self, arg, from_tty): signal_data = receive_from_pince() - for signal, stop, pass_to_program in json.loads(signal_data): + for signal, stop, pass_to_program in signal_data: stop = "stop print" if stop else "nostop noprint" pass_to_program = "pass" if pass_to_program else "nopass" gdb.execute(f"handle {signal} {stop} {pass_to_program}", from_tty, to_string=True) From 060eed7df25e858d6214154348d3b9d9564f2fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 7 Jan 2024 18:00:24 +0300 Subject: [PATCH 317/487] Implement automatic update for HexView --- GUI/AbstractTableModels/AsciiModel.py | 12 ++++++------ GUI/AbstractTableModels/HexModel.py | 28 +++++++++++++++++++++------ PINCE.py | 26 +++++++++++++++---------- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/GUI/AbstractTableModels/AsciiModel.py b/GUI/AbstractTableModels/AsciiModel.py index 0b47b923..9aef7493 100644 --- a/GUI/AbstractTableModels/AsciiModel.py +++ b/GUI/AbstractTableModels/AsciiModel.py @@ -15,13 +15,10 @@ along with this program. If not, see . """ from PyQt6.QtCore import QVariant, Qt -from PyQt6.QtGui import QColor, QColorConstants from GUI.AbstractTableModels.HexModel import QHexModel from libpince import utils, debugcore -breakpoint_red = QColor(QColorConstants.Red) -breakpoint_red.setAlpha(96) class QAsciiModel(QHexModel): def __init__(self, row_count, column_count, parent=None): @@ -29,10 +26,13 @@ def __init__(self, row_count, column_count, parent=None): def data(self, QModelIndex, int_role=None): if self.data_array and QModelIndex.isValid(): + index = QModelIndex.row() * self.column_count + QModelIndex.column() if int_role == Qt.ItemDataRole.BackgroundRole: - address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() + address = self.current_address + index if utils.modulo_address(address, debugcore.inferior_arch) in self.breakpoint_list: - return QVariant(breakpoint_red) + return QVariant(self.breakpoint_color) + self.cell_change_color.setAlpha(20*self.cell_animation[index]) + return QVariant(self.cell_change_color) elif int_role == Qt.ItemDataRole.DisplayRole: - return QVariant(utils.aob_to_str(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()])) + return QVariant(utils.aob_to_str(self.data_array[index])) return QVariant() diff --git a/GUI/AbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py index 10d45a7f..c0724064 100644 --- a/GUI/AbstractTableModels/HexModel.py +++ b/GUI/AbstractTableModels/HexModel.py @@ -19,8 +19,6 @@ from libpince import utils, debugcore -breakpoint_red = QColor(QColorConstants.Red) -breakpoint_red.setAlpha(96) class QHexModel(QAbstractTableModel): def __init__(self, row_count, column_count, parent=None): @@ -30,6 +28,11 @@ def __init__(self, row_count, column_count, parent=None): self.row_count = row_count self.column_count = column_count self.current_address = 0 + offset = row_count*column_count + self.cell_animation = [0]*offset + self.cell_change_color = QColor(QColorConstants.Red) + self.breakpoint_color = QColor(QColorConstants.Green) + self.breakpoint_color.setAlpha(96) def rowCount(self, QModelIndex_parent=None, *args, **kwargs): return self.row_count @@ -39,13 +42,15 @@ def columnCount(self, QModelIndex_parent=None, *args, **kwargs): def data(self, QModelIndex, int_role=None): if self.data_array and QModelIndex.isValid(): + index = QModelIndex.row() * self.column_count + QModelIndex.column() if int_role == Qt.ItemDataRole.BackgroundRole: - address = self.current_address + QModelIndex.row() * self.column_count + QModelIndex.column() + address = self.current_address + index if utils.modulo_address(address, debugcore.inferior_arch) in self.breakpoint_list: - return QVariant(breakpoint_red) + return QVariant(self.breakpoint_color) + self.cell_change_color.setAlpha(20*self.cell_animation[index]) + return QVariant(self.cell_change_color) elif int_role == Qt.ItemDataRole.DisplayRole: - return QVariant(self.data_array[QModelIndex.row() * self.column_count + QModelIndex.column()]) - + return QVariant(self.data_array[index]) return QVariant() def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): @@ -62,4 +67,15 @@ def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): for i in range(bp.size): self.breakpoint_list.add(utils.modulo_address(breakpoint_address + i, debugcore.inferior_arch)) self.current_address = int_address + self.cell_animation = [0]*offset + self.layoutChanged.emit() + + def update_loop(self, updated_array): + for index, item in enumerate(self.cell_animation): + if item > 0: + self.cell_animation[index] = item-1 + for index, item in enumerate(updated_array): + if item != self.data_array[index]: + self.cell_animation[index] = 6 + self.data_array = updated_array self.layoutChanged.emit() diff --git a/PINCE.py b/PINCE.py index d9180341..4368ee91 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2802,9 +2802,7 @@ def initialize_disassemble_view(self): self.bDisassemblyScrolling = False # rejects new scroll requests while scrolling self.tableWidget_Disassemble.wheelEvent = QEvent.ignore self.verticalScrollBar_Disassemble.wheelEvent = QEvent.ignore - self.verticalScrollBar_Disassemble.sliderChange = self.disassemble_scrollbar_sliderchanged - guiutils.center_scroll_bar(self.verticalScrollBar_Disassemble) # Format: [address1, address2, ...] @@ -2824,8 +2822,12 @@ def initialize_disassemble_view(self): def initialize_hex_view(self): self.hex_view_last_selected_address_int = 0 self.hex_view_current_region = typedefs.tuple_region_info(0, 0, None, None) + self.hex_model = QHexModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) + self.ascii_model = QAsciiModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) + self.tableView_HexView_Hex.setModel(self.hex_model) + self.tableView_HexView_Ascii.setModel(self.ascii_model) + self.widget_HexView.wheelEvent = self.widget_HexView_wheel_event - # Saving the original function because super() doesn't work when we override functions like this self.widget_HexView.keyPressEvent_original = self.widget_HexView.keyPressEvent self.widget_HexView.keyPressEvent = self.widget_HexView_key_press_event @@ -2841,19 +2843,14 @@ def initialize_hex_view(self): self.bHexViewScrolling = False # rejects new scroll requests while scrolling self.verticalScrollBar_HexView.wheelEvent = QEvent.ignore - self.verticalScrollBar_HexView.sliderChange = self.hex_view_scrollbar_sliderchanged + guiutils.center_scroll_bar(self.verticalScrollBar_HexView) self.tableWidget_HexView_Address.wheelEvent = QEvent.ignore self.tableWidget_HexView_Address.setAutoScroll(False) self.tableWidget_HexView_Address.setStyleSheet("QTableWidget {background-color: transparent;}") self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) - self.hex_model = QHexModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) - self.ascii_model = QAsciiModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) - self.tableView_HexView_Hex.setModel(self.hex_model) - self.tableView_HexView_Ascii.setModel(self.ascii_model) - self.tableView_HexView_Hex.selectionModel().currentChanged.connect(self.on_hex_view_current_changed) self.tableView_HexView_Ascii.selectionModel().currentChanged.connect(self.on_ascii_view_current_changed) @@ -2864,7 +2861,8 @@ def initialize_hex_view(self): self.tableWidget_HexView_Address.verticalHeader().setDefaultSectionSize( self.tableView_HexView_Hex.verticalHeader().defaultSectionSize()) - guiutils.center_scroll_bar(self.verticalScrollBar_HexView) + self.hex_update_timer = QTimer(timeout=self.hex_update_loop) + self.hex_update_timer.start(200) def show_trace_window(self): TraceInstructionsWindowForm(prompt_dialog=False) @@ -3112,6 +3110,14 @@ def on_ascii_view_current_changed(self, QModelIndex_current): self.tableWidget_HexView_Address.selectRow(QModelIndex_current.row()) self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) + def hex_update_loop(self): + if debugcore.currentpid == -1: + return + offset = HEX_VIEW_ROW_COUNT*HEX_VIEW_COL_COUNT + updated_array = debugcore.hex_dump(self.hex_model.current_address, offset) + self.hex_model.update_loop(updated_array) + self.ascii_model.update_loop(updated_array) + # TODO: Consider merging HexView_Address, HexView_Hex and HexView_Ascii into one UI class # TODO: Move this function to that class if that happens # TODO: Also consider moving shared fields of HexView and HexModel to that class(such as HexModel.current_address) From 6cd2da68cf6e1d918ce57f791e6e89b245afb791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 8 Jan 2024 17:51:54 +0300 Subject: [PATCH 318/487] Implement toggle_children --- PINCE.py | 22 +++++++++++++++++----- i18n/ts/it_IT.ts | 5 +++++ i18n/ts/zh_CN.ts | 5 +++++ tr/tr.py | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 4368ee91..0550087f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -745,6 +745,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): show_unsigned = menu.addAction(tr.SHOW_UNSIGNED) show_signed = menu.addAction(tr.SHOW_SIGNED) toggle_record = menu.addAction(f"{tr.TOGGLE}[Space]") + toggle_children = menu.addAction(f"{tr.TOGGLE_CHILDREN}[Ctrl+Space]") freeze_menu = menu.addMenu(tr.FREEZE) freeze_default = freeze_menu.addAction(tr.DEFAULT) freeze_inc = freeze_menu.addAction(tr.INCREMENTAL) @@ -766,8 +767,9 @@ def treeWidget_AddressTable_context_menu_event(self, event): create_group = menu.addAction(tr.CREATE_GROUP) if current_row is None: deletion_list = [edit_menu.menuAction(), show_hex, show_dec, show_unsigned, show_signed, toggle_record, - freeze_menu.menuAction(), browse_region, disassemble, what_writes, what_reads, - what_accesses, cut_record, copy_record, paste_inside, delete_record, add_group] + toggle_children, freeze_menu.menuAction(), browse_region, disassemble, what_writes, + what_reads, what_accesses, cut_record, copy_record, paste_inside, delete_record, + add_group] guiutils.delete_menu_entries(menu, deletion_list) else: value_type = current_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) @@ -783,6 +785,8 @@ def treeWidget_AddressTable_context_menu_event(self, event): else: guiutils.delete_menu_entries(menu, [show_hex, show_dec, show_unsigned, show_signed, freeze_menu.menuAction()]) + if current_row.childCount() == 0: + guiutils.delete_menu_entries(menu, [toggle_children]) font_size = self.treeWidget_AddressTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -797,6 +801,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): show_unsigned: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.UNSIGNED), show_signed: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.SIGNED), toggle_record: self.toggle_records, + toggle_children: lambda: self.toggle_records(True), freeze_default: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT), freeze_inc: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.INCREMENT), freeze_dec: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DECREMENT), @@ -872,14 +877,19 @@ def change_freeze_type(self, freeze_type): row.setText(FROZEN_COL, "▼") row.setForeground(FROZEN_COL, QBrush(QColor(255, 0, 0))) - def toggle_records(self): + def toggle_records(self, toggle_children=False): row = guiutils.get_current_item(self.treeWidget_AddressTable) if row: check_state = row.checkState(FROZEN_COL) - new_check_state = Qt.CheckState.Checked if check_state == Qt.CheckState.Unchecked else Qt.CheckState.Unchecked + new_state = Qt.CheckState.Checked if check_state == Qt.CheckState.Unchecked else Qt.CheckState.Unchecked for row in self.treeWidget_AddressTable.selectedItems(): - row.setCheckState(FROZEN_COL, new_check_state) + row.setCheckState(FROZEN_COL, new_state) self.treeWidget_AddressTable_item_clicked(row, FROZEN_COL) + if toggle_children: + for index in range(row.childCount()): + child = row.child(index) + child.setCheckState(FROZEN_COL, new_state) + self.treeWidget_AddressTable_item_clicked(child, FROZEN_COL) def cut_records(self): self.copy_records() @@ -998,6 +1008,8 @@ def treeWidget_AddressTable_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), lambda: self.update_address_table(use_cache=False)), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Space), + lambda: self.toggle_records(True)), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_X), self.cut_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), self.paste_records), diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 79c9df46..e32798f0 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1473,6 +1473,11 @@ To change the current GDB path, check Settings->Debug Toggle + + + Toggle including children + + Freeze diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 13eec778..aa062e80 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1477,6 +1477,11 @@ To change the current GDB path, check Settings->Debug Toggle + + + Toggle including children + + Freeze diff --git a/tr/tr.py b/tr/tr.py index 428c965e..a8a9371c 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -52,6 +52,7 @@ def translate(): SHOW_UNSIGNED = QT_TR_NOOP("Show as unsigned") SHOW_SIGNED = QT_TR_NOOP("Show as signed") TOGGLE = QT_TR_NOOP("Toggle") + TOGGLE_CHILDREN = QT_TR_NOOP("Toggle including children") FREEZE = QT_TR_NOOP("Freeze") DEFAULT = QT_TR_NOOP("Default") INCREMENTAL = QT_TR_NOOP("Incremental") From 3bda885d74ae47fb525d9ec96c4f0898ae67e846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 Jan 2024 18:16:23 +0300 Subject: [PATCH 319/487] Add cell editing for HexView --- GUI/AbstractTableModels/AsciiModel.py | 21 ++++--------- GUI/AbstractTableModels/HexModel.py | 32 ++++++++++++++------ GUI/ItemDelegates/HexDelegate.py | 43 +++++++++++++++++++++++++++ GUI/TableViews/AsciiView.py | 7 ++++- GUI/TableViews/HexView.py | 22 ++++++++++++-- PINCE.py | 4 +-- 6 files changed, 98 insertions(+), 31 deletions(-) create mode 100644 GUI/ItemDelegates/HexDelegate.py diff --git a/GUI/AbstractTableModels/AsciiModel.py b/GUI/AbstractTableModels/AsciiModel.py index 9aef7493..55f5889e 100644 --- a/GUI/AbstractTableModels/AsciiModel.py +++ b/GUI/AbstractTableModels/AsciiModel.py @@ -14,25 +14,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt6.QtCore import QVariant, Qt from GUI.AbstractTableModels.HexModel import QHexModel - -from libpince import utils, debugcore +from libpince import utils class QAsciiModel(QHexModel): def __init__(self, row_count, column_count, parent=None): super().__init__(row_count, column_count, parent) - def data(self, QModelIndex, int_role=None): - if self.data_array and QModelIndex.isValid(): - index = QModelIndex.row() * self.column_count + QModelIndex.column() - if int_role == Qt.ItemDataRole.BackgroundRole: - address = self.current_address + index - if utils.modulo_address(address, debugcore.inferior_arch) in self.breakpoint_list: - return QVariant(self.breakpoint_color) - self.cell_change_color.setAlpha(20*self.cell_animation[index]) - return QVariant(self.cell_change_color) - elif int_role == Qt.ItemDataRole.DisplayRole: - return QVariant(utils.aob_to_str(self.data_array[index])) - return QVariant() + def display_data(self, index): + return utils.aob_to_str(self.data_array[index]) + + def translate_data(self, data): + return utils.str_to_aob(data) diff --git a/GUI/AbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py index c0724064..7dc8f30a 100644 --- a/GUI/AbstractTableModels/HexModel.py +++ b/GUI/AbstractTableModels/HexModel.py @@ -14,9 +14,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt6.QtCore import QAbstractTableModel, QVariant, Qt +from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt from PyQt6.QtGui import QColor, QColorConstants - from libpince import utils, debugcore @@ -40,18 +39,26 @@ def rowCount(self, QModelIndex_parent=None, *args, **kwargs): def columnCount(self, QModelIndex_parent=None, *args, **kwargs): return self.column_count - def data(self, QModelIndex, int_role=None): - if self.data_array and QModelIndex.isValid(): - index = QModelIndex.row() * self.column_count + QModelIndex.column() + def flags(self, index: QModelIndex): + return super().flags(index) | Qt.ItemFlag.ItemIsEditable + + def data(self, model_index: QModelIndex, int_role=None): + if self.data_array and model_index.isValid(): + index = model_index.row() * self.column_count + model_index.column() if int_role == Qt.ItemDataRole.BackgroundRole: address = self.current_address + index if utils.modulo_address(address, debugcore.inferior_arch) in self.breakpoint_list: - return QVariant(self.breakpoint_color) + return self.breakpoint_color self.cell_change_color.setAlpha(20*self.cell_animation[index]) - return QVariant(self.cell_change_color) + return self.cell_change_color elif int_role == Qt.ItemDataRole.DisplayRole: - return QVariant(self.data_array[index]) - return QVariant() + return self.display_data(index) + + def display_data(self, index): + return self.data_array[index] + + def translate_data(self, data): + return data def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): int_address = utils.modulo_address(int_address, debugcore.inferior_arch) @@ -79,3 +86,10 @@ def update_loop(self, updated_array): self.cell_animation[index] = 6 self.data_array = updated_array self.layoutChanged.emit() + + def update_index(self, index, data): + data = self.translate_data(data) + if self.data_array[index] != data: + self.cell_animation[index] = 6 + self.data_array[index] = data + self.layoutChanged.emit() diff --git a/GUI/ItemDelegates/HexDelegate.py b/GUI/ItemDelegates/HexDelegate.py new file mode 100644 index 00000000..a778f4a7 --- /dev/null +++ b/GUI/ItemDelegates/HexDelegate.py @@ -0,0 +1,43 @@ +""" +Copyright (C) Korcan Karaokçu + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" +from PyQt6.QtWidgets import QItemDelegate, QLineEdit +from PyQt6.QtGui import QRegularExpressionValidator +from PyQt6.QtCore import Qt, QRegularExpression + + +class QHexDelegate(QItemDelegate): + def __init__(self, max_length=2, regexp="[0-9a-fA-F]+", parent=None): + super().__init__(parent) + self.max_length = max_length + self.regexp = regexp + + def createEditor(self, parent, option, index): + self.editor = QLineEdit(parent) + self.editor.setMaxLength(self.max_length) + hex_validator = QRegularExpressionValidator(QRegularExpression(self.regexp), self.editor) + self.editor.setValidator(hex_validator) + self.editor.setText(index.model().data(index, Qt.ItemDataRole.DisplayRole)) + self.editor.textChanged.connect(self.check_text) + return self.editor + + def setEditorData(self, editor, index): + # Initial text was set in createEditor, this is a trick to dodge the textChanged signal + return + + def check_text(self): + if len(self.editor.text()) >= self.max_length: + self.closeEditor.emit(self.editor, QItemDelegate.EndEditHint.EditNextItem) diff --git a/GUI/TableViews/AsciiView.py b/GUI/TableViews/AsciiView.py index ba81803a..fc718644 100644 --- a/GUI/TableViews/AsciiView.py +++ b/GUI/TableViews/AsciiView.py @@ -15,11 +15,16 @@ along with this program. If not, see . """ from GUI.TableViews.HexView import QHexView +from GUI.ItemDelegates.HexDelegate import QHexDelegate +from libpince import typedefs class QAsciiView(QHexView): - # data_array is returned from debugcore.hex_dump() def __init__(self, parent=None): super().__init__(parent) self.horizontalHeader().setMinimumSectionSize(15) self.horizontalHeader().setDefaultSectionSize(15) + self.write_type = typedefs.VALUE_INDEX.STRING_UTF8 + self.delegate = QHexDelegate(1, ".+") + self.delegate.closeEditor.connect(self.on_editor_close) + self.setItemDelegate(self.delegate) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index 98194904..e676712b 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -16,7 +16,9 @@ """ from PyQt6.QtWidgets import QTableView, QAbstractItemView from PyQt6.QtCore import Qt -from libpince import utils, debugcore +from GUI.ItemDelegates.HexDelegate import QHexDelegate +from GUI.AbstractTableModels.HexModel import QHexModel +from libpince import utils, debugcore, typedefs class QHexView(QTableView): @@ -34,6 +36,10 @@ def __init__(self, parent=None): self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setAutoScroll(False) + self.write_type = typedefs.VALUE_INDEX.AOB + self.delegate = QHexDelegate() + self.delegate.closeEditor.connect(self.on_editor_close) + self.setItemDelegate(self.delegate) def wheelEvent(self, QWheelEvent): QWheelEvent.ignore() @@ -45,8 +51,18 @@ def resize_to_contents(self): def get_selected_address(self): index_list = self.selectionModel().selectedIndexes() # Use selectionModel instead of currentIndex - current_address = self.model().current_address + model: QHexModel = self.model() + current_address = model.current_address if index_list: cell = index_list[0] - current_address = current_address + cell.row() * self.model().columnCount() + cell.column() + current_address = current_address + cell.row() * model.columnCount() + cell.column() return utils.modulo_address(current_address, debugcore.inferior_arch) + + def on_editor_close(self): + model: QHexModel = self.model() + cell = self.selectionModel().selectedIndexes()[0] + index = cell.row() * model.columnCount() + cell.column() + address = utils.modulo_address(model.current_address + index, debugcore.inferior_arch) + data = self.delegate.editor.text() + debugcore.write_memory(address, self.write_type, data) + model.update_index(index, data) diff --git a/PINCE.py b/PINCE.py index 0550087f..ce14ff0f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2846,8 +2846,6 @@ def initialize_hex_view(self): self.tableView_HexView_Hex.contextMenuEvent = self.widget_HexView_context_menu_event self.tableView_HexView_Ascii.contextMenuEvent = self.widget_HexView_context_menu_event - self.tableView_HexView_Hex.doubleClicked.connect(self.exec_hex_view_edit_dialog) - self.tableView_HexView_Ascii.doubleClicked.connect(self.exec_hex_view_edit_dialog) # Ignoring the event sends it directly to the parent, which is widget_HexView self.tableView_HexView_Hex.keyPressEvent = QEvent.ignore @@ -3123,7 +3121,7 @@ def on_ascii_view_current_changed(self, QModelIndex_current): self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) def hex_update_loop(self): - if debugcore.currentpid == -1: + if debugcore.currentpid == -1 or exiting: return offset = HEX_VIEW_ROW_COUNT*HEX_VIEW_COL_COUNT updated_array = debugcore.hex_dump(self.hex_model.current_address, offset) From 83119dba54c95606314485d9f68617cf9db25bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 9 Jan 2024 18:51:51 +0300 Subject: [PATCH 320/487] Add zero_terminate param to write_memory --- GUI/TableViews/HexView.py | 2 +- PINCE.py | 16 ++++++++-------- libpince/debugcore.py | 7 +++++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index e676712b..84e270ee 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -64,5 +64,5 @@ def on_editor_close(self): index = cell.row() * model.columnCount() + cell.column() address = utils.modulo_address(model.current_address + index, debugcore.inferior_arch) data = self.delegate.editor.text() - debugcore.write_memory(address, self.write_type, data) + debugcore.write_memory(address, self.write_type, data, False) model.update_index(index, data) diff --git a/PINCE.py b/PINCE.py index ce14ff0f..a19f8b2d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1594,9 +1594,9 @@ def freeze(self): if freeze_type == typedefs.FREEZE_TYPE.INCREMENT and new_value > int(value, 0) or \ freeze_type == typedefs.FREEZE_TYPE.DECREMENT and new_value < int(value, 0): frozen.value = str(new_value) - debugcore.write_memory(address, vt.value_index, frozen.value, vt.endian) + debugcore.write_memory(address, vt.value_index, frozen.value, endian=vt.endian) continue - debugcore.write_memory(address, vt.value_index, value, vt.endian) + debugcore.write_memory(address, vt.value_index, value, vt.zero_terminate, vt.endian) it += 1 def treeWidget_AddressTable_item_clicked(self, row, column): @@ -1627,16 +1627,16 @@ def treeWidget_AddressTable_edit_value(self): new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): address = row.text(ADDR_COL).strip("P->") - value_type = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - if typedefs.VALUE_INDEX.has_length(value_type.value_index): - unknown_type = utils.parse_string(new_value, value_type.value_index) + vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) + if typedefs.VALUE_INDEX.has_length(vt.value_index): + unknown_type = utils.parse_string(new_value, vt.value_index) if unknown_type is not None: - value_type.length = len(unknown_type) - row.setText(TYPE_COL, value_type.text()) + vt.length = len(unknown_type) + row.setText(TYPE_COL, vt.text()) frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) frozen.value = new_value row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) - debugcore.write_memory(address, value_type.value_index, new_value, value_type.endian) + debugcore.write_memory(address, vt.value_index, new_value, vt.zero_terminate, vt.endian) self.update_address_table() def treeWidget_AddressTable_edit_desc(self): diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 32e135f6..185790d5 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -887,7 +887,7 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re #:tag:MemoryRW -def write_memory(address, value_index, value, endian=typedefs.ENDIANNESS.HOST): +def write_memory(address, value_index, value, zero_terminate=True, endian=typedefs.ENDIANNESS.HOST): """Sets the given value to the given address If any errors occurs while setting value to the according address, it'll be ignored but the information about @@ -897,6 +897,7 @@ def write_memory(address, value_index, value, endian=typedefs.ENDIANNESS.HOST): address (str, int): Can be a hex string or an integer value_index (int): Can be a member of typedefs.VALUE_INDEX value (str): The value that'll be written to the given address + zero_terminate (bool): If True, appends a null byte to the value. Only used when value_index is STRING endian (int): Can be a member of typedefs.ENDIANNESS Notes: @@ -921,7 +922,9 @@ def write_memory(address, value_index, value, endian=typedefs.ENDIANNESS.HOST): data_type = typedefs.index_to_struct_pack_dict.get(value_index, -1) write_data = struct.pack(data_type, write_data) else: - write_data = write_data.encode(encoding, option) + b"\x00" # Zero-terminated by default + write_data = write_data.encode(encoding, option) + if zero_terminate: + write_data += b"\x00" if endian != typedefs.ENDIANNESS.HOST and system_endianness != endian: write_data = write_data[::-1] FILE = open(mem_file, "rb+") From 23fb929b1f40a03099e417172bb6128aa771c1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 10 Jan 2024 16:51:51 +0300 Subject: [PATCH 321/487] Fix QPainter error in signal_handler --- PINCE.py | 66 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/PINCE.py b/PINCE.py index a19f8b2d..6842bc54 100755 --- a/PINCE.py +++ b/PINCE.py @@ -34,10 +34,10 @@ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ - QLocale + QLocale, QSignalBlocker from typing import Final from time import sleep, time -import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect, json +import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect, json, select from libpince import utils, debugcore, typedefs from libpince.libscanmem.scanmem import Scanmem @@ -371,21 +371,35 @@ def except_hook(exception_type, value, tb): # So, we must override sys.excepthook to avoid calling of qFatal() sys.excepthook = except_hook +quit_prompt_active = False + def signal_handler(signal, frame): - if debugcore.lock_send_command.locked(): - print("\nCancelling the last GDB command") - debugcore.cancel_last_command() - else: - try: - text = input("\nNo GDB command to cancel, quit PINCE? (y/n)") - if text.lower().startswith("y"): + global quit_prompt_active + with QSignalBlocker(app): + if debugcore.lock_send_command.locked(): + print("\nCancelling the last GDB command") + debugcore.cancel_last_command() + else: + if quit_prompt_active: + print() # Prints a newline so the terminal looks nicer when we quit debugcore.detach() quit() - except RuntimeError: - print() # Prints a newline so the terminal looks nicer when we quit - debugcore.detach() - quit() + quit_prompt_active = True + print("\nNo GDB command to cancel, quit PINCE? (y/n)", end="", flush=True) + while True: + # Using select() instead of input() because it causes the bug below + # QBackingStore::endPaint() called with active painter + rlist, _, _ = select.select([sys.stdin], [], [], 0.1) + if rlist: + user_input = sys.stdin.readline().strip().lower() + break + if user_input.lower().startswith("y"): + debugcore.detach() + quit() + else: + print("Quit aborted") + quit_prompt_active = False signal.signal(signal.SIGINT, signal_handler) @@ -2405,22 +2419,20 @@ def config_gui(self): self.comboBox_Language.addItem(lang) if loc == cur_loc: self.comboBox_Language.setCurrentIndex(self.comboBox_Language.count()-1) - self.comboBox_Theme.blockSignals(True) - self.comboBox_Theme.clear() - cur_theme = self.settings.value("General/theme", type=str) - for thm in theme_list: - self.comboBox_Theme.addItem(thm) - if thm == cur_theme: - self.comboBox_Theme.setCurrentIndex(self.comboBox_Theme.count()-1) - self.comboBox_Theme.blockSignals(False) + with QSignalBlocker(self.comboBox_Theme): + self.comboBox_Theme.clear() + cur_theme = self.settings.value("General/theme", type=str) + for thm in theme_list: + self.comboBox_Theme.addItem(thm) + if thm == cur_theme: + self.comboBox_Theme.setCurrentIndex(self.comboBox_Theme.count()-1) logo_directory = utils.get_logo_directory() logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") - self.comboBox_Logo.blockSignals(True) - self.comboBox_Logo.clear() - for logo in logo_list: - self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) - self.comboBox_Logo.setCurrentIndex(logo_list.index(self.settings.value("General/logo_path", type=str))) - self.comboBox_Logo.blockSignals(False) + with QSignalBlocker(self.comboBox_Logo): + self.comboBox_Logo.clear() + for logo in logo_list: + self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) + self.comboBox_Logo.setCurrentIndex(logo_list.index(self.settings.value("General/logo_path", type=str))) self.listWidget_Functions.clear() self.hotkey_to_value.clear() for hotkey in Hotkeys.get_hotkeys(): From f56d272cc75fac74147eb1e1d766e9e143a42c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 10 Jan 2024 16:57:12 +0300 Subject: [PATCH 322/487] Remove redundant lower() call --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 6842bc54..e634a49e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -394,7 +394,7 @@ def signal_handler(signal, frame): if rlist: user_input = sys.stdin.readline().strip().lower() break - if user_input.lower().startswith("y"): + if user_input.startswith("y"): debugcore.detach() quit() else: From 9b68eb068b36654981b14e8673f46a3b0aff88f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 Jan 2024 13:39:26 +0300 Subject: [PATCH 323/487] Fix keyPressEvent of ProcessForm --- PINCE.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index e634a49e..2e24b4b0 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1758,16 +1758,15 @@ def generate_new_list(self): processlist = utils.search_processes(text) self.refresh_process_table(self.tableWidget_ProcessTable, processlist) - def keyPressEvent(self, e): - if e.key() == Qt.Key.Key_Escape: - # closes the window whenever ESC key is pressed + def keyPressEvent(self, event): + if event.key() == Qt.Key.Key_Escape: self.close() - elif e.key() == Qt.Key.Key_Return: + elif event.key() == Qt.Key.Key_Return: self.pushButton_Open_clicked() - elif e.key() == Qt.Key.Key_F1: + elif event.key() == Qt.Key.Key_F1: self.pushButton_CreateProcess_clicked() - elif e.key() == Qt.Key.Key_Down or e.key() == Qt.Key.Key_Up: - self.tableWidget_ProcessTable.keyPressEvent(QKeyEvent(QEvent.KeyPress, e.key(), Qt.NoModifier)) + else: + return super().keyPressEvent(event) # lists currently working processes to table def refresh_process_table(self, tablewidget, processlist): From 9946429e1654832e84ab645801cc42ad754355ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 Jan 2024 14:36:53 +0300 Subject: [PATCH 324/487] Enter edit mode when pressed enter in HexView --- GUI/TableViews/HexView.py | 8 ++++++++ PINCE.py | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index 84e270ee..2e99245f 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +from PyQt6.QtGui import QKeyEvent from PyQt6.QtWidgets import QTableView, QAbstractItemView from PyQt6.QtCore import Qt from GUI.ItemDelegates.HexDelegate import QHexDelegate @@ -32,6 +33,7 @@ def __init__(self, parent=None): self.horizontalHeader().setDefaultSectionSize(25) self.setStyleSheet("QTableView {background-color: transparent;}") self.setShowGrid(False) + self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked) self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) @@ -44,6 +46,12 @@ def __init__(self, parent=None): def wheelEvent(self, QWheelEvent): QWheelEvent.ignore() + def keyPressEvent(self, event: QKeyEvent): + if event.key() == Qt.Key.Key_Return and self.state() != QAbstractItemView.State.EditingState: + self.edit(self.currentIndex()) + else: + return super().keyPressEvent(event) + def resize_to_contents(self): size = self.columnWidth(0) * self.model().columnCount() self.setMinimumWidth(size) diff --git a/PINCE.py b/PINCE.py index 2e24b4b0..f2000134 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2858,10 +2858,6 @@ def initialize_hex_view(self): self.tableView_HexView_Hex.contextMenuEvent = self.widget_HexView_context_menu_event self.tableView_HexView_Ascii.contextMenuEvent = self.widget_HexView_context_menu_event - # Ignoring the event sends it directly to the parent, which is widget_HexView - self.tableView_HexView_Hex.keyPressEvent = QEvent.ignore - self.tableView_HexView_Ascii.keyPressEvent = QEvent.ignore - self.bHexViewScrolling = False # rejects new scroll requests while scrolling self.verticalScrollBar_HexView.wheelEvent = QEvent.ignore self.verticalScrollBar_HexView.sliderChange = self.hex_view_scrollbar_sliderchanged From d6254504052a998e5736772325ca4531377320b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 Jan 2024 18:59:25 +0300 Subject: [PATCH 325/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d7614d59..115e362a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -178,6 +178,7 @@ These tasks are ordered by importance but feel free to pick any of them. Further - Implement libpince engine - Implement multi-line code injection, this will also help with previously dropped inject_with_advanced_injection - Migrate to Sphinx documentation from the custom libpince documentation +- Libpince support for Mono and Java (symbol recognition, calling functions, dissect obj tree etc.) - Move GUI classes of PINCE.py to their own files - Extend documentation to GUI parts. Libpince has 100% documentation coverage but GUI doesn't - Use type hints(py 3.5) and variable annotations(py 3.6) when support drops for older systems From 6dc5cd9b09e0308db0852d83ffcab351d08aef0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 11 Jan 2024 22:59:04 +0300 Subject: [PATCH 326/487] Add type hints to guiutils --- GUI/Utils/guiutils.py | 114 ++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 54 deletions(-) diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index df2fb948..e4ce643e 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -15,6 +15,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ +from PyQt6.QtWidgets import QWidget, QScrollBar, QTableWidget, QComboBox, QMenu, QLayout +from PyQt6.QtCore import QObject +from PyQt6.QtGui import QShortcut from libpince import utils, typedefs, regexes from tr.tr import TranslationConstants as tr @@ -29,79 +32,81 @@ def get_icons_directory(): #:tag:GUI -def center(window): +def center(window: QWidget): """Center the given window to desktop Args: - window (QMainWindow, QWidget etc.): The window that'll be centered to desktop + window (QWidget): The window that'll be centered to desktop """ window.frameGeometry().moveCenter(window.screen().availableGeometry().center()) #:tag:GUI -def center_to_parent(window): +def center_to_parent(window: QWidget): """Center the given window to it's parent Args: - window (QMainWindow, QWidget etc.): The window that'll be centered to it's parent + window (QWidget): The window that'll be centered to it's parent """ - window.move(window.parent().frameGeometry().center() - window.frameGeometry().center()) + parent: QWidget = window.parent() + window.move(parent.frameGeometry().center() - window.frameGeometry().center()) #:tag:GUI -def center_to_window(window_secondary, window_main): +def center_to_window(window_secondary: QWidget, window_main: QWidget): """Center the given window_secondary to window_main Args: - window_secondary (QMainWindow, QWidget etc.): The window that'll be centered to window_main - window_main (QMainWindow, QWidget etc.): The window that window_secondary will centered to + window_secondary (QQWidget): The window that'll be centered to window_main + window_main (QWidget): The window that window_secondary will centered to """ window_secondary.move(window_main.frameGeometry().center() - window_secondary.frameGeometry().center()) #:tag:GUI -def center_scroll_bar(QScrollBar): +def center_scroll_bar(scrollbar: QScrollBar): """Center the given scrollbar Args: - QScrollBar (QScrollbar): The scrollbar that'll be centered + scrollbar (QScrollbar): Self-explanatory """ - maximum = QScrollBar.maximum() - minimum = QScrollBar.minimum() - QScrollBar.setValue((maximum + minimum) // 2) + maximum = scrollbar.maximum() + minimum = scrollbar.minimum() + scrollbar.setValue((maximum + minimum) // 2) #:tag:GUI -def resize_to_contents(QTableWidget): +def resize_to_contents(tablewidget: QTableWidget): """Resizes the columns of the given QTableWidget to its contents This also fixes the stretch problem of the last column Args: - QTableWidget (QTableWidget): Self-explanatory + tablewidget (QTableWidget): Self-explanatory """ - QTableWidget.resizeColumnsToContents() - default_size = QTableWidget.horizontalHeader().defaultSectionSize() - QTableWidget.horizontalHeader().resizeSection(QTableWidget.columnCount() - 1, default_size) + tablewidget.resizeColumnsToContents() + default_size = tablewidget.horizontalHeader().defaultSectionSize() + tablewidget.horizontalHeader().resizeSection(tablewidget.columnCount() - 1, default_size) #:tag:GUI -def fill_value_combobox(QCombobox, current_index=typedefs.VALUE_INDEX.INT32): - """Fills the given QCombobox with value_index strings +def fill_value_combobox(combobox: QComboBox, current_index: int = typedefs.VALUE_INDEX.INT32): + """Fills the given QComboBox with value_index strings Args: - QCombobox (QCombobox): The combobox that'll be filled + combobox (QComboBox): The combobox that'll be filled current_index (int): Can be a member of typedefs.VALUE_INDEX """ for key in typedefs.index_to_text_dict: - QCombobox.addItem(typedefs.index_to_text_dict[key]) - QCombobox.setCurrentIndex(current_index) + combobox.addItem(typedefs.index_to_text_dict[key]) + combobox.setCurrentIndex(current_index) + #:tag:GUI -def fill_endianness_combobox(QCombobox, current_index=typedefs.ENDIANNESS.HOST): - """Fills the given QCombobox with endianness strings +def fill_endianness_combobox(combobox: QComboBox, current_index: int = typedefs.ENDIANNESS.HOST): + """Fills the given QComboBox with endianness strings Args: - QCombobox (QCombobox): The combobox that'll be filled + combobox (QComboBox): The combobox that'll be filled current_index (int): Can be a member of typedefs.ENDIANNESS """ endianness_text = [ @@ -110,18 +115,19 @@ def fill_endianness_combobox(QCombobox, current_index=typedefs.ENDIANNESS.HOST): (typedefs.ENDIANNESS.BIG, tr.BIG) ] for endian, text in endianness_text: - QCombobox.addItem(text, endian) - QCombobox.setCurrentIndex(current_index) + combobox.addItem(text, endian) + combobox.setCurrentIndex(current_index) + #:tag:GUI -def get_current_row(QObject): - """Returns the currently selected row index for the given QObject +def get_current_row(tablewidget: QTableWidget): + """Returns the currently selected row index for the given QTableWidget If you try to use only selectionModel().currentIndex().row() for this purpose, you'll get the last selected row even if it was unselected afterwards. This is why this function exists, it checks the selection state before returning the selected row Args: - QObject (QObject): Self-explanatory + tablewidget (QTableWidget): Self-explanatory Returns: int: Currently selected row. Returns -1 if nothing is selected @@ -134,20 +140,20 @@ def get_current_row(QObject): For developers: You can use the regex \.current.*\.connect to search signals if a cleanup is needed """ - if QObject.selectionModel().selectedRows(): - return QObject.selectionModel().currentIndex().row() + if tablewidget.selectionModel().selectedRows(): + return tablewidget.selectionModel().currentIndex().row() return -1 #:tag:GUI -def get_current_item(QObject): - """Returns the currently selected item for the given QObject +def get_current_item(tablewidget: QTableWidget): + """Returns the currently selected item for the given QTableWidget If you try to use only selectionModel().currentItem() for this purpose, you'll get the last selected item even if it was unselected afterwards. This is why this function exists, it checks the selection state before returning the selected item. Unlike get_current_row, this function can be used with QTreeWidget Args: - QObject (QObject): Self-explanatory + tablewidget (QTableWidget): Self-explanatory Returns: Any: Currently selected item. Returns None if nothing is selected @@ -160,21 +166,21 @@ def get_current_item(QObject): For developers: You can use the regex \.current.*\.connect to search signals if a cleanup is needed """ - if QObject.selectionModel().selectedRows(): - return QObject.currentItem() + if tablewidget.selectionModel().selectedRows(): + return tablewidget.currentItem() #:tag:GUI -def delete_menu_entries(QMenu, QAction_list): +def delete_menu_entries(menu: QMenu, QAction_list: list): """Deletes given QActions from the QMenu recursively and cleans up the remaining redundant separators and menus Doesn't support menus that includes types other than actions, separators and menus Args: - QMenu (QMenu): Self-explanatory + menu (QMenu): Self-explanatory QAction_list (list): List of QActions. Leave blank if you just want to clean the redundant separators up """ - def remove_entries(menu): + def remove_entries(menu: QMenu): for action in menu.actions(): try: QAction_list.index(action) @@ -183,7 +189,7 @@ def remove_entries(menu): else: menu.removeAction(action) - def clean_entries(menu): + def clean_entries(menu: QMenu): for action in menu.actions(): if action.isSeparator(): actions = menu.actions() @@ -193,18 +199,18 @@ def clean_entries(menu): (actions[current_index - 1].isSeparator() and actions[current_index + 1].isSeparator()): menu.removeAction(action) - remove_entries(QMenu) - clean_entries(QMenu) + remove_entries(menu) + clean_entries(menu) # TODO: This is a really bad design pattern, remove this function after moving classes to their own files #:tag:GUI -def search_parents_by_function(qt_object, func_name): - """Search for func_name in the parents of given qt_object. Once function is found, parent that possesses func_name +def search_parents_by_function(qt_object: QObject, func_name: str): + """Search for func_name in the parents of given QObject. Once function is found, parent that possesses func_name is returned Args: - qt_object (object): The object that'll be searched for it's parents + qt_object (QObject): The object that'll be searched for it's parents func_name (str): The name of the function that'll be searched """ while qt_object is not None: @@ -214,8 +220,8 @@ def search_parents_by_function(qt_object, func_name): #:tag:GUI -def get_layout_widgets(layout): - """Returns the widgets of a layout as a list +def get_layout_widgets(layout: QLayout): + """Returns the widgets of a QLayout as a list Args: layout: Self-explanatory @@ -227,7 +233,7 @@ def get_layout_widgets(layout): #:tag:GUI -def contains_reference_mark(string): +def contains_reference_mark(string: str): """Checks if given string contains the reference mark Args: @@ -240,11 +246,11 @@ def contains_reference_mark(string): #:tag:GUI -def append_shortcut_to_tooltip(QObject, QShortcut): +def append_shortcut_to_tooltip(qt_object: QObject, shortcut: QShortcut): """Appends key string of the given QShortcut to the toolTip of the given QObject Args: - QObject (QObject): Self-explanatory - QShortcut (QShortcut): Self-explanatory + qt_object (QObject): Self-explanatory + shortcut (QShortcut): Self-explanatory """ - QObject.setToolTip(QObject.toolTip() + "[" + QShortcut.key().toString() + "]") \ No newline at end of file + qt_object.setToolTip(qt_object.toolTip() + "[" + shortcut.key().toString() + "]") From c5353d24baedd6060bb77fe54b297e5c6e857b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 12 Jan 2024 15:48:24 +0300 Subject: [PATCH 327/487] Implement multi selection for HexView --- CONTRIBUTING.md | 1 - GUI/MemoryViewerWindow.py | 1 - GUI/MemoryViewerWindow.ui | 3 --- GUI/TableViews/HexView.py | 8 +++---- PINCE.py | 46 +++++++++++++++++++++------------------ 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 115e362a..9531ccbc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -191,7 +191,6 @@ These tasks are ordered by importance but feel free to pick any of them. Further - Automatic function bypassing(make it return the desired value, hook specific parts etc.) - Implement auto-ESP&aimbot - Implement thread info widget -- Implement multi selection for HexView - Write at least one test for each function in libpince - Refactorize memory write/read functions - - ReferencedStringsWidgetForm refreshes the cache everytime the comboBox_ValueType changes, this creates serious performance issues if total results are more than 800k. diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 412cb2b3..ed106722 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -642,7 +642,6 @@ def setupUi(self, MainWindow_MemoryView): self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.tableWidget_HexView_Address = QtWidgets.QTableWidget(parent=self.scrollAreaWidgetContents_2) self.tableWidget_HexView_Address.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) - self.tableWidget_HexView_Address.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_HexView_Address.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_HexView_Address.setShowGrid(False) self.tableWidget_HexView_Address.setObjectName("tableWidget_HexView_Address") diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 7c788a15..77a54877 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -1298,9 +1298,6 @@ QAbstractItemView::NoEditTriggers - - QAbstractItemView::SingleSelection - QAbstractItemView::SelectRows diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index 2e99245f..96063daa 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -34,7 +34,6 @@ def __init__(self, parent=None): self.setStyleSheet("QTableView {background-color: transparent;}") self.setShowGrid(False) self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked) - self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setAutoScroll(False) @@ -58,17 +57,16 @@ def resize_to_contents(self): self.setMaximumWidth(size) def get_selected_address(self): - index_list = self.selectionModel().selectedIndexes() # Use selectionModel instead of currentIndex + cell = self.currentIndex() model: QHexModel = self.model() current_address = model.current_address - if index_list: - cell = index_list[0] + if cell: current_address = current_address + cell.row() * model.columnCount() + cell.column() return utils.modulo_address(current_address, debugcore.inferior_arch) def on_editor_close(self): model: QHexModel = self.model() - cell = self.selectionModel().selectedIndexes()[0] + cell = self.currentIndex() index = cell.row() * model.columnCount() + cell.column() address = utils.modulo_address(model.current_address + index, debugcore.inferior_arch) data = self.delegate.editor.text() diff --git a/PINCE.py b/PINCE.py index f2000134..0fb9e8fb 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2843,7 +2843,7 @@ def initialize_disassemble_view(self): self.tableWidget_Disassemble.itemSelectionChanged.connect(self.tableWidget_Disassemble_item_selection_changed) def initialize_hex_view(self): - self.hex_view_last_selected_address_int = 0 + self.hex_view_last_selected_address = 0 self.hex_view_current_region = typedefs.tuple_region_info(0, 0, None, None) self.hex_model = QHexModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) self.ascii_model = QAsciiModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) @@ -2868,8 +2868,8 @@ def initialize_hex_view(self): self.tableWidget_HexView_Address.setStyleSheet("QTableWidget {background-color: transparent;}") self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) - self.tableView_HexView_Hex.selectionModel().currentChanged.connect(self.on_hex_view_current_changed) - self.tableView_HexView_Ascii.selectionModel().currentChanged.connect(self.on_ascii_view_current_changed) + self.tableView_HexView_Hex.selectionModel().selectionChanged.connect(self.hex_view_selection_changed) + self.tableView_HexView_Ascii.selectionModel().selectionChanged.connect(self.hex_view_selection_changed) self.scrollArea_Hex.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.scrollArea_Hex.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) @@ -3108,24 +3108,28 @@ def disassemble_scrollbar_sliderchanged(self, even): guiutils.center_scroll_bar(self.verticalScrollBar_Disassemble) self.bDisassemblyScrolling = False - def on_hex_view_current_changed(self, QModelIndex_current): - if debugcore.currentpid == -1: - return - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) - self.tableView_HexView_Ascii.selectionModel().setCurrentIndex(QModelIndex_current, - QItemSelectionModel.SelectionFlag.ClearAndSelect) - self.tableWidget_HexView_Address.selectRow(QModelIndex_current.row()) - self.hex_view_last_selected_address_int = self.tableView_HexView_Hex.get_selected_address() - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) - - def on_ascii_view_current_changed(self, QModelIndex_current): - if debugcore.currentpid == -1: - return - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) - self.tableView_HexView_Hex.selectionModel().setCurrentIndex(QModelIndex_current, - QItemSelectionModel.SelectionFlag.ClearAndSelect) - self.tableWidget_HexView_Address.selectRow(QModelIndex_current.row()) + def hex_view_selection_changed(self, selected, deselected): + sender_selection_model: QItemSelectionModel = self.sender() + if sender_selection_model == self.tableView_HexView_Hex.selectionModel(): + other_selection_model = self.tableView_HexView_Ascii.selectionModel() + else: + other_selection_model = self.tableView_HexView_Hex.selectionModel() + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) + self.tableWidget_HexView_Address.clearSelection() + selected_rows = [] + with QSignalBlocker(other_selection_model): + other_selection_model.clearSelection() + for index in sender_selection_model.selectedIndexes(): + other_selection_model.select(index, QItemSelectionModel.SelectionFlag.Select) + row = index.row() + if row not in selected_rows: + selected_rows.append(row) + self.tableWidget_HexView_Address.selectRow(row) self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) + self.hex_view_last_selected_address = self.tableView_HexView_Hex.get_selected_address() + self.tableView_HexView_Hex.update() + self.tableView_HexView_Ascii.update() + self.tableWidget_HexView_Address.update() def hex_update_loop(self): if debugcore.currentpid == -1 or exiting: @@ -3166,7 +3170,7 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL self.ascii_model.refresh(int_address, offset, data_array, breakpoint_info) for index in range(offset): current_address = utils.modulo_address(self.hex_model.current_address + index, debugcore.inferior_arch) - if current_address == self.hex_view_last_selected_address_int: + if current_address == self.hex_view_last_selected_address: row_index = int(index / HEX_VIEW_COL_COUNT) model_index = QModelIndex(self.hex_model.index(row_index, index % HEX_VIEW_COL_COUNT)) self.tableView_HexView_Hex.selectionModel().setCurrentIndex(model_index, From 866ca1c861521a52ffdedad2ea7b6a138b15f91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 13 Jan 2024 18:03:16 +0000 Subject: [PATCH 328/487] Update libscanmem for new undo changes --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index 2bbea6fa..321fa6b1 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit 2bbea6fac1b33d0e06f780d72b3294d22768719e +Subproject commit 321fa6b18246ebcb2ac19c997a4e85ce7e54b82b From f4924bf78642b1dc74ebf7ea0a202ff6f31a376a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 13 Jan 2024 18:24:39 +0000 Subject: [PATCH 329/487] Change undo scan button behaviour Scan method naming change --- PINCE.py | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/PINCE.py b/PINCE.py index 0fb9e8fb..6ff64d0b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1101,6 +1101,19 @@ def update_address_table(self, use_cache=True): value = "" if value is None else str(value) row.setText(VALUE_COL, value) + def scan_values(self): + global threadpool + if debugcore.currentpid == -1: + return + search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) + self.QWidget_Toolbox.setEnabled(False) + self.progressBar.setValue(0) + self.progress_bar_timer = QTimer(timeout=self.update_progress_bar) + self.progress_bar_timer.start(100) + scan_thread = Worker(scanmem.send_command, search_for) + scan_thread.signals.finished.connect(self.scan_callback) + threadpool.start(scan_thread) + def resize_address_table(self): self.treeWidget_AddressTable.resizeColumnToContents(FROZEN_COL) @@ -1154,7 +1167,6 @@ def pushButton_NewFirstScan_clicked(self): self.pushButton_NewFirstScan.setText(tr.NEW_SCAN) self.comboBox_ValueType.setEnabled(False) self.pushButton_NextScan.setEnabled(True) - self.pushButton_UndoScan.setEnabled(True) search_scope = self.comboBox_ScanScope.currentData(Qt.ItemDataRole.UserRole) endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) scanmem.send_command(f"option region_scan_level {search_scope}") @@ -1162,11 +1174,17 @@ def pushButton_NewFirstScan_clicked(self): scanmem.reset() self.comboBox_ScanScope.setEnabled(False) self.comboBox_Endianness.setEnabled(False) - self.pushButton_NextScan_clicked() # makes code a little simpler to just implement everything in nextscan + self.scan_values() self.comboBox_ScanType_init() def pushButton_UndoScan_clicked(self): - self.pushButton_NextScan_clicked("undo") + global threadpool + if debugcore.currentpid == -1: + return + undo_thread = Worker(scanmem.undo_scan) + undo_thread.signals.finished.connect(self.scan_callback) + threadpool.start(undo_thread) + self.pushButton_UndoScan.setEnabled(False) # we can undo once so set it to false and re-enable at next scan def comboBox_ScanType_current_index_changed(self): hidden_types = [typedefs.SCAN_TYPE.INCREASED, typedefs.SCAN_TYPE.DECREASED, typedefs.SCAN_TYPE.CHANGED, @@ -1268,22 +1286,9 @@ def validate_search(self, search_for, search_for2): return cmp_symbols[type_index] + " " + search_for return search_for - def pushButton_NextScan_clicked(self, search_for=None): - global threadpool - if debugcore.currentpid == -1: - return - if not search_for: - search_for = self.validate_search(self.lineEdit_Scan.text(), self.lineEdit_Scan2.text()) - self.QWidget_Toolbox.setEnabled(False) - self.progressBar.setValue(0) - self.progress_bar_timer = QTimer(timeout=self.update_progress_bar) - self.progress_bar_timer.start(100) - if search_for == "undo": - scan_thread = Worker(scanmem.undo_scan) - else: - scan_thread = Worker(scanmem.send_command, search_for) - scan_thread.signals.finished.connect(self.scan_callback) - threadpool.start(scan_thread) + def pushButton_NextScan_clicked(self): + self.scan_values() + self.pushButton_UndoScan.setEnabled(True) def scan_callback(self): self.progress_bar_timer.stop() From c2d2a87193e3cf63699fadeafdc64e64eb442995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 14 Jan 2024 19:37:32 +0000 Subject: [PATCH 330/487] Add git cloning check to installer --- install_pince.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/install_pince.sh b/install_pince.sh index c753340e..a9be4e5f 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -25,6 +25,14 @@ if [ "$(id -u)" = "0" ]; then exit 1 fi +if [ ! -d ".git" ]; then + echo "Error! Could not find \".git\" folder!" + echo "This can happen if you downloaded the ZIP file instead of cloning through git." + echo "Please clone the PINCE repository using the \"--recursive\" flag and try again!" + echo "For more information, please follow the installation instructions on GitHub." + exit 1 +fi + CURRENT_USER="$(whoami)" if [ -z "$NUM_MAKE_JOBS" ]; then From 8af10384f1fbd2b0ea7056b5863cd6e8a910b5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 22 Jan 2024 15:46:25 +0300 Subject: [PATCH 331/487] Use QStyledItemDelegate and update type hints --- GUI/ItemDelegates/HexDelegate.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/GUI/ItemDelegates/HexDelegate.py b/GUI/ItemDelegates/HexDelegate.py index a778f4a7..f00752b5 100644 --- a/GUI/ItemDelegates/HexDelegate.py +++ b/GUI/ItemDelegates/HexDelegate.py @@ -14,18 +14,18 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt6.QtWidgets import QItemDelegate, QLineEdit +from PyQt6.QtWidgets import QStyledItemDelegate, QLineEdit, QWidget from PyQt6.QtGui import QRegularExpressionValidator -from PyQt6.QtCore import Qt, QRegularExpression +from PyQt6.QtCore import QModelIndex, Qt, QRegularExpression -class QHexDelegate(QItemDelegate): - def __init__(self, max_length=2, regexp="[0-9a-fA-F]+", parent=None): +class QHexDelegate(QStyledItemDelegate): + def __init__(self, max_length: int = 2, regexp: str = "[0-9a-fA-F]+", parent=None) -> None: super().__init__(parent) self.max_length = max_length self.regexp = regexp - def createEditor(self, parent, option, index): + def createEditor(self, parent: QWidget, option, index: QModelIndex) -> QLineEdit: self.editor = QLineEdit(parent) self.editor.setMaxLength(self.max_length) hex_validator = QRegularExpressionValidator(QRegularExpression(self.regexp), self.editor) @@ -34,10 +34,10 @@ def createEditor(self, parent, option, index): self.editor.textChanged.connect(self.check_text) return self.editor - def setEditorData(self, editor, index): + def setEditorData(self, editor, index) -> None: # Initial text was set in createEditor, this is a trick to dodge the textChanged signal return - def check_text(self): + def check_text(self) -> None: if len(self.editor.text()) >= self.max_length: - self.closeEditor.emit(self.editor, QItemDelegate.EndEditHint.EditNextItem) + self.closeEditor.emit(self.editor, QStyledItemDelegate.EndEditHint.EditNextItem) From 8de07590c53a916930013cc1bb67414f2fd29d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 23 Jan 2024 20:10:13 +0300 Subject: [PATCH 332/487] Implement text-like selection for hex view --- PINCE.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/PINCE.py b/PINCE.py index 6ff64d0b..6b92b5f6 100755 --- a/PINCE.py +++ b/PINCE.py @@ -34,7 +34,7 @@ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ - QLocale, QSignalBlocker + QLocale, QSignalBlocker, QItemSelection from typing import Final from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect, json, select @@ -3119,17 +3119,64 @@ def hex_view_selection_changed(self, selected, deselected): other_selection_model = self.tableView_HexView_Ascii.selectionModel() else: other_selection_model = self.tableView_HexView_Hex.selectionModel() + sender_selection = sorted([(idx.row(), idx.column()) for idx in sender_selection_model.selectedIndexes()]) + first_selection = sender_selection[0] + last_selection = sender_selection[-1] + if len(sender_selection) == 1: + self.hex_selection_start = first_selection + self.hex_selection_end = first_selection + else: + # Selection ends in top left + if last_selection == self.hex_selection_start: + self.hex_selection_end = first_selection + # Selection ends in top right + elif last_selection[0] == self.hex_selection_start[0]: + self.hex_selection_end = (first_selection[0], last_selection[1]) + # Selection ends in bottom left + elif last_selection[1] == self.hex_selection_start[1]: + self.hex_selection_end = (last_selection[0], first_selection[1]) + # Selection ends in bottom right + else: + self.hex_selection_end = last_selection + with QSignalBlocker(sender_selection_model), QSignalBlocker(other_selection_model): + sender_selection_model.clearSelection() + other_selection_model.clearSelection() + if self.hex_selection_start < self.hex_selection_end: + start_point = self.hex_selection_start + end_point = self.hex_selection_end + else: + start_point = self.hex_selection_end + end_point = self.hex_selection_start + if start_point[0] == end_point[0]: + start = sender_selection_model.model().index(*start_point) + end = sender_selection_model.model().index(*end_point) + selection = QItemSelection(start, end) + sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + else: + # First line + start = sender_selection_model.model().index(*start_point) + end = sender_selection_model.model().index(start_point[0], HEX_VIEW_COL_COUNT-1) + selection = QItemSelection(start, end) + sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + # Middle + if end_point[0]-start_point[0] > 1: + start = sender_selection_model.model().index(start_point[0]+1, 0) + end = sender_selection_model.model().index(end_point[0]-1, HEX_VIEW_COL_COUNT-1) + selection = QItemSelection(start, end) + sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + # Last line + start = sender_selection_model.model().index(end_point[0], 0) + end = sender_selection_model.model().index(*end_point) + selection = QItemSelection(start, end) + sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) self.tableWidget_HexView_Address.clearSelection() - selected_rows = [] - with QSignalBlocker(other_selection_model): - other_selection_model.clearSelection() - for index in sender_selection_model.selectedIndexes(): - other_selection_model.select(index, QItemSelectionModel.SelectionFlag.Select) - row = index.row() - if row not in selected_rows: - selected_rows.append(row) - self.tableWidget_HexView_Address.selectRow(row) + for row in range(start_point[0], end_point[0]+1): + self.tableWidget_HexView_Address.selectRow(row) self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) self.hex_view_last_selected_address = self.tableView_HexView_Hex.get_selected_address() self.tableView_HexView_Hex.update() From fb592d70daad5ac4adec07a1d6ccd013f7189863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 24 Jan 2024 07:50:42 +0300 Subject: [PATCH 333/487] Fix racing condition between breakpoints and their commands --- PINCE.py | 20 ++++++++++---------- libpince/debugcore.py | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/PINCE.py b/PINCE.py index 6b92b5f6..78e00bbd 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4540,6 +4540,8 @@ def __init__(self, address, length, watchpoint_type, parent=None): self.update_timer = QTimer(timeout=self.update_list) self.stopped = False self.address = address + self.info = {} + self.last_selected_row = 0 if watchpoint_type == typedefs.WATCHPOINT_TYPE.WRITE_ONLY: string = tr.OPCODE_WRITING_TO.format(address) elif watchpoint_type == typedefs.WATCHPOINT_TYPE.READ_ONLY: @@ -4549,13 +4551,11 @@ def __init__(self, address, length, watchpoint_type, parent=None): else: raise Exception("Watchpoint type is invalid: " + str(watchpoint_type)) self.setWindowTitle(string) - breakpoints = debugcore.track_watchpoint(address, length, watchpoint_type) - if not breakpoints: + self.breakpoints = debugcore.track_watchpoint(address, length, watchpoint_type) + if not self.breakpoints: QMessageBox.information(self, tr.ERROR, tr.TRACK_WATCHPOINT_FAILED.format(address)) + self.close() return - self.breakpoints = breakpoints - self.info = {} - self.last_selected_row = 0 self.pushButton_Stop.clicked.connect(self.pushButton_Stop_clicked) self.pushButton_Refresh.clicked.connect(self.update_list) self.tableWidget_Opcodes.itemDoubleClicked.connect(self.tableWidget_Opcodes_item_double_clicked) @@ -4632,16 +4632,16 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.update_values_timer = QTimer(timeout=self.update_values) self.stopped = False self.address = address + self.info = {} + self.last_selected_row = 0 self.setWindowFlags(Qt.WindowType.Window) guiutils.center_to_parent(self) self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) - breakpoint = debugcore.track_breakpoint(address, register_expressions) - if not breakpoint: + self.breakpoint = debugcore.track_breakpoint(address, register_expressions) + if not self.breakpoint: QMessageBox.information(self, tr.ERROR, tr.TRACK_BREAKPOINT_FAILED.format(address)) + self.close() return - self.breakpoint = breakpoint - self.info = {} - self.last_selected_row = 0 guiutils.fill_value_combobox(self.comboBox_ValueType) self.pushButton_Stop.clicked.connect(self.pushButton_Stop_clicked) self.tableWidget_TrackInfo.itemDoubleClicked.connect(self.tableWidget_TrackInfo_item_double_clicked) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 185790d5..6818f37c 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -143,6 +143,13 @@ New parts can try to rely on gdb/mi output ''' +''' +Functions that require breakpoint commands, such as track_watchpoint and track_breakpoint, requires process to be +stopped beforehand. If the process is running before we give the breakpoint its commands, there's a chance that the +breakpoint will be triggered before we give it commands. The process must be stopped to avoid this race condition +It's also necessary to stop the process to run commands like "watch" +''' + #:tag:GDBCommunication def set_gdb_output_mode(output_mode_tuple): @@ -342,13 +349,22 @@ def execute_func_temporary_interruption(func, *args, **kwargs): old_status = inferior_status if old_status == typedefs.INFERIOR_STATUS.RUNNING: interrupt_inferior(typedefs.STOP_REASON.PAUSE) - wait_for_stop() result = func(*args, **kwargs) if old_status == typedefs.INFERIOR_STATUS.RUNNING: continue_inferior() return result +#:tag:GDBCommunication +def execute_with_temporary_interruption(func): + """Decorator version of execute_func_temporary_interruption""" + + def wrapper(*args, **kwargs): + return execute_func_temporary_interruption(func, *args, **kwargs) + + return wrapper + + #:tag:Debug def can_attach(pid): """Check if we can attach to the target @@ -1687,6 +1703,7 @@ def delete_breakpoint(expression): return True +@execute_with_temporary_interruption #:tag:BreakWatchpoints def track_watchpoint(expression, length, watchpoint_type): """Starts tracking a value by setting a watchpoint at the address holding it @@ -1738,6 +1755,7 @@ def get_track_watchpoint_info(watchpoint_list): return output +@execute_with_temporary_interruption #:tag:BreakWatchpoints def track_breakpoint(expression, register_expressions): """Starts tracking a value by setting a breakpoint at the address holding it @@ -1786,6 +1804,7 @@ def get_track_breakpoint_info(breakpoint): return output +@execute_with_temporary_interruption #:tag:Tools def trace_instructions(expression, max_trace_count=1000, trigger_condition="", stop_condition="", step_mode=typedefs.STEP_MODE.SINGLE_STEP, From 2c0d27780f481b0a0047ba1889adfa20b728bd33 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sat, 27 Jan 2024 13:24:30 +0100 Subject: [PATCH 334/487] QoL: click outside freeze checkbox to change freeze type BugFix: Reapply Styling when freeze gets enabled as freeze type is saved but the type indicator in UI is reset --- PINCE.py | 33 ++++++++++++++++++++++++++------- libpince/typedefs.py | 3 ++- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index 78e00bbd..7e32e79f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -880,7 +880,6 @@ def change_freeze_type(self, freeze_type): frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) frozen.freeze_type = freeze_type - # TODO: Create a QWidget subclass with signals so freeze type can be changed by clicking on the cell if freeze_type == typedefs.FREEZE_TYPE.DEFAULT: row.setText(FROZEN_COL, "") row.setForeground(FROZEN_COL, QBrush()) @@ -1620,12 +1619,32 @@ def freeze(self): def treeWidget_AddressTable_item_clicked(self, row, column): if column == FROZEN_COL: - if row.checkState(FROZEN_COL) == Qt.CheckState.Checked: - frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) - frozen.value = row.text(VALUE_COL) - else: - row.setText(FROZEN_COL, "") - row.setForeground(FROZEN_COL, QBrush()) + frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + is_checked = row.checkState(FROZEN_COL) == Qt.CheckState.Checked + is_frozen = frozen.enabled + + frozen_state_toggled = is_checked and not is_frozen or not is_checked and is_frozen + # this helps determine whether the user clicked checkbox or the text + # if the user clicked the text, change the freeze type + + if not frozen_state_toggled and is_checked: + # user clicked the text, iterate through the freeze type + if frozen.freeze_type == typedefs.FREEZE_TYPE.DECREMENT: + # decrement is the last freeze type + self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT) + else: + self.change_freeze_type(frozen.freeze_type + 1) + + if frozen_state_toggled: + if is_checked: + frozen.enabled = True + # reapply the freeze type, to reflect the current freeze type in the UI + # otherwise the UI will show DEFAULT freeze type after enabling instead of the actual type + self.change_freeze_type(frozen.freeze_type) + frozen.value = row.text(VALUE_COL) + else: + frozen.enabled = False # it has just been toggled off + def treeWidget_AddressTable_change_repr(self, new_repr): value_type = guiutils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) diff --git a/libpince/typedefs.py b/libpince/typedefs.py index 7f18fd39..aee294d1 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -397,9 +397,10 @@ def __init__(self, message="GDB not initialized"): class Frozen: - def __init__(self, value, freeze_type): + def __init__(self, value, freeze_type=FREEZE_TYPE.DEFAULT): self.value = value self.freeze_type = freeze_type + self.enabled = False class ValueType: From 0d9a684a43d6cd39b7e2b4368634aee584f3a452 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sat, 27 Jan 2024 13:42:27 +0100 Subject: [PATCH 335/487] QoL: Autoselect Process with Enter if only one Process is found --- PINCE.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PINCE.py b/PINCE.py index 7e32e79f..711ad3d7 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1804,6 +1804,12 @@ def refresh_process_table(self, tablewidget, processlist): # gets the pid out of the selection to attach def pushButton_Open_clicked(self): + index = self.tableWidget_ProcessTable.currentIndex() + row_count = self.tableWidget_ProcessTable.rowCount() + if index.row() == -1 and row_count == 1: + # autoselect first row if there is only one row + self.tableWidget_ProcessTable.setCurrentCell(0, 0) + current_item = self.tableWidget_ProcessTable.item(self.tableWidget_ProcessTable.currentIndex().row(), 0) if current_item is None: QMessageBox.information(self, tr.ERROR, tr.SELECT_PROCESS) From 22faacd7c4bcb8eb5823578c618cd85a77785df7 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sat, 27 Jan 2024 15:43:39 +0100 Subject: [PATCH 336/487] QoL: Press Enter in lineEdit_Scan for Search QoL: Add CTRL+Enter/Return for "New Search" --- PINCE.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 711ad3d7..d878bb91 100755 --- a/PINCE.py +++ b/PINCE.py @@ -555,6 +555,10 @@ def __init__(self): QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan)) self.lineEdit_Scan2.setValidator( QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.keyPressEvent_original = self.lineEdit_Scan.keyPressEvent + self.lineEdit_Scan2.keyPressEvent_original = self.lineEdit_Scan2.keyPressEvent + self.lineEdit_Scan.keyPressEvent = self.lineEdit_Scan_on_key_press_event + self.lineEdit_Scan2.keyPressEvent = self.lineEdit_Scan2_on_key_press_event self.comboBox_ScanType.currentIndexChanged.connect(self.comboBox_ScanType_current_index_changed) self.comboBox_ScanType_current_index_changed() self.pushButton_Settings.clicked.connect(self.pushButton_Settings_clicked) @@ -1154,7 +1158,6 @@ def checkBox_Hex_stateChanged(self, state): self.lineEdit_Scan.setValidator(QRegularExpressionValidator(self.qRegExp_dec, parent=self.lineEdit_Scan)) self.lineEdit_Scan2.setValidator(QRegularExpressionValidator(self.qRegExp_dec, parent=self.lineEdit_Scan2)) - # TODO add a damn keybind for this... def pushButton_NewFirstScan_clicked(self): if debugcore.currentpid == -1: self.comboBox_ScanType_init() @@ -1176,6 +1179,27 @@ def pushButton_NewFirstScan_clicked(self): self.scan_values() self.comboBox_ScanType_init() + def handle_line_edit_scan_key_press_event(self, event): + valid_keys = [Qt.Key.Key_Return, Qt.Key.Key_Enter] + if event.key() in valid_keys and Qt.KeyboardModifier.ControlModifier in event.modifiers(): + self.pushButton_NewFirstScan_clicked() + return + + if event.key() in valid_keys: + if self.scan_mode == typedefs.SCAN_MODE.ONGOING: + self.pushButton_NextScan_clicked() + else: + self.pushButton_NewFirstScan_clicked() + return + + def lineEdit_Scan_on_key_press_event(self, event): + self.handle_line_edit_scan_key_press_event(event) + self.lineEdit_Scan.keyPressEvent_original(event) + + def lineEdit_Scan2_on_key_press_event(self, event): + self.handle_line_edit_scan_key_press_event(event) + self.lineEdit_Scan2.keyPressEvent_original(event) + def pushButton_UndoScan_clicked(self): global threadpool if debugcore.currentpid == -1: From 065bb39e73c38c8919db28b4cedb18d7c2a9cdc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 27 Jan 2024 18:38:18 +0300 Subject: [PATCH 337/487] Set freeze type to default when unfreezed --- PINCE.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index d878bb91..9a0f4db8 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1641,9 +1641,9 @@ def freeze(self): debugcore.write_memory(address, vt.value_index, value, vt.zero_terminate, vt.endian) it += 1 - def treeWidget_AddressTable_item_clicked(self, row, column): + def treeWidget_AddressTable_item_clicked(self, row: QTreeWidgetItem, column: int): if column == FROZEN_COL: - frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + frozen: typedefs.Frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) is_checked = row.checkState(FROZEN_COL) == Qt.CheckState.Checked is_frozen = frozen.enabled @@ -1668,7 +1668,8 @@ def treeWidget_AddressTable_item_clicked(self, row, column): frozen.value = row.text(VALUE_COL) else: frozen.enabled = False # it has just been toggled off - + self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT) + def treeWidget_AddressTable_change_repr(self, new_repr): value_type = guiutils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) From 2f2a79c00ca77dee5210692b6824e18c1d446820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 28 Jan 2024 18:51:24 +0300 Subject: [PATCH 338/487] Fix freeze for float entries --- PINCE.py | 36 +++++++++++++++++------------------- libpince/debugcore.py | 14 +++++++++----- libpince/typedefs.py | 16 ++++++++++++---- libpince/utils.py | 5 ++--- 4 files changed, 40 insertions(+), 31 deletions(-) diff --git a/PINCE.py b/PINCE.py index 9a0f4db8..7cb8776c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1625,18 +1625,17 @@ def freeze(self): while it.value(): row = it.value() if row.checkState(FROZEN_COL) == Qt.CheckState.Checked: - vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) + vt: typedefs.ValueType = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) address = row.text(ADDR_COL).strip("P->") - frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + frozen: typedefs.Frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) value = frozen.value freeze_type = frozen.freeze_type - if typedefs.VALUE_INDEX.is_integer(vt.value_index): + if typedefs.VALUE_INDEX.is_number(vt.value_index): new_value = debugcore.read_memory(address, vt.value_index, endian=vt.endian) - new_value = int(new_value, 0) if isinstance(new_value, str) else new_value - if freeze_type == typedefs.FREEZE_TYPE.INCREMENT and new_value > int(value, 0) or \ - freeze_type == typedefs.FREEZE_TYPE.DECREMENT and new_value < int(value, 0): - frozen.value = str(new_value) - debugcore.write_memory(address, vt.value_index, frozen.value, endian=vt.endian) + if freeze_type == typedefs.FREEZE_TYPE.INCREMENT and new_value > value or \ + freeze_type == typedefs.FREEZE_TYPE.DECREMENT and new_value < value: + frozen.value = new_value + debugcore.write_memory(address, vt.value_index, new_value, endian=vt.endian) continue debugcore.write_memory(address, vt.value_index, value, vt.zero_terminate, vt.endian) it += 1 @@ -1665,7 +1664,8 @@ def treeWidget_AddressTable_item_clicked(self, row: QTreeWidgetItem, column: int # reapply the freeze type, to reflect the current freeze type in the UI # otherwise the UI will show DEFAULT freeze type after enabling instead of the actual type self.change_freeze_type(frozen.freeze_type) - frozen.value = row.text(VALUE_COL) + vt: typedefs.ValueType = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) + frozen.value = utils.parse_string(row.text(VALUE_COL), vt.value_index) else: frozen.enabled = False # it has just been toggled off self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT) @@ -1690,16 +1690,14 @@ def treeWidget_AddressTable_edit_value(self): new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): address = row.text(ADDR_COL).strip("P->") - vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - if typedefs.VALUE_INDEX.has_length(vt.value_index): - unknown_type = utils.parse_string(new_value, vt.value_index) - if unknown_type is not None: - vt.length = len(unknown_type) - row.setText(TYPE_COL, vt.text()) - frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) - frozen.value = new_value - row.setData(FROZEN_COL, Qt.ItemDataRole.UserRole, frozen) - debugcore.write_memory(address, vt.value_index, new_value, vt.zero_terminate, vt.endian) + vt: typedefs.ValueType = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) + parsed_value = utils.parse_string(new_value, vt.value_index) + if typedefs.VALUE_INDEX.has_length(vt.value_index) and parsed_value != None: + vt.length = len(parsed_value) + row.setText(TYPE_COL, vt.text()) + frozen: typedefs.Frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + frozen.value = parsed_value + debugcore.write_memory(address, vt.value_index, parsed_value, vt.zero_terminate, vt.endian) self.update_address_table() def treeWidget_AddressTable_edit_desc(self): diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 6818f37c..c5cc4356 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -903,7 +903,8 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re #:tag:MemoryRW -def write_memory(address, value_index, value, zero_terminate=True, endian=typedefs.ENDIANNESS.HOST): +def write_memory(address: str | int, value_index: int, value: str | int | float | list[int], zero_terminate=True, + endian=typedefs.ENDIANNESS.HOST): """Sets the given value to the given address If any errors occurs while setting value to the according address, it'll be ignored but the information about @@ -912,7 +913,7 @@ def write_memory(address, value_index, value, zero_terminate=True, endian=typede Args: address (str, int): Can be a hex string or an integer value_index (int): Can be a member of typedefs.VALUE_INDEX - value (str): The value that'll be written to the given address + value (str, int, float, list): The value that'll be written to the given address zero_terminate (bool): If True, appends a null byte to the value. Only used when value_index is STRING endian (int): Can be a member of typedefs.ENDIANNESS @@ -927,9 +928,12 @@ def write_memory(address, value_index, value, zero_terminate=True, endian=typede except: # print(str(address) + " is not a valid address") return - write_data = utils.parse_string(value, value_index) - if write_data is None: - return + if isinstance(value, str): + write_data = utils.parse_string(value, value_index) + if write_data is None: + return + else: + write_data = value encoding, option = typedefs.string_index_to_encoding_dict.get(value_index, (None, None)) if encoding is None: if value_index is typedefs.VALUE_INDEX.AOB: diff --git a/libpince/typedefs.py b/libpince/typedefs.py index aee294d1..2fe933e7 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -171,16 +171,24 @@ class VALUE_INDEX: AOB = 10 # Array of Bytes @staticmethod - def is_integer(value_index): + def is_integer(value_index: int): return VALUE_INDEX.INT8 <= value_index <= VALUE_INDEX.INT64 @staticmethod - def is_string(value_index): + def is_float(value_index: int): + return VALUE_INDEX.FLOAT32 <= value_index <= VALUE_INDEX.FLOAT64 + + @staticmethod + def is_number(value_index: int): + return VALUE_INDEX.INT8 <= value_index <= VALUE_INDEX.FLOAT64 + + @staticmethod + def is_string(value_index: int): return VALUE_INDEX.STRING_ASCII <= value_index <= VALUE_INDEX.STRING_UTF32 @staticmethod - def has_length(value_index): - return VALUE_INDEX.STRING_ASCII <= value_index <= VALUE_INDEX.STRING_UTF32 or value_index == VALUE_INDEX.AOB + def has_length(value_index: int): + return VALUE_INDEX.STRING_ASCII <= value_index <= VALUE_INDEX.AOB class SCAN_INDEX: diff --git a/libpince/utils.py b/libpince/utils.py index 5a560b15..728da1f0 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -557,7 +557,7 @@ def get_to_pince_file(pid): #:tag:ValueType -def parse_string(string, value_index): +def parse_string(string: str, value_index: int): """Parses the string according to the given value_index Args: @@ -575,7 +575,6 @@ def parse_string(string, value_index): string="42 DE AD BE EF 24",value_index=typedefs.VALUE_INDEX.AOB--▼ returned_list=[66, 222, 173, 190, 239, 36] """ - string = str(string) if not string: print("please enter a string first") return @@ -599,7 +598,7 @@ def parse_string(string, value_index): except: print(string + " can't be parsed as array of bytes") return - elif value_index == typedefs.VALUE_INDEX.FLOAT32 or value_index == typedefs.VALUE_INDEX.FLOAT64: + elif typedefs.VALUE_INDEX.is_float(value_index): try: string = float(string) except: From e99b33893745e222cd0796604e8c5895ece67594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 29 Jan 2024 17:41:57 +0300 Subject: [PATCH 339/487] Fix region parsing --- libpince/gdb_python_scripts/gdbextensions.py | 2 +- libpince/gdb_python_scripts/gdbutils.py | 39 ++++++++------------ libpince/regexes.py | 2 +- libpince/utils.py | 29 +++++++++------ 4 files changed, 35 insertions(+), 37 deletions(-) diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 089e57a0..063f8b26 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -603,7 +603,7 @@ def invoke(self, arg, from_tty): contents_recv = receive_from_pince() # contents_recv format: [expression1, expression2, ...] - regions = utils.get_regions(pid) + regions = utils.get_region_dict(pid) for expression in contents_recv: result_tuple = gdbutils.examine_expression(expression, regions) data_read_list.append(result_tuple) diff --git a/libpince/gdb_python_scripts/gdbutils.py b/libpince/gdb_python_scripts/gdbutils.py index 70cf2738..2261aad7 100644 --- a/libpince/gdb_python_scripts/gdbutils.py +++ b/libpince/gdb_python_scripts/gdbutils.py @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import gdb, sys, os, traceback, functools +import gdb, sys, traceback, functools from collections import OrderedDict # This is some retarded hack @@ -23,15 +23,10 @@ GDBINIT_AA_PATH = gdb.parse_and_eval("$GDBINIT_AA_PATH").string() sys.path.append(PINCE_PATH) # Adds the PINCE directory to PYTHONPATH to import libraries from PINCE -from libpince import utils, typedefs, regexes +from libpince import typedefs, regexes inferior = gdb.selected_inferior() -pid = inferior.pid -if pid == 0: - pid = -1 - inferior_name = "" -else: - inferior_name = utils.get_process_name(pid) +pid = -1 if inferior.pid == 0 else inferior.pid mem_file = "/proc/" + str(pid) + "/mem" void_ptr = gdb.lookup_type("void").pointer() @@ -118,7 +113,7 @@ def get_float_registers(): return contents_send -def examine_expression(expression, regions=None): +def examine_expression(expression: str, regions=None): try: value = gdb.parse_and_eval(expression).cast(void_ptr) except Exception as e: @@ -135,21 +130,17 @@ def examine_expression(expression, regions=None): index = int(index.group(1)) else: index = 0 - count = 0 - if expression == inferior_name or regexes.file_with_extension.search(expression): - for address, _, _, _, _, _, path in regions: - file_name = os.path.split(path)[1] - if expression in file_name: - if index == count: - address = "0x"+address - try: - address = hex(eval(address+offset)) - except Exception as e: - print(e) - return typedefs.tuple_examine_expression(None, None, None) - return typedefs.tuple_examine_expression(address+file_name, address, file_name) - else: - count += 1 + if expression in regions: + start_address_list = regions[expression] + if len(start_address_list) > index: + address = start_address_list[index] + try: + address = hex(eval(address+offset)) + except Exception as e: + print(e) + return typedefs.tuple_examine_expression(None, None, None) + return typedefs.tuple_examine_expression(f"{address} {expression}", address, expression) + return typedefs.tuple_examine_expression(None, None, None) print(e) return typedefs.tuple_examine_expression(None, None, None) result = regexes.address_with_symbol.search(str(value)) diff --git a/libpince/regexes.py b/libpince/regexes.py index 32751ebc..9bf660bf 100644 --- a/libpince/regexes.py +++ b/libpince/regexes.py @@ -79,6 +79,6 @@ trace_instructions_call = compile(r":\s+call") # 0x7f71a4dc5fe4 : call 0x7f71a4de1100 dissect_code_valid_address = compile(r"(\s+|\[|,)" + hex_number.pattern + "(\s+|\]|,|$)") alphanumerics = compile(r"\w+") -file_with_extension = compile(r".+\.\w+") +file_with_extension = compile(r".+?\.\w+") offset_expression = compile(r"[/*+\-][0-9a-fA-FxX/*+\-\[\]]+$") index = compile(r"\[(\d+)\]$") diff --git a/libpince/utils.py b/libpince/utils.py index 728da1f0..94f25550 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -91,27 +91,34 @@ def get_regions(pid): #:tag:Processes -def get_region_set(pid): - """Returns memory regions of a process, removes path duplicates and empty paths +def get_region_dict(pid: int) -> dict[str, list[str]]: + """Returns memory regions of a process as a dictionary where key is the path tail and value is the list of the + corresponding start addresses of the tail, empty paths will be ignored. Also adds shortcuts for file extensions, + returned dict will include both sonames, with and without version information Args: pid (int): PID of the process Returns: - list: List of (start_address, file_name) -> (str, str) + dict: {file_name:start_address_list} """ - region_set = [] - current_file = "" + region_dict: dict[str, list[str]] = {} for item in get_regions(pid): start_addr, _, _, _, _, _, path = item if not path: continue - head, tail = os.path.split(path) - if not head or tail == current_file: - continue - current_file = tail - region_set.append(("0x"+start_addr, tail)) - return region_set + _, tail = os.path.split(path) + start_addr = "0x"+start_addr + short_name = regexes.file_with_extension.search(tail) + if tail in region_dict: + region_dict[tail].append(start_addr) + if short_name: + region_dict[short_name.group(0)].append(start_addr) + else: + region_dict[tail] = [start_addr] + if short_name: + region_dict[short_name.group(0)] = [start_addr] + return region_dict #:tag:Processes From 9cb0338475e0b7a332a3f5b94da2bfb7dac645a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 1 Feb 2024 18:42:34 +0300 Subject: [PATCH 340/487] Extend multi selection functionality --- GUI/TableViews/HexView.py | 14 +-- PINCE.py | 247 ++++++++++++++++++++------------------ i18n/ts/it_IT.ts | 15 --- i18n/ts/zh_CN.ts | 15 --- libpince/debugcore.py | 43 +++---- tr/tr.py | 3 - 6 files changed, 153 insertions(+), 184 deletions(-) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index 96063daa..20a4529e 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt6.QtGui import QKeyEvent +from PyQt6.QtGui import QKeyEvent, QWheelEvent from PyQt6.QtWidgets import QTableView, QAbstractItemView from PyQt6.QtCore import Qt from GUI.ItemDelegates.HexDelegate import QHexDelegate @@ -42,8 +42,8 @@ def __init__(self, parent=None): self.delegate.closeEditor.connect(self.on_editor_close) self.setItemDelegate(self.delegate) - def wheelEvent(self, QWheelEvent): - QWheelEvent.ignore() + def wheelEvent(self, event: QWheelEvent): + event.ignore() def keyPressEvent(self, event: QKeyEvent): if event.key() == Qt.Key.Key_Return and self.state() != QAbstractItemView.State.EditingState: @@ -56,14 +56,6 @@ def resize_to_contents(self): self.setMinimumWidth(size) self.setMaximumWidth(size) - def get_selected_address(self): - cell = self.currentIndex() - model: QHexModel = self.model() - current_address = model.current_address - if cell: - current_address = current_address + cell.row() * model.columnCount() + cell.column() - return utils.modulo_address(current_address, debugcore.inferior_arch) - def on_editor_close(self): model: QHexModel = self.model() cell = self.currentIndex() diff --git a/PINCE.py b/PINCE.py index 7cb8776c..7dfcd304 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1881,7 +1881,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() try: - length = str(length) + length = str(vt.length) except: length = "10" self.lineEdit_Length.setText(length) @@ -1890,7 +1890,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.AOB: self.widget_Length.show() try: - length = str(length) + length = str(vt.length) except: length = "10" self.lineEdit_Length.setText(length) @@ -2108,7 +2108,7 @@ def __init__(self, parent=None, value_type=None): if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): self.widget_Length.show() try: - length = str(length) + length = str(vt.length) except: length = "10" self.lineEdit_Length.setText(length) @@ -2117,7 +2117,7 @@ def __init__(self, parent=None, value_type=None): elif self.comboBox_ValueType.currentIndex() == typedefs.VALUE_INDEX.AOB: self.widget_Length.show() try: - length = str(length) + length = str(vt.length) except: length = "10" self.lineEdit_Length.setText(length) @@ -2896,7 +2896,12 @@ def initialize_disassemble_view(self): self.tableWidget_Disassemble.itemSelectionChanged.connect(self.tableWidget_Disassemble_item_selection_changed) def initialize_hex_view(self): - self.hex_view_last_selected_address = 0 + # Determines where selection starts and ends + self.hex_selection_start = 0 + self.hex_selection_end = 0 + # Actual start and end addresses of the selection + self.hex_selection_address_begin = 0 + self.hex_selection_address_end = 0 self.hex_view_current_region = typedefs.tuple_region_info(0, 0, None, None) self.hex_model = QHexModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) self.ascii_model = QAsciiModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) @@ -2989,31 +2994,23 @@ def toggle_breakpoint(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) - if debugcore.check_address_in_breakpoints(current_address_int): + if debugcore.get_breakpoints_in_range(current_address_int): debugcore.delete_breakpoint(current_address) else: if not debugcore.add_breakpoint(current_address): QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_FAILED.format(current_address)) self.refresh_disassemble_view() - def toggle_watchpoint(self, address, watchpoint_type=typedefs.WATCHPOINT_TYPE.BOTH): + def toggle_watchpoint(self, address, length, watchpoint_type=typedefs.WATCHPOINT_TYPE.BOTH): if debugcore.currentpid == -1: return - if debugcore.check_address_in_breakpoints(address): - debugcore.delete_breakpoint(hex(address)) + breakpoints = debugcore.get_breakpoints_in_range(address, length) + if not breakpoints: + if len(debugcore.add_watchpoint(hex(address), length, watchpoint_type)) < 1: + QMessageBox.information(self, tr.ERROR, tr.WATCHPOINT_FAILED.format(hex(address))) else: - watchpoint_dialog = InputDialogForm(item_list=[(tr.ENTER_WATCHPOINT_LENGTH, "")]) - if watchpoint_dialog.exec(): - user_input = watchpoint_dialog.get_values() - user_input_int = utils.parse_string(user_input, typedefs.VALUE_INDEX.INT32) - if user_input_int is None: - QMessageBox.information(self, tr.ERROR, tr.PARSE_ERROR_INT.format(user_input)) - return - if user_input_int < 1: - QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_ASSERT_LT.format(1)) - return - if len(debugcore.add_watchpoint(hex(address), user_input_int, watchpoint_type)) < 1: - QMessageBox.information(self, tr.ERROR, tr.WATCHPOINT_FAILED.format(hex(address))) + for bp in breakpoints: + debugcore.delete_breakpoint(bp.address) self.refresh_hex_view() def label_HexView_Information_context_menu_event(self, event): @@ -3039,7 +3036,8 @@ def copy_to_clipboard(): def widget_HexView_context_menu_event(self, event): if debugcore.currentpid == -1: return - selected_address = self.tableView_HexView_Hex.get_selected_address() + addr = self.hex_selection_address_begin + length = self.get_hex_selection_length() menu = QMenu() edit = menu.addAction(tr.EDIT) menu.addSeparator() @@ -3056,7 +3054,7 @@ def widget_HexView_context_menu_event(self, event): watchpoint_both = watchpoint_menu.addAction(tr.BOTH) add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) delete_breakpoint = menu.addAction(tr.DELETE_BREAKPOINT) - if not debugcore.check_address_in_breakpoints(selected_address): + if not debugcore.get_breakpoints_in_range(addr, length): guiutils.delete_menu_entries(menu, [add_condition, delete_breakpoint]) else: guiutils.delete_menu_entries(menu, [watchpoint_menu.menuAction()]) @@ -3066,14 +3064,14 @@ def widget_HexView_context_menu_event(self, event): actions = { edit: self.exec_hex_view_edit_dialog, go_to: self.exec_hex_view_go_to_dialog, - disassemble: lambda: self.disassemble_expression(hex(selected_address), append_to_travel_history=True), + disassemble: lambda: self.disassemble_expression(hex(addr), append_to_travel_history=True), add_address: self.exec_hex_view_add_address_dialog, refresh: self.refresh_hex_view, - watchpoint_write: lambda: self.toggle_watchpoint(selected_address, typedefs.WATCHPOINT_TYPE.WRITE_ONLY), - watchpoint_read: lambda: self.toggle_watchpoint(selected_address, typedefs.WATCHPOINT_TYPE.READ_ONLY), - watchpoint_both: lambda: self.toggle_watchpoint(selected_address, typedefs.WATCHPOINT_TYPE.BOTH), - add_condition: lambda: self.add_breakpoint_condition(selected_address), - delete_breakpoint: lambda: self.toggle_watchpoint(selected_address) + watchpoint_write: lambda: self.toggle_watchpoint(addr, length, typedefs.WATCHPOINT_TYPE.WRITE_ONLY), + watchpoint_read: lambda: self.toggle_watchpoint(addr, length, typedefs.WATCHPOINT_TYPE.READ_ONLY), + watchpoint_both: lambda: self.toggle_watchpoint(addr, length, typedefs.WATCHPOINT_TYPE.BOTH), + add_condition: lambda: self.add_breakpoint_condition(addr, length), + delete_breakpoint: lambda: self.toggle_watchpoint(addr, length) } try: actions[action]() @@ -3083,15 +3081,13 @@ def widget_HexView_context_menu_event(self, event): def exec_hex_view_edit_dialog(self): if debugcore.currentpid == -1: return - selected_address = self.tableView_HexView_Hex.get_selected_address() - HexEditDialogForm(hex(selected_address)).exec() + HexEditDialogForm(self.hex_selection_address_begin, self.get_hex_selection_length()).exec() self.refresh_hex_view() def exec_hex_view_go_to_dialog(self): if debugcore.currentpid == -1: return - current_address = hex(self.tableView_HexView_Hex.get_selected_address()) - go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, current_address)]) + go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, hex(self.hex_selection_address_begin))]) if go_to_dialog.exec(): expression = go_to_dialog.get_values() dest_address = debugcore.examine_expression(expression).address @@ -3103,9 +3099,8 @@ def exec_hex_view_go_to_dialog(self): def exec_hex_view_add_address_dialog(self): if debugcore.currentpid == -1: return - selected_address = self.tableView_HexView_Hex.get_selected_address() - vt = typedefs.ValueType(typedefs.VALUE_INDEX.AOB) - manual_address_dialog = ManualAddressDialogForm(address=hex(selected_address), value_type=vt) + vt = typedefs.ValueType(typedefs.VALUE_INDEX.AOB, self.get_hex_selection_length()) + manual_address_dialog = ManualAddressDialogForm(address=hex(self.hex_selection_address_begin), value_type=vt) if manual_address_dialog.exec(): desc, address, vt = manual_address_dialog.get_values() self.parent().add_entry_to_addresstable(desc, address, vt) @@ -3163,74 +3158,104 @@ def disassemble_scrollbar_sliderchanged(self, even): def hex_view_selection_changed(self, selected, deselected): sender_selection_model: QItemSelectionModel = self.sender() - if sender_selection_model == self.tableView_HexView_Hex.selectionModel(): - other_selection_model = self.tableView_HexView_Ascii.selectionModel() - else: - other_selection_model = self.tableView_HexView_Hex.selectionModel() sender_selection = sorted([(idx.row(), idx.column()) for idx in sender_selection_model.selectedIndexes()]) first_selection = sender_selection[0] last_selection = sender_selection[-1] + hex_start = self.address_to_hex_point(self.hex_selection_start) + hex_end = self.address_to_hex_point(self.hex_selection_end) + hex_start, hex_end = self.fix_selection_at_borders(hex_start, hex_end) if len(sender_selection) == 1: - self.hex_selection_start = first_selection - self.hex_selection_end = first_selection + hex_start = first_selection + hex_end = first_selection else: # Selection ends in top left - if last_selection == self.hex_selection_start: - self.hex_selection_end = first_selection + if last_selection == hex_start: + hex_end = first_selection # Selection ends in top right - elif last_selection[0] == self.hex_selection_start[0]: - self.hex_selection_end = (first_selection[0], last_selection[1]) + elif last_selection[0] == hex_start[0]: + hex_end = (first_selection[0], last_selection[1]) # Selection ends in bottom left - elif last_selection[1] == self.hex_selection_start[1]: - self.hex_selection_end = (last_selection[0], first_selection[1]) + elif last_selection[1] == hex_start[1]: + hex_end = (last_selection[0], first_selection[1]) # Selection ends in bottom right else: - self.hex_selection_end = last_selection - with QSignalBlocker(sender_selection_model), QSignalBlocker(other_selection_model): - sender_selection_model.clearSelection() - other_selection_model.clearSelection() - if self.hex_selection_start < self.hex_selection_end: - start_point = self.hex_selection_start - end_point = self.hex_selection_end - else: - start_point = self.hex_selection_end - end_point = self.hex_selection_start - if start_point[0] == end_point[0]: - start = sender_selection_model.model().index(*start_point) - end = sender_selection_model.model().index(*end_point) - selection = QItemSelection(start, end) - sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - else: - # First line - start = sender_selection_model.model().index(*start_point) - end = sender_selection_model.model().index(start_point[0], HEX_VIEW_COL_COUNT-1) - selection = QItemSelection(start, end) - sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - # Middle - if end_point[0]-start_point[0] > 1: - start = sender_selection_model.model().index(start_point[0]+1, 0) - end = sender_selection_model.model().index(end_point[0]-1, HEX_VIEW_COL_COUNT-1) + hex_end = last_selection + if hex_start < hex_end: + address_begin = hex_start + address_end = hex_end + else: + address_begin = hex_end + address_end = hex_start + self.hex_selection_start = self.hex_point_to_address(hex_start) + self.hex_selection_end = self.hex_point_to_address(hex_end) + self.hex_selection_address_begin = self.hex_point_to_address(address_begin) + self.hex_selection_address_end = self.hex_point_to_address(address_end) + self.handle_hex_selection() + + def handle_hex_selection(self): + hex_selection_model = self.tableView_HexView_Hex.selectionModel() + ascii_selection_model = self.tableView_HexView_Ascii.selectionModel() + start_point = self.address_to_hex_point(self.hex_selection_address_begin) + end_point = self.address_to_hex_point(self.hex_selection_address_end) + with QSignalBlocker(hex_selection_model), QSignalBlocker(ascii_selection_model): + hex_selection_model.clearSelection() + ascii_selection_model.clearSelection() + self.tableWidget_HexView_Address.clearSelection() + if start_point or end_point: + start_point, end_point = self.fix_selection_at_borders(start_point, end_point) + if start_point[0] == end_point[0]: + start = hex_selection_model.model().index(*start_point) + end = hex_selection_model.model().index(*end_point) selection = QItemSelection(start, end) - sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - # Last line - start = sender_selection_model.model().index(end_point[0], 0) - end = sender_selection_model.model().index(*end_point) - selection = QItemSelection(start, end) - sender_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - other_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) - self.tableWidget_HexView_Address.clearSelection() - for row in range(start_point[0], end_point[0]+1): - self.tableWidget_HexView_Address.selectRow(row) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) - self.hex_view_last_selected_address = self.tableView_HexView_Hex.get_selected_address() + hex_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + ascii_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + else: + # First line + start = hex_selection_model.model().index(*start_point) + end = hex_selection_model.model().index(start_point[0], HEX_VIEW_COL_COUNT-1) + selection = QItemSelection(start, end) + hex_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + ascii_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + # Middle + if end_point[0]-start_point[0] > 1: + start = hex_selection_model.model().index(start_point[0]+1, 0) + end = hex_selection_model.model().index(end_point[0]-1, HEX_VIEW_COL_COUNT-1) + selection = QItemSelection(start, end) + hex_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + ascii_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + # Last line + start = hex_selection_model.model().index(end_point[0], 0) + end = hex_selection_model.model().index(*end_point) + selection = QItemSelection(start, end) + hex_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + ascii_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) + for row in range(start_point[0], end_point[0]+1): + self.tableWidget_HexView_Address.selectRow(row) + self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) self.tableView_HexView_Hex.update() self.tableView_HexView_Ascii.update() self.tableWidget_HexView_Address.update() + def hex_point_to_address(self, point): + address = self.hex_model.current_address+point[0]*HEX_VIEW_COL_COUNT+point[1] + return utils.modulo_address(address, debugcore.inferior_arch) + + def address_to_hex_point(self, address): + diff = address-self.hex_model.current_address + if 0 <= diff < HEX_VIEW_ROW_COUNT*HEX_VIEW_COL_COUNT: + return diff//HEX_VIEW_COL_COUNT, diff % HEX_VIEW_COL_COUNT + + def get_hex_selection_length(self): + return self.hex_selection_address_end-self.hex_selection_address_begin+1 + + def fix_selection_at_borders(self, start_point, end_point): + if not start_point: + start_point = (0, 0) + if not end_point: + end_point = (HEX_VIEW_ROW_COUNT-1, HEX_VIEW_COL_COUNT-1) + return start_point, end_point + def hex_update_loop(self): if debugcore.currentpid == -1 or exiting: return @@ -3268,22 +3293,7 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL breakpoint_info = debugcore.get_breakpoint_info() self.hex_model.refresh(int_address, offset, data_array, breakpoint_info) self.ascii_model.refresh(int_address, offset, data_array, breakpoint_info) - for index in range(offset): - current_address = utils.modulo_address(self.hex_model.current_address + index, debugcore.inferior_arch) - if current_address == self.hex_view_last_selected_address: - row_index = int(index / HEX_VIEW_COL_COUNT) - model_index = QModelIndex(self.hex_model.index(row_index, index % HEX_VIEW_COL_COUNT)) - self.tableView_HexView_Hex.selectionModel().setCurrentIndex(model_index, - QItemSelectionModel.SelectionFlag.ClearAndSelect) - self.tableView_HexView_Ascii.selectionModel().setCurrentIndex(model_index, - QItemSelectionModel.SelectionFlag.ClearAndSelect) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) - self.tableWidget_HexView_Address.selectRow(row_index) - self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) - break - else: - self.tableView_HexView_Hex.clearSelection() - self.tableView_HexView_Ascii.clearSelection() + self.handle_hex_selection() def refresh_hex_view(self): if debugcore.currentpid == -1: @@ -3509,21 +3519,22 @@ def on_process_stop(self): def on_process_running(self): self.setWindowTitle(tr.MV_RUNNING) - def add_breakpoint_condition(self, int_address): + def add_breakpoint_condition(self, int_address, length=1): if debugcore.currentpid == -1: return - breakpoint = debugcore.check_address_in_breakpoints(int_address) - if breakpoint: - condition_line_edit_text = breakpoint.condition + breakpoints = debugcore.get_breakpoints_in_range(int_address, length) + if breakpoints: + condition_line_edit_text = breakpoints[0].condition else: condition_line_edit_text = "" condition_dialog = InputDialogForm( item_list=[(tr.ENTER_BP_CONDITION, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) if condition_dialog.exec(): condition = condition_dialog.get_values() - if not debugcore.modify_breakpoint(hex(int_address), typedefs.BREAKPOINT_MODIFY.CONDITION, - condition=condition): - QMessageBox.information(app.focusWidget(), tr.ERROR, tr.BP_CONDITION_FAILED.format(hex(int_address))) + for bp in breakpoints: + addr = bp.address + if not debugcore.modify_breakpoint(addr, typedefs.BREAKPOINT_MODIFY.CONDITION, condition): + QMessageBox.information(app.focusWidget(), tr.ERROR, tr.BP_CONDITION_FAILED.format(addr)) def update_registers(self): if debugcore.currentpid == -1: @@ -3800,12 +3811,10 @@ def widget_HexView_wheel_event(self, event): def widget_HexView_key_press_event(self, event): if debugcore.currentpid == -1: return - selected_address = self.tableView_HexView_Hex.get_selected_address() - actions = typedefs.KeyboardModifiersTupleDict([ (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_hex_view_go_to_dialog), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), - lambda: self.disassemble_expression(hex(selected_address), append_to_travel_history=True)), + lambda: self.disassemble_expression(hex(self.hex_selection_address_begin), append_to_travel_history=True)), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_A), self.exec_hex_view_add_address_dialog), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_hex_view), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.hex_view_scroll_up), @@ -3935,7 +3944,7 @@ def copy_all_columns(row): menu.addSeparator() toggle_breakpoint = menu.addAction(f"{tr.TOGGLE_BREAKPOINT}[F5]") add_condition = menu.addAction(tr.CHANGE_BREAKPOINT_CONDITION) - if not debugcore.check_address_in_breakpoints(current_address_int): + if not debugcore.get_breakpoints_in_range(current_address_int): guiutils.delete_menu_entries(menu, [add_condition]) menu.addSeparator() edit_instruction = menu.addAction(tr.EDIT_INSTRUCTION) @@ -5139,12 +5148,12 @@ def accept(self): class HexEditDialogForm(QDialog, HexEditDialog): - def __init__(self, address, parent=None): + def __init__(self, address, length=20, parent=None): super().__init__(parent=parent) self.setupUi(self) self.lineEdit_Length.setValidator(QHexValidator(999, self)) - self.lineEdit_Address.setText(address) - self.lineEdit_Length.setText("20") + self.lineEdit_Address.setText(hex(address)) + self.lineEdit_Length.setText(str(length)) self.refresh_view() self.lineEdit_AsciiView.selectionChanged.connect(self.lineEdit_AsciiView_selection_changed) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index e32798f0..eb8df502 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1868,21 +1868,6 @@ Changing output mode only affects commands sent. Any other output coming from ex Failed to set breakpoint at address {} - - - Enter the watchpoint length in size of bytes - - - - - {} can't be parsed as an integer - - - - - Breakpoint length can't be lower than {} - - Failed to set watchpoint at address {} diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index aa062e80..98b4230f 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1897,21 +1897,6 @@ pince-execute-from-so-file lib.func(params):运行 lib 中的一个函数 Failed to set breakpoint at address {} 在地址 {} 处设置断点失败 - - - Enter the watchpoint length in size of bytes - 输入监视点长度,以字节为单位 - - - - {} can't be parsed as an integer - {} 无法解析为整数 - - - - Breakpoint length can't be lower than {} - 断点长度不能小于 {} - Failed to set watchpoint at address {} diff --git a/libpince/debugcore.py b/libpince/debugcore.py index c5cc4356..32651a2d 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1392,7 +1392,7 @@ def restore_instruction(start_address): #:tag:BreakWatchpoints -def get_breakpoint_info(): +def get_breakpoint_info() -> list[typedefs.tuple_breakpoint_info]: """Returns current breakpoint/watchpoint list Returns: @@ -1452,27 +1452,28 @@ def get_breakpoint_info(): #:tag:BreakWatchpoints -def check_address_in_breakpoints(address, range_offset=0): +def get_breakpoints_in_range(address: str | int, length: int = 1) -> list[typedefs.tuple_breakpoint_info]: """Checks if given address exists in breakpoint list Args: - address (int,str): Hex address or an int - range_offset (int): If this parameter is different than 0, the range between address and address+offset is - checked instead of just address itself + address (str,int): Start address of the range, hex address or an int + length (int): If this parameter is bigger than 1, the range between address and address+length-1 will be + checked instead of just the address itself Returns: - typedefs.tuple_breakpoint_info: Info of the existing breakpoint for given address range - None: If it doesn't exist + list: A list of typedefs.tuple_breakpoint_info, info of the existing breakpoints for given address range """ + breakpoint_list = [] if type(address) != int: address = int(address, 0) - max_address = max(address, address + range_offset) - min_address = min(address, address + range_offset) + max_address = max(address, address+length-1) + min_address = min(address, address+length-1) breakpoint_info = get_breakpoint_info() for item in breakpoint_info: breakpoint_address = int(item.address, 16) - if not (max_address < breakpoint_address or min_address > breakpoint_address + item.size - 1): - return item + if not (max_address < breakpoint_address or min_address > breakpoint_address+item.size-1): + breakpoint_list.append(item) + return breakpoint_list #:tag:BreakWatchpoints @@ -1516,7 +1517,7 @@ def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE if not str_address: print("expression for breakpoint is not valid") return - if check_address_in_breakpoints(str_address): + if get_breakpoints_in_range(str_address): print("breakpoint/watchpoint for address " + str_address + " is already set") return if breakpoint_type == typedefs.BREAKPOINT_TYPE.HARDWARE: @@ -1570,16 +1571,16 @@ def add_watchpoint(expression, length=4, watchpoint_type=typedefs.WATCHPOINT_TYP else: max_length = 4 while remaining_length > 0: - if check_address_in_breakpoints(str_address_int): + if remaining_length >= max_length: + breakpoint_length = max_length + else: + breakpoint_length = remaining_length + if get_breakpoints_in_range(str_address_int, breakpoint_length): print("breakpoint/watchpoint for address " + hex(str_address_int) + " is already set. Bailing out...") break if not hardware_breakpoint_available(): print("All hardware breakpoint slots are being used, unable to set a new watchpoint. Bailing out...") break - if remaining_length >= max_length: - breakpoint_length = max_length - else: - breakpoint_length = remaining_length cmd = f"{watch_command} * (char[{breakpoint_length}] *) {hex(str_address_int)}" output = execute_func_temporary_interruption(send_command, cmd) if regexes.breakpoint_created.search(output): @@ -1635,12 +1636,12 @@ def modify_breakpoint(expression, modify_what, condition=None, count=None): modification_list = item break for breakpoint in modification_list: - found_breakpoint = check_address_in_breakpoints(breakpoint[0]) + found_breakpoint = get_breakpoints_in_range(breakpoint[0]) if not found_breakpoint: print("no such breakpoint exists for address " + str_address) continue else: - breakpoint_number = found_breakpoint.number + breakpoint_number = found_breakpoint[0].number if modify_what == typedefs.BREAKPOINT_MODIFY.CONDITION: if condition is None: print("Please set condition first") @@ -1692,12 +1693,12 @@ def delete_breakpoint(expression): del chained_breakpoints[n] break for breakpoint in deletion_list: - found_breakpoint = check_address_in_breakpoints(breakpoint[0]) + found_breakpoint = get_breakpoints_in_range(breakpoint[0]) if not found_breakpoint: print("no such breakpoint exists for address " + str_address) continue else: - breakpoint_number = found_breakpoint.number + breakpoint_number = found_breakpoint[0].number global breakpoint_on_hit_dict try: del breakpoint_on_hit_dict[breakpoint_number] diff --git a/tr/tr.py b/tr/tr.py index a8a9371c..26e4074f 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -161,9 +161,6 @@ def translate(): RUN = QT_TR_NOOP("Run[{}]") TOGGLE_ATTACH = QT_TR_NOOP("Toggle Attach[{}]") BREAKPOINT_FAILED = QT_TR_NOOP("Failed to set breakpoint at address {}") - ENTER_WATCHPOINT_LENGTH = QT_TR_NOOP("Enter the watchpoint length in size of bytes") - PARSE_ERROR_INT = QT_TR_NOOP("{} can't be parsed as an integer") - BREAKPOINT_ASSERT_LT = QT_TR_NOOP("Breakpoint length can't be lower than {}") WATCHPOINT_FAILED = QT_TR_NOOP("Failed to set watchpoint at address {}") COPY_CLIPBOARD = QT_TR_NOOP("Copy to Clipboard") GO_TO_EXPRESSION = QT_TR_NOOP("Go to expression") From 221a0dd68fbe873dfae714f8ad7deecce9eb3bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 1 Feb 2024 19:16:51 +0300 Subject: [PATCH 341/487] Fix duplicates in get_region_dict --- libpince/utils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libpince/utils.py b/libpince/utils.py index 94f25550..2a0b6af4 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -110,14 +110,18 @@ def get_region_dict(pid: int) -> dict[str, list[str]]: _, tail = os.path.split(path) start_addr = "0x"+start_addr short_name = regexes.file_with_extension.search(tail) + if short_name: + short_name = short_name.group(0) + if short_name == tail: + short_name = None if tail in region_dict: region_dict[tail].append(start_addr) if short_name: - region_dict[short_name.group(0)].append(start_addr) + region_dict[short_name].append(start_addr) else: region_dict[tail] = [start_addr] if short_name: - region_dict[short_name.group(0)] = [start_addr] + region_dict[short_name] = [start_addr] return region_dict From 6a7b6dab741429d0def0b39a82d56747bc1868e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 3 Feb 2024 12:30:03 +0300 Subject: [PATCH 342/487] Add copy action to hex view --- PINCE.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/PINCE.py b/PINCE.py index 7dfcd304..bace757c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3046,6 +3046,7 @@ def widget_HexView_context_menu_event(self, event): menu.addSeparator() add_address = menu.addAction(f"{tr.ADD_TO_ADDRESS_LIST}[Ctrl+A]") menu.addSeparator() + copy_selection = menu.addAction(f"{tr.COPY}[Ctrl+C]") refresh = menu.addAction(f"{tr.REFRESH}[R]") menu.addSeparator() watchpoint_menu = menu.addMenu(tr.SET_WATCHPOINT) @@ -3066,6 +3067,7 @@ def widget_HexView_context_menu_event(self, event): go_to: self.exec_hex_view_go_to_dialog, disassemble: lambda: self.disassemble_expression(hex(addr), append_to_travel_history=True), add_address: self.exec_hex_view_add_address_dialog, + copy_selection: self.copy_hex_view_selection, refresh: self.refresh_hex_view, watchpoint_write: lambda: self.toggle_watchpoint(addr, length, typedefs.WATCHPOINT_TYPE.WRITE_ONLY), watchpoint_read: lambda: self.toggle_watchpoint(addr, length, typedefs.WATCHPOINT_TYPE.READ_ONLY), @@ -3106,6 +3108,14 @@ def exec_hex_view_add_address_dialog(self): self.parent().add_entry_to_addresstable(desc, address, vt) self.parent().update_address_table() + def copy_hex_view_selection(self): + data = debugcore.hex_dump(self.hex_selection_address_begin, self.get_hex_selection_length()) + if self.focusWidget() == self.tableView_HexView_Ascii: + display_text = utils.aob_to_str(data) + else: + display_text = " ".join(data) + app.clipboard().setText(display_text) + def hex_view_scroll_up(self): self.verticalScrollBar_HexView.setValue(1) @@ -3816,6 +3826,7 @@ def widget_HexView_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), lambda: self.disassemble_expression(hex(self.hex_selection_address_begin), append_to_travel_history=True)), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_A), self.exec_hex_view_add_address_dialog), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_hex_view_selection), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_hex_view), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.hex_view_scroll_up), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.hex_view_scroll_down), From 2f1283e83ba840c7a33829af18ceaf048b9737fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 3 Feb 2024 13:42:11 +0300 Subject: [PATCH 343/487] Change hex view behavior when process dies --- GUI/AbstractTableModels/HexModel.py | 2 +- PINCE.py | 7 ++++--- libpince/utils.py | 4 ---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/GUI/AbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py index 7dc8f30a..42ee96cf 100644 --- a/GUI/AbstractTableModels/HexModel.py +++ b/GUI/AbstractTableModels/HexModel.py @@ -22,12 +22,12 @@ class QHexModel(QAbstractTableModel): def __init__(self, row_count, column_count, parent=None): super().__init__(parent) - self.data_array = [] self.breakpoint_list = set() self.row_count = row_count self.column_count = column_count self.current_address = 0 offset = row_count*column_count + self.data_array = ["??"]*offset self.cell_animation = [0]*offset self.cell_change_color = QColor(QColorConstants.Red) self.breakpoint_color = QColor(QColorConstants.Green) diff --git a/PINCE.py b/PINCE.py index bace757c..c1bf02b0 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3267,10 +3267,11 @@ def fix_selection_at_borders(self, start_point, end_point): return start_point, end_point def hex_update_loop(self): - if debugcore.currentpid == -1 or exiting: - return offset = HEX_VIEW_ROW_COUNT*HEX_VIEW_COL_COUNT - updated_array = debugcore.hex_dump(self.hex_model.current_address, offset) + if debugcore.currentpid == -1 or exiting: + updated_array = ["??"]*offset + else: + updated_array = debugcore.hex_dump(self.hex_model.current_address, offset) self.hex_model.update_loop(updated_array) self.ascii_model.update_loop(updated_array) diff --git a/libpince/utils.py b/libpince/utils.py index 2a0b6af4..2c57e61f 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -758,9 +758,6 @@ def aob_to_str(list_of_bytes, encoding="ascii"): else: byteList = [] byteList.append(list_of_bytes) - - newByte=0 - for sByte in byteList: if (sByte == "??"): hexString += f'{63:02x}' # replace ?? with a single ? @@ -781,7 +778,6 @@ def aob_to_str(list_of_bytes, encoding="ascii"): # hexString += f'{46:02x}' # replace non-printable chars with a period (.) #else: hexString += f'{byte:02x}' - hexBytes=bytes.fromhex(hexString) return hexBytes.decode(encoding, "surrogateescape") From 09181d9e364dd5dd443d5240441eaba4ed5acfe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 3 Feb 2024 15:59:00 +0300 Subject: [PATCH 344/487] Fixed a race condition for chained watchpoints --- libpince/debugcore.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 32651a2d..9cebb6c1 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1477,7 +1477,7 @@ def get_breakpoints_in_range(address: str | int, length: int = 1) -> list[typede #:tag:BreakWatchpoints -def hardware_breakpoint_available(): +def hardware_breakpoint_available() -> bool: """Checks if there is an available hardware breakpoint slot Returns: @@ -1485,7 +1485,7 @@ def hardware_breakpoint_available(): Todo: Check debug registers to determine hardware breakpoint state rather than relying on gdb output because inferior - might modify it's own debug registers + might modify its own debug registers """ breakpoint_info = get_breakpoint_info() hw_bp_total = 0 @@ -1536,10 +1536,10 @@ def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE else: return - +@execute_with_temporary_interruption #:tag:BreakWatchpoints -def add_watchpoint(expression, length=4, watchpoint_type=typedefs.WATCHPOINT_TYPE.BOTH, - on_hit=typedefs.BREAKPOINT_ON_HIT.BREAK): +def add_watchpoint(expression: str, length: int = 4, watchpoint_type: int = typedefs.WATCHPOINT_TYPE.BOTH, + on_hit: int = typedefs.BREAKPOINT_ON_HIT.BREAK) -> list[str]: """Adds a watchpoint at the address evaluated by the given expression Args: From 87e1d32710c9abc5786df7c4dc7ece2e861379a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 3 Feb 2024 18:23:31 +0300 Subject: [PATCH 345/487] Disable multi selection when ctrl is pressed --- GUI/TableViews/HexView.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index 20a4529e..df759c1d 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -16,7 +16,7 @@ """ from PyQt6.QtGui import QKeyEvent, QWheelEvent from PyQt6.QtWidgets import QTableView, QAbstractItemView -from PyQt6.QtCore import Qt +from PyQt6.QtCore import QItemSelectionModel, QModelIndex, Qt from GUI.ItemDelegates.HexDelegate import QHexDelegate from GUI.AbstractTableModels.HexModel import QHexModel from libpince import utils, debugcore, typedefs @@ -51,6 +51,13 @@ def keyPressEvent(self, event: QKeyEvent): else: return super().keyPressEvent(event) + def selectionCommand(self, index: QModelIndex, event: QKeyEvent): + if event.modifiers() == Qt.KeyboardModifier.ControlModifier: + # Disable multi-selection when Ctrl key is pressed + return QItemSelectionModel.SelectionFlag.ClearAndSelect + else: + return super().selectionCommand(index, event) + def resize_to_contents(self): size = self.columnWidth(0) * self.model().columnCount() self.setMinimumWidth(size) From 3efc5e946f487ae715a0bd1a3eeffe2664b2d3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 5 Feb 2024 16:47:48 +0300 Subject: [PATCH 346/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9531ccbc..f4beaaec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,14 +60,18 @@ So I think it's good to keep this old habit. This limit however, is not strict a messes up the readability, trust your guts and decide for yourself # UI Files -You need to have [Qt6 Designer](https://pkgs.org/search/?q=designer&on=files) and [pyuic6](https://pkgs.org/search/?q=pyuic6&on=files) installed. Here are the steps: +You need to have [Qt6 Designer](https://pkgs.org/search/?q=designer&on=files) and [pyuic6](https://pkgs.org/search/?q=pyuic6&on=files) installed. If there are no available packages for your distro, install [pyqt6-tools](https://pypi.org/project/pyqt6-tools/) instead + +Follow the steps below: - Edit or create ui files with the designer and then save them - After saving the files, use pyuic6 to convert them into py files: `pyuic6 SomeDialog.ui -o SomeDialog.py` The py files that contains the same name with the ui files are auto-generated, please edit the ui files with designer instead of messing with the py files # Translation -You need to have [Qt6 Linguist](https://pkgs.org/search/?q=linguist&on=files) and [pylupdate6](https://pkgs.org/search/?q=pylupdate6&on=files) installed. Here are the steps: +You need to have [Qt6 Linguist](https://pkgs.org/search/?q=linguist&on=files) and [pylupdate6](https://pkgs.org/search/?q=pylupdate6&on=files) installed. If there are no available packages for your distro, install [pyqt6-tools](https://pypi.org/project/pyqt6-tools/) instead + +Follow the steps below: - To create a new translation file, use [compile_ts.sh](./compile_ts.sh) with the locale as the parameter, such as `sh compile.sh ja_JP`. This will create a ts file with the locale you entered. You can skip this step if you only want to edit already existing files - Edit ts files in [/i18n/ts](./i18n/ts) with the linguist and then save them. After saving the files, run the [compile_ts.sh](./compile_ts.sh) script. @@ -169,7 +173,7 @@ OSError handles I/O related errors and ValueError handles the off_t limit error tuple_examine_expression = collections.namedtuple("tuple_examine_expression", "all address symbol") ``` - 6/10/2016 - HexView section of MemoryViewerWindow.ui: Changed listWidget_HexView_Address to tableWidget_HexView_Address in order to prevent possible future visual bugs. -Logically, it should stay as a listwidget considering it's functionality. But it doesn't play nice with the other neighboring tablewidgets in different pyqt versions, +Logically, it should stay as a listwidget considering its functionality. But it doesn't play nice with the other neighboring tablewidgets in different pyqt versions, forcing me to use magic numbers for adjusting, which is a bit hackish # Roadmap From adbc3553dddd2f8349eb68c869b7cbc6a87c95e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 5 Feb 2024 18:03:56 +0300 Subject: [PATCH 347/487] Add option to disable SIGSEGV if the process is java --- GUI/SettingsDialog.py | 19 +++++++++++++++++-- GUI/SettingsDialog.ui | 29 +++++++++++++++++++++++++++++ PINCE.py | 13 ++++++++++++- i18n/ts/it_IT.ts | 10 ++++++++++ i18n/ts/zh_CN.ts | 10 ++++++++++ libpince/debugcore.py | 2 +- libpince/utils.py | 8 ++++---- 7 files changed, 83 insertions(+), 8 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index e6070c19..8f1a66cf 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -37,6 +37,8 @@ def setupUi(self, Dialog): self.listWidget_Options.addItem(item) item = QtWidgets.QListWidgetItem() self.listWidget_Options.addItem(item) + item = QtWidgets.QListWidgetItem() + self.listWidget_Options.addItem(item) self.horizontalLayout_2.addWidget(self.listWidget_Options) self.stackedWidget = QtWidgets.QStackedWidget(parent=Dialog) self.stackedWidget.setMinimumSize(QtCore.QSize(500, 500)) @@ -331,6 +333,16 @@ def setupUi(self, Dialog): self.verticalLayout_11.addItem(spacerItem15) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) + self.page_6 = QtWidgets.QWidget() + self.page_6.setObjectName("page_6") + self.gridLayout_7 = QtWidgets.QGridLayout(self.page_6) + self.gridLayout_7.setObjectName("gridLayout_7") + self.checkBox_JavaSegfault = QtWidgets.QCheckBox(parent=self.page_6) + self.checkBox_JavaSegfault.setObjectName("checkBox_JavaSegfault") + self.gridLayout_7.addWidget(self.checkBox_JavaSegfault, 0, 0, 1, 1) + spacerItem16 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.gridLayout_7.addItem(spacerItem16, 1, 0, 1, 1) + self.stackedWidget.addWidget(self.page_6) self.horizontalLayout_2.addWidget(self.stackedWidget) self.verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout = QtWidgets.QHBoxLayout() @@ -338,8 +350,8 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(parent=Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem16) + spacerItem17 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem17) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -370,6 +382,8 @@ def retranslateUi(self, Dialog): item.setText(_translate("Dialog", "Disassemble")) item = self.listWidget_Options.item(4) item.setText(_translate("Dialog", "Debug")) + item = self.listWidget_Options.item(5) + item.setText(_translate("Dialog", "Java")) self.listWidget_Options.setSortingEnabled(__sortingEnabled) self.checkBox_AutoUpdateAddressTable.setText(_translate("Dialog", "Auto-update address table")) self.label.setText(_translate("Dialog", "Update Interval")) @@ -397,4 +411,5 @@ def retranslateUi(self, Dialog): self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) self.label_15.setText(_translate("Dialog", "Interruption signal")) self.pushButton_HandleSignals.setText(_translate("Dialog", "Handle Signals")) + self.checkBox_JavaSegfault.setText(_translate("Dialog", "Ignore SIGSEGV if the process is Java (overrides signal settings if enabled)")) self.pushButton_ResetSettings.setText(_translate("Dialog", "Reset Settings")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 3caa0df9..630a1fb2 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -57,6 +57,11 @@ Debug + + + Java + + @@ -719,6 +724,30 @@ Patterns at former positions have higher priority if regex is off + + + + + + Ignore SIGSEGV if the process is Java (overrides signal settings if enabled) + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + diff --git a/PINCE.py b/PINCE.py index c1bf02b0..8a94f70a 100755 --- a/PINCE.py +++ b/PINCE.py @@ -130,7 +130,7 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on # settings -current_settings_version = "30" # Increase version by one if you change settings +current_settings_version = "31" # Increase version by one if you change settings update_table = bool table_update_interval = int freeze_interval = int @@ -627,6 +627,9 @@ def set_default_settings(self): self.settings.setValue("interrupt_signal", "SIGINT") self.settings.setValue("handle_signals", json.dumps(default_signals)) self.settings.endGroup() + self.settings.beginGroup("Java") + self.settings.setValue("ignore_segfault", True) + self.settings.endGroup() self.settings.beginGroup("Misc") self.settings.setValue("version", current_settings_version) self.settings.endGroup() @@ -642,8 +645,14 @@ def apply_after_init(self): gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) interrupt_signal = self.settings.value("Debug/interrupt_signal", type=str) handle_signals = json.loads(self.settings.value("Debug/handle_signals", type=str)) + java_ignore_segfault = self.settings.value("Java/ignore_segfault", type=bool) + pid = debugcore.currentpid debugcore.set_logging(gdb_logging) debugcore.handle_signals(handle_signals) + # Not a great method but okayish until the implementation of the libpince engine and the java dissector + # "jps" command could be used instead if we ever need to install openjdk + if pid != -1 and java_ignore_segfault and utils.get_process_name(pid).startswith("java"): + debugcore.handle_signal("SIGSEGV", False, True) debugcore.set_interrupt_signal(interrupt_signal) # Needs to be called after handle_signals def apply_settings(self): @@ -2441,6 +2450,7 @@ def accept(self): self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) self.settings.setValue("Debug/interrupt_signal", self.comboBox_InterruptSignal.currentText()) + self.settings.setValue("Java/ignore_segfault", self.checkBox_JavaSegfault.isChecked()) if self.handle_signals_data: self.settings.setValue("Debug/handle_signals", self.handle_signals_data) super().accept() @@ -2507,6 +2517,7 @@ def config_gui(self): self.comboBox_InterruptSignal.addItems([f"SIG{x}" for x in range(signal.SIGRTMIN, signal.SIGRTMAX+1)]) self.comboBox_InterruptSignal.setCurrentIndex(self.comboBox_InterruptSignal.findText(cur_signal)) self.comboBox_InterruptSignal.setStyleSheet("combobox-popup: 0;") # maxVisibleItems doesn't work otherwise + self.checkBox_JavaSegfault.setChecked(self.settings.value("Java/ignore_segfault", type=bool)) def change_display(self, index): self.stackedWidget.setCurrentIndex(index) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index eb8df502..76bdb5ce 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -234,6 +234,11 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Debug + + + Java + + Auto-update address table @@ -355,6 +360,11 @@ Patterns at former positions have higher priority if regex is off Interruption signal + + + Ignore SIGSEGV if the process is Java (overrides signal settings if enabled) + + Reset Settings diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 98b4230f..7d656740 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -235,6 +235,11 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Debug 调试 + + + Java + + Auto-update address table @@ -357,6 +362,11 @@ Patterns at former positions have higher priority if regex is off Interruption signal + + + Ignore SIGSEGV if the process is Java (overrides signal settings if enabled) + + Reset Settings diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 9cebb6c1..63a41425 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -460,7 +460,7 @@ def set_interrupt_signal(signal_name): #:tag:Debug -def handle_signal(signal_name, stop, pass_to_program): +def handle_signal(signal_name: str, stop: bool, pass_to_program: bool) -> None: """Decides on what will GDB do when the process recieves a signal Args: diff --git a/libpince/utils.py b/libpince/utils.py index 2c57e61f..50bd92d1 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -43,17 +43,17 @@ def get_process_list(): #:tag:Processes -def get_process_name(pid): +def get_process_name(pid: int | str) -> str: """Returns the process name of given pid Args: - pid (int): PID of the process + pid (int, str): PID of the process Returns: str: Process name """ - with open("/proc/"+str(pid)+"/comm") as f: - return f.read()[:-1] + with open(f"/proc/{pid}/comm") as f: + return f.read().splitlines()[0] #:tag:Processes From 221ada6dc70e9a163473b0036ce26796e2ea17e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 5 Feb 2024 18:40:05 +0300 Subject: [PATCH 348/487] Adjust SettingsDialog params and texts --- GUI/SettingsDialog.py | 49 +++++++++++++++++-------------------------- GUI/SettingsDialog.ui | 48 +++--------------------------------------- 2 files changed, 22 insertions(+), 75 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 8f1a66cf..560145ad 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -56,7 +56,6 @@ def setupUi(self, Dialog): self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") self.checkBox_AutoUpdateAddressTable = QtWidgets.QCheckBox(parent=self.page) - self.checkBox_AutoUpdateAddressTable.setChecked(True) self.checkBox_AutoUpdateAddressTable.setObjectName("checkBox_AutoUpdateAddressTable") self.verticalLayout_2.addWidget(self.checkBox_AutoUpdateAddressTable) self.verticalLayout_3.addLayout(self.verticalLayout_2) @@ -70,7 +69,6 @@ def setupUi(self, Dialog): self.label.setObjectName("label") self.horizontalLayout_UpdateInterval.addWidget(self.label) self.lineEdit_UpdateInterval = QtWidgets.QLineEdit(parent=self.QWidget_UpdateInterval) - self.lineEdit_UpdateInterval.setText("500") self.lineEdit_UpdateInterval.setObjectName("lineEdit_UpdateInterval") self.horizontalLayout_UpdateInterval.addWidget(self.lineEdit_UpdateInterval) self.label_2 = QtWidgets.QLabel(parent=self.QWidget_UpdateInterval) @@ -100,7 +98,6 @@ def setupUi(self, Dialog): sizePolicy.setHeightForWidth(self.lineEdit_FreezeInterval.sizePolicy().hasHeightForWidth()) self.lineEdit_FreezeInterval.setSizePolicy(sizePolicy) self.lineEdit_FreezeInterval.setBaseSize(QtCore.QSize(20, 0)) - self.lineEdit_FreezeInterval.setText("100") self.lineEdit_FreezeInterval.setObjectName("lineEdit_FreezeInterval") self.horizontalLayout_14.addWidget(self.lineEdit_FreezeInterval) self.label_10 = QtWidgets.QLabel(parent=self.LockInterval) @@ -118,15 +115,12 @@ def setupUi(self, Dialog): self.label_8.setObjectName("label_8") self.horizontalLayout_3.addWidget(self.label_8) self.checkBox_OutputModeAsync = QtWidgets.QCheckBox(parent=self.page) - self.checkBox_OutputModeAsync.setChecked(True) self.checkBox_OutputModeAsync.setObjectName("checkBox_OutputModeAsync") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeAsync) self.checkBox_OutputModeCommand = QtWidgets.QCheckBox(parent=self.page) - self.checkBox_OutputModeCommand.setChecked(True) self.checkBox_OutputModeCommand.setObjectName("checkBox_OutputModeCommand") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeCommand) self.checkBox_OutputModeCommandInfo = QtWidgets.QCheckBox(parent=self.page) - self.checkBox_OutputModeCommandInfo.setChecked(True) self.checkBox_OutputModeCommandInfo.setObjectName("checkBox_OutputModeCommandInfo") self.horizontalLayout_3.addWidget(self.checkBox_OutputModeCommandInfo) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -235,12 +229,9 @@ def setupUi(self, Dialog): self.verticalLayout_8.addWidget(self.label_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") - spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_6.addItem(spacerItem8) self.verticalLayout_7 = QtWidgets.QVBoxLayout() self.verticalLayout_7.setObjectName("verticalLayout_7") self.radioButton_SimpleDLopenCall = QtWidgets.QRadioButton(parent=self.page_3) - self.radioButton_SimpleDLopenCall.setChecked(True) self.radioButton_SimpleDLopenCall.setObjectName("radioButton_SimpleDLopenCall") self.verticalLayout_7.addWidget(self.radioButton_SimpleDLopenCall) self.radioButton_AdvancedInjection = QtWidgets.QRadioButton(parent=self.page_3) @@ -250,11 +241,11 @@ def setupUi(self, Dialog): self.horizontalLayout_6.addLayout(self.verticalLayout_7) self.verticalLayout_8.addLayout(self.horizontalLayout_6) self.horizontalLayout_8.addLayout(self.verticalLayout_8) - spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_8.addItem(spacerItem9) + spacerItem8 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_8.addItem(spacerItem8) self.verticalLayout_9.addLayout(self.horizontalLayout_8) - spacerItem10 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_9.addItem(spacerItem10) + spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_9.addItem(spacerItem9) self.gridLayout_4.addLayout(self.verticalLayout_9, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_3) self.page_4 = QtWidgets.QWidget() @@ -264,7 +255,6 @@ def setupUi(self, Dialog): self.verticalLayout_10 = QtWidgets.QVBoxLayout() self.verticalLayout_10.setObjectName("verticalLayout_10") self.checkBox_BringDisassembleToFront = QtWidgets.QCheckBox(parent=self.page_4) - self.checkBox_BringDisassembleToFront.setChecked(True) self.checkBox_BringDisassembleToFront.setObjectName("checkBox_BringDisassembleToFront") self.verticalLayout_10.addWidget(self.checkBox_BringDisassembleToFront) self.horizontalLayout_10 = QtWidgets.QHBoxLayout() @@ -278,11 +268,11 @@ def setupUi(self, Dialog): self.lineEdit_InstructionsPerScroll.setObjectName("lineEdit_InstructionsPerScroll") self.horizontalLayout_9.addWidget(self.lineEdit_InstructionsPerScroll) self.horizontalLayout_10.addLayout(self.horizontalLayout_9) - spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_10.addItem(spacerItem11) + spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_10.addItem(spacerItem10) self.verticalLayout_10.addLayout(self.horizontalLayout_10) - spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_10.addItem(spacerItem12) + spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_10.addItem(spacerItem11) self.gridLayout_5.addLayout(self.verticalLayout_10, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_4) self.page_5 = QtWidgets.QWidget() @@ -303,7 +293,6 @@ def setupUi(self, Dialog): self.horizontalLayout_101.addWidget(self.lineEdit_GDBPath) self.horizontalLayout_11.addLayout(self.horizontalLayout_101) self.pushButton_GDBPath = QtWidgets.QPushButton(parent=self.page_5) - self.pushButton_GDBPath.setText("") self.pushButton_GDBPath.setObjectName("pushButton_GDBPath") self.horizontalLayout_11.addWidget(self.pushButton_GDBPath) self.verticalLayout_11.addLayout(self.horizontalLayout_11) @@ -318,19 +307,19 @@ def setupUi(self, Dialog): self.comboBox_InterruptSignal = QtWidgets.QComboBox(parent=self.page_5) self.comboBox_InterruptSignal.setObjectName("comboBox_InterruptSignal") self.horizontalLayout_18.addWidget(self.comboBox_InterruptSignal) - spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_18.addItem(spacerItem13) + spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_18.addItem(spacerItem12) self.verticalLayout_11.addLayout(self.horizontalLayout_18) self.horizontalLayout_16 = QtWidgets.QHBoxLayout() self.horizontalLayout_16.setObjectName("horizontalLayout_16") self.pushButton_HandleSignals = QtWidgets.QPushButton(parent=self.page_5) self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) - spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_16.addItem(spacerItem14) + spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_16.addItem(spacerItem13) self.verticalLayout_11.addLayout(self.horizontalLayout_16) - spacerItem15 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_11.addItem(spacerItem15) + spacerItem14 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_11.addItem(spacerItem14) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) self.page_6 = QtWidgets.QWidget() @@ -340,8 +329,8 @@ def setupUi(self, Dialog): self.checkBox_JavaSegfault = QtWidgets.QCheckBox(parent=self.page_6) self.checkBox_JavaSegfault.setObjectName("checkBox_JavaSegfault") self.gridLayout_7.addWidget(self.checkBox_JavaSegfault, 0, 0, 1, 1) - spacerItem16 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.gridLayout_7.addItem(spacerItem16, 1, 0, 1, 1) + spacerItem15 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.gridLayout_7.addItem(spacerItem15, 1, 0, 1, 1) self.stackedWidget.addWidget(self.page_6) self.horizontalLayout_2.addWidget(self.stackedWidget) self.verticalLayout.addLayout(self.horizontalLayout_2) @@ -350,8 +339,8 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(parent=Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem17 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem17) + spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem16) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -411,5 +400,5 @@ def retranslateUi(self, Dialog): self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) self.label_15.setText(_translate("Dialog", "Interruption signal")) self.pushButton_HandleSignals.setText(_translate("Dialog", "Handle Signals")) - self.checkBox_JavaSegfault.setText(_translate("Dialog", "Ignore SIGSEGV if the process is Java (overrides signal settings if enabled)")) + self.checkBox_JavaSegfault.setText(_translate("Dialog", "Ignore SIGSEGV for Java processes (overrides signal settings if enabled)")) self.pushButton_ResetSettings.setText(_translate("Dialog", "Reset Settings")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 630a1fb2..0cfc6241 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -90,9 +90,6 @@ Auto-update address table - - true - @@ -117,11 +114,7 @@ - - - 500 - - + @@ -178,9 +171,6 @@ 0 - - 100 - @@ -224,9 +214,6 @@ Async - - true - @@ -234,9 +221,6 @@ Command - - true - @@ -244,9 +228,6 @@ Command info - - true - @@ -485,19 +466,6 @@ Patterns at former positions have higher priority if regex is off - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -505,9 +473,6 @@ Patterns at former positions have higher priority if regex is off Simp&le dlopen call - - true - @@ -567,9 +532,6 @@ Patterns at former positions have higher priority if regex is off Bring disassemble screen to front when the inferior is stopped - - true - @@ -641,11 +603,7 @@ Patterns at former positions have higher priority if regex is off - - - - - + @@ -729,7 +687,7 @@ Patterns at former positions have higher priority if regex is off - Ignore SIGSEGV if the process is Java (overrides signal settings if enabled) + Ignore SIGSEGV for Java processes (overrides signal settings if enabled) From acf4c1e722be500859031ff62be986c60c5e0df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 5 Feb 2024 18:43:00 +0300 Subject: [PATCH 349/487] Update translations --- i18n/ts/it_IT.ts | 2 +- i18n/ts/zh_CN.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 76bdb5ce..875767bf 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -362,7 +362,7 @@ Patterns at former positions have higher priority if regex is off - Ignore SIGSEGV if the process is Java (overrides signal settings if enabled) + Ignore SIGSEGV for Java processes (overrides signal settings if enabled) diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 7d656740..e3f369c4 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -364,7 +364,7 @@ Patterns at former positions have higher priority if regex is off - Ignore SIGSEGV if the process is Java (overrides signal settings if enabled) + Ignore SIGSEGV for Java processes (overrides signal settings if enabled) From f29e52f411a1f48308ca3a31bc2ae2f007b17c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 6 Feb 2024 16:34:32 +0300 Subject: [PATCH 350/487] Don't handle signals when a process isn't present --- PINCE.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index 8a94f70a..0deaa74a 100755 --- a/PINCE.py +++ b/PINCE.py @@ -646,14 +646,16 @@ def apply_after_init(self): interrupt_signal = self.settings.value("Debug/interrupt_signal", type=str) handle_signals = json.loads(self.settings.value("Debug/handle_signals", type=str)) java_ignore_segfault = self.settings.value("Java/ignore_segfault", type=bool) - pid = debugcore.currentpid debugcore.set_logging(gdb_logging) - debugcore.handle_signals(handle_signals) - # Not a great method but okayish until the implementation of the libpince engine and the java dissector - # "jps" command could be used instead if we ever need to install openjdk - if pid != -1 and java_ignore_segfault and utils.get_process_name(pid).startswith("java"): - debugcore.handle_signal("SIGSEGV", False, True) - debugcore.set_interrupt_signal(interrupt_signal) # Needs to be called after handle_signals + + # Don't handle signals if a process isn't present, a small optimization to gain time on launch and detach + if debugcore.currentpid != -1: + debugcore.handle_signals(handle_signals) + # Not a great method but okayish until the implementation of the libpince engine and the java dissector + # "jps" command could be used instead if we ever need to install openjdk + if java_ignore_segfault and utils.get_process_name(debugcore.currentpid).startswith("java"): + debugcore.handle_signal("SIGSEGV", False, True) + debugcore.set_interrupt_signal(interrupt_signal) # Needs to be called after handle_signals def apply_settings(self): global update_table From 9b5638c8083f5afb94aa9db9b3f1e5ee7cda8d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 6 Feb 2024 18:24:09 +0300 Subject: [PATCH 351/487] Fix wiki links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c4022d2b..6a70a4ce 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ Pre-release screenshots: - **Background Execution:** PINCE uses background execution by default, allowing users to run GDB commands while process is running - **Variable Inspection&Modification** * **CheatEngine-like value type support:** Currently supports all types of CE and scanmem along with extended strings(utf-8, utf-16, utf-32) - * **Symbol Recognition:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) - * **Automatic Variable Allocation:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) + * **Symbol Recognition:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/GDB-Expressions) + * **Automatic Variable Allocation:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/GDB-Expressions) * **Dynamic Address Table:** Supports drag&drop, recursive copy&pasting&inserting and many more * **Smart casting:** PINCE lets you modify multiple different-type values together as long as the input is parsable. All parsing/memory errors are directed to the terminal * **Variable Locking:** PINCE lets you freeze(constantly write a value to memory cell) variables @@ -38,7 +38,7 @@ Pre-release screenshots: * **Assembler:** PINCE uses keystone engine to assemble code on the fly * **Dissect Code:** You can dissect desired memory regions to find referenced calls, jumps and strings. Disassemble screen will automatically handle the referenced data and show you if there's a referenced address in the current dissasemble view. It can be used from Tools->Dissect Code in the MemoryView window. Using its hotkey instead in the MemoryView window automatically dissects the currently viewed region. You can separately view referenced calls and strings after the search from View->Referenced Calls/Strings. *Note: If you decide to uncheck 'Discard invalid strings' before the search, PINCE will try to search for regular pointers as well* * **Bookmarking:** Bookmark menu is dynamically created when right clicked in the disassemble screen. So unlike Cheat Engine, PINCE lets you set unlimited number of bookmarks. List of bookmarks can also be viewed from View->Bookmarks in the MemoryView window. Commenting on an address automatically bookmarks it - * **Modify on the fly:** PINCE lets you modify registers on the fly. Check [GDB expressions in the Wiki page](https://github.com/korcankaraokcu/PINCE/wiki/About-GDB-Expressions) for additional information + * **Modify on the fly:** PINCE lets you modify registers on the fly. Check [GDB expressions in the Wiki page](https://github.com/korcankaraokcu/PINCE/wiki/GDB-Expressions) for additional information * **Opcode Search:** You can search opcodes with python regular expressions. To use this feature, click Tools->Search Opcode in the MemoryView window - **Debugging** * Has basic debugging features such as stepping, stepping over, execute till return, break, continue. Also has breakpoints, watchpoints and breakpoint conditions. Has advanced debugging utilities such as Watchpoint/Breakpoint Tracking and Tracing From 9123cef7a3507f1caa98f0fa50cd86d66dc7542b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 6 Feb 2024 20:33:11 +0300 Subject: [PATCH 352/487] Clear exp_cache instead of use_cache param --- PINCE.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 0deaa74a..16499e23 100755 --- a/PINCE.py +++ b/PINCE.py @@ -567,7 +567,7 @@ def __init__(self): self.pushButton_About.clicked.connect(self.pushButton_About_clicked) self.pushButton_AddAddressManually.clicked.connect(self.pushButton_AddAddressManually_clicked) self.pushButton_MemoryView.clicked.connect(self.pushButton_MemoryView_clicked) - self.pushButton_RefreshAdressTable.clicked.connect(lambda: self.update_address_table(use_cache=False)) + self.pushButton_RefreshAdressTable.clicked.connect(self.pushButton_RefreshAdressTable_clicked) self.pushButton_CopyToAddressTable.clicked.connect(self.copy_to_address_table) self.pushButton_CleanAddressTable.clicked.connect(self.clear_address_table) self.tableWidget_valuesearchtable.cellDoubleClicked.connect( @@ -1033,8 +1033,7 @@ def treeWidget_AddressTable_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), self.browse_region_for_selected_row), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), - lambda: self.update_address_table(use_cache=False)), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.pushButton_RefreshAdressTable_clicked), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_records), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Space), lambda: self.toggle_records(True)), @@ -1056,7 +1055,7 @@ def treeWidget_AddressTable_key_press_event(self, event): except KeyError: self.treeWidget_AddressTable.keyPressEvent_original(event) - def update_address_table(self, use_cache=True): + def update_address_table(self): global exp_cache if debugcore.currentpid == -1 or self.treeWidget_AddressTable.topLevelItemCount() == 0: return @@ -1076,7 +1075,7 @@ def update_address_table(self, use_cache=True): parent = row.parent() if parent and expression.startswith(('+', '-')): expression = parent.data(ADDR_COL, Qt.ItemDataRole.UserRole+1)+expression - if use_cache and expression in exp_cache: + if expression in exp_cache: address = exp_cache[expression] elif expression.startswith(('+', '-')): # If parent has an empty address address = expression @@ -1139,6 +1138,11 @@ def pushButton_AddAddressManually_clicked(self): self.add_entry_to_addresstable(desc, address_expr, vt) self.update_address_table() + def pushButton_RefreshAdressTable_clicked(self): + global exp_cache + exp_cache.clear() + self.update_address_table() + def pushButton_MemoryView_clicked(self): self.memory_view_window.showMaximized() self.memory_view_window.activateWindow() From 81bc2d24186d71dd015ec50938c08650a4ab3149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 7 Feb 2024 15:10:58 +0300 Subject: [PATCH 353/487] Delete unused variable and update comments --- PINCE.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 16499e23..3171bcec 100755 --- a/PINCE.py +++ b/PINCE.py @@ -322,15 +322,12 @@ def get_hotkeys(): REF_CALL_ADDR_COL = 0 REF_CALL_COUNT_COL = 1 -# used for automatically updating the values in the saved address tree widget -# see UpdateAddressTableThread -saved_addresses_changed_list = list() - # GDB expression cache # TODO: Try to find a fast and non-gdb way to calculate symbols so we don't need this # This is one of the few tricks we do to minimize examine_expression calls # This solution might bring problems if the symbols are changing frequently -# Currently only address_table_loop uses this so user can refresh symbols with a button press +# Pressing the refresh button in the address table or attaching to a new process will clear this cache +# Currently only used in address_table_loop exp_cache = {} # vars for communication with the non blocking threads From ddf02c49e964599ebbf84ad184924b826752b8f5 Mon Sep 17 00:00:00 2001 From: Viktor Horsmanheimo Date: Tue, 6 Feb 2024 20:28:06 +0200 Subject: [PATCH 354/487] fix white space issues --- PINCE.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PINCE.py b/PINCE.py index 3171bcec..be1cee37 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1203,7 +1203,7 @@ def handle_line_edit_scan_key_press_event(self, event): else: self.pushButton_NewFirstScan_clicked() return - + def lineEdit_Scan_on_key_press_event(self, event): self.handle_line_edit_scan_key_press_event(event) self.lineEdit_Scan.keyPressEvent_original(event) @@ -1664,7 +1664,7 @@ def treeWidget_AddressTable_item_clicked(self, row: QTreeWidgetItem, column: int if not frozen_state_toggled and is_checked: # user clicked the text, iterate through the freeze type - if frozen.freeze_type == typedefs.FREEZE_TYPE.DECREMENT: + if frozen.freeze_type == typedefs.FREEZE_TYPE.DECREMENT: # decrement is the last freeze type self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT) else: @@ -1777,7 +1777,7 @@ def read_address_table_entries(self, row, serialize=False): def read_address_table_recursively(self, row): return self.read_address_table_entries(row, True) + \ ([self.read_address_table_recursively(row.child(i)) for i in range(row.childCount())],) - + # Flashing Attach Button when the process is not attached def flash_attach_button(self): if not self.flashAttachButton: @@ -1844,7 +1844,7 @@ def pushButton_Open_clicked(self): if index.row() == -1 and row_count == 1: # autoselect first row if there is only one row self.tableWidget_ProcessTable.setCurrentCell(0, 0) - + current_item = self.tableWidget_ProcessTable.item(self.tableWidget_ProcessTable.currentIndex().row(), 0) if current_item is None: QMessageBox.information(self, tr.ERROR, tr.SELECT_PROCESS) @@ -2604,7 +2604,7 @@ def __init__(self, signal_data, parent=None): else: checkbox.setCheckState(Qt.CheckState.Unchecked) self.tableWidget_Signals.resizeColumnsToContents() - + def create_checkbox_widget(self): widget = QWidget() From c994ce8de8bc3f35a2e5190ddc73ab965420e830 Mon Sep 17 00:00:00 2001 From: Viktor Horsmanheimo Date: Tue, 6 Feb 2024 21:11:04 +0200 Subject: [PATCH 355/487] Add missing dependency to install script `pkgconf` was missing from the arch installation, this made installing cairo with pip fail. --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index a9be4e5f..297e8853 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -130,7 +130,7 @@ PKG_NAMES_ALL="python3-pip gdb libtool" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-dev python3-venv pkg-config qt6-l10n-tools libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" -PKG_NAMES_ARCH="python-pip qt6-tools gdb lsb-release" # arch defaults to py3 nowadays +PKG_NAMES_ARCH="python-pip qt6-tools gdb lsb-release pkgconf" # arch defaults to py3 nowadays INSTALL_COMMAND="install" From b4e2aeb2c47335efd6fafabc568cb69fb072015f Mon Sep 17 00:00:00 2001 From: Viktor Horsmanheimo Date: Wed, 7 Feb 2024 15:55:10 +0200 Subject: [PATCH 356/487] Refactor Hotkeys Move Hotkeys into it's own file in GUI/Settings/hotkeys.py --- GUI/Settings/hotkeys.py | 56 ++++++++++++++++++++++++++++++++++++ PINCE.py | 64 ++++------------------------------------- 2 files changed, 62 insertions(+), 58 deletions(-) create mode 100644 GUI/Settings/hotkeys.py diff --git a/GUI/Settings/hotkeys.py b/GUI/Settings/hotkeys.py new file mode 100644 index 00000000..ee5497a4 --- /dev/null +++ b/GUI/Settings/hotkeys.py @@ -0,0 +1,56 @@ +from keyboard import add_hotkey, remove_hotkey + +from tr.tr import TranslationConstants as tr + + +class Hotkeys: + class Hotkey: + def __init__(self, name="", desc="", default="", func=None, custom="", handle=None): + self.name = name + self.desc = desc + self.default = default + self.func = func + self.custom = custom + if default == "" or func is None: + self.handle = handle + else: + self.handle = add_hotkey(default, func) + + def change_key(self, custom): + if self.handle is not None: + remove_hotkey(self.handle) + self.handle = None + self.custom = custom + if custom == '': + return + self.handle = add_hotkey(custom.lower(), self.func) + + def change_func(self, func): + self.func = func + if self.handle is not None: + remove_hotkey(self.handle) + if self.custom != "": + self.handle = add_hotkey(self.custom, func) + elif self.default != "": + self.handle = add_hotkey(self.default, func) + + def get_active_key(self): + if self.custom == "": + return self.default + return self.custom + + pause_hotkey = Hotkey("pause_hotkey", tr.PAUSE_HOTKEY, "F1") + break_hotkey = Hotkey("break_hotkey", tr.BREAK_HOTKEY, "F2") + continue_hotkey = Hotkey("continue_hotkey", tr.CONTINUE_HOTKEY, "F3") + toggle_attach_hotkey = Hotkey("toggle_attach_hotkey", tr.TOGGLE_ATTACH_HOTKEY, "Shift+F10") + exact_scan_hotkey = Hotkey("exact_scan_hotkey", tr.EXACT_SCAN_HOTKEY, "") + increased_scan_hotkey = Hotkey("increased_scan_hotkey", tr.INC_SCAN_HOTKEY, "") + decreased_scan_hotkey = Hotkey("decreased_scan_hotkey", tr.DEC_SCAN_HOTKEY, "") + changed_scan_hotkey = Hotkey("changed_scan_hotkey", tr.CHANGED_SCAN_HOTKEY, "") + unchanged_scan_hotkey = Hotkey("unchanged_scan_hotkey", tr.UNCHANGED_SCAN_HOTKEY, "") + + @staticmethod + def get_hotkeys(): + return Hotkeys.pause_hotkey, Hotkeys.break_hotkey, Hotkeys.continue_hotkey, Hotkeys.toggle_attach_hotkey, \ + Hotkeys.exact_scan_hotkey, Hotkeys.increased_scan_hotkey, Hotkeys.decreased_scan_hotkey, \ + Hotkeys.changed_scan_hotkey, Hotkeys.unchanged_scan_hotkey diff --git a/PINCE.py b/PINCE.py index be1cee37..4881c32e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -20,6 +20,8 @@ """ import gi +from GUI.Settings.hotkeys import Hotkeys + # This fixes GTK version mismatch issues and crashes on gnome # See #153 and #159 for more information # This line can be deleted when GTK 4.0 properly runs on all supported systems @@ -28,12 +30,12 @@ from tr.tr import TranslationConstants as tr from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ - QKeyEvent, QRegularExpressionValidator, QShortcut, QColorConstants + QRegularExpressionValidator, QShortcut, QColorConstants from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ - QItemSelectionModel, QTimer, QModelIndex, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ + QItemSelectionModel, QTimer, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ QLocale, QSignalBlocker, QItemSelection from typing import Final from time import sleep, time @@ -86,7 +88,6 @@ from GUI.AbstractTableModels.AsciiModel import QAsciiModel from GUI.Validators.HexValidator import QHexValidator -from keyboard import add_hotkey, remove_hotkey from operator import add as opAdd, sub as opSub # TODO: Carry all settings related things to their own script if possible @@ -141,60 +142,6 @@ def get_locale(): logo_path = str theme = str - -class Hotkeys: - class Hotkey: - def __init__(self, name="", desc="", default="", func=None, custom="", handle=None): - self.name = name - self.desc = desc - self.default = default - self.func = func - self.custom = custom - if default == "" or func is None: - self.handle = handle - else: - self.handle = add_hotkey(default, func) - - def change_key(self, custom): - if self.handle is not None: - remove_hotkey(self.handle) - self.handle = None - self.custom = custom - if custom == '': - return - self.handle = add_hotkey(custom.lower(), self.func) - - def change_func(self, func): - self.func = func - if self.handle is not None: - remove_hotkey(self.handle) - if self.custom != "": - self.handle = add_hotkey(self.custom, func) - elif self.default != "": - self.handle = add_hotkey(self.default, func) - - def get_active_key(self): - if self.custom == "": - return self.default - return self.custom - - pause_hotkey = Hotkey("pause_hotkey", tr.PAUSE_HOTKEY, "F1") - break_hotkey = Hotkey("break_hotkey", tr.BREAK_HOTKEY, "F2") - continue_hotkey = Hotkey("continue_hotkey", tr.CONTINUE_HOTKEY, "F3") - toggle_attach_hotkey = Hotkey("toggle_attach_hotkey", tr.TOGGLE_ATTACH_HOTKEY, "Shift+F10") - exact_scan_hotkey = Hotkey("exact_scan_hotkey", tr.EXACT_SCAN_HOTKEY, "") - increased_scan_hotkey = Hotkey("increased_scan_hotkey", tr.INC_SCAN_HOTKEY, "") - decreased_scan_hotkey = Hotkey("decreased_scan_hotkey", tr.DEC_SCAN_HOTKEY, "") - changed_scan_hotkey = Hotkey("changed_scan_hotkey", tr.CHANGED_SCAN_HOTKEY, "") - unchanged_scan_hotkey = Hotkey("unchanged_scan_hotkey", tr.UNCHANGED_SCAN_HOTKEY, "") - - @staticmethod - def get_hotkeys(): - return Hotkeys.pause_hotkey, Hotkeys.break_hotkey, Hotkeys.continue_hotkey, Hotkeys.toggle_attach_hotkey, \ - Hotkeys.exact_scan_hotkey, Hotkeys.increased_scan_hotkey, Hotkeys.decreased_scan_hotkey, \ - Hotkeys.changed_scan_hotkey, Hotkeys.unchanged_scan_hotkey - - code_injection_method = int bring_disassemble_to_front = bool instructions_per_scroll = int @@ -2536,7 +2483,8 @@ def keySequenceEdit_Hotkey_key_sequence_changed(self): if index == -1: self.keySequenceEdit_Hotkey.clear() else: - self.hotkey_to_value[Hotkeys.get_hotkeys()[index].name] = self.keySequenceEdit_Hotkey.keySequence().toString() + self.hotkey_to_value[ + Hotkeys.get_hotkeys()[index].name] = self.keySequenceEdit_Hotkey.keySequence().toString() def pushButton_ClearHotkey_clicked(self): self.keySequenceEdit_Hotkey.clear() From 27079842b986b2b5d1c83a574151abc8a1b10f81 Mon Sep 17 00:00:00 2001 From: Viktor Horsmanheimo Date: Wed, 7 Feb 2024 18:51:57 +0200 Subject: [PATCH 357/487] Refactor settings Move class specific options into their respective classes. Global settings and GDB related settings have been moved into a separate file `settings.py` --- GUI/Settings/settings.py | 53 ++++++++++++ PINCE.py | 174 ++++++++++++++------------------------- 2 files changed, 117 insertions(+), 110 deletions(-) create mode 100644 GUI/Settings/settings.py diff --git a/GUI/Settings/settings.py b/GUI/Settings/settings.py new file mode 100644 index 00000000..ab28c3d3 --- /dev/null +++ b/GUI/Settings/settings.py @@ -0,0 +1,53 @@ +import libpince.typedefs as typedefs + +current_settings_version = "32" # Increase version by one if you change settings + + +locale: str = "" +# Unused, will be re-added in the future +code_injection_method: int = 0 + +gdb_path: str = typedefs.PATHS.GDB +gdb_output_mode: tuple = (True, True, True) +gdb_logging: bool = False +interrupt_signal: str +handle_signals: list = [] +# Due to community feedback, these signals are disabled by default: SIGUSR1, SIGUSR2, SIGPWR, SIGXCPU, SIGXFSZ, SIGSYS +default_signals = [ + ["SIGHUP", True, True], ["SIGINT", True, False], ["SIGQUIT", True, True], ["SIGILL", True, True], + ["SIGTRAP", True, False], ["SIGABRT", True, True], ["SIGEMT", True, True], ["SIGFPE", True, True], + ["SIGKILL", True, True], ["SIGBUS", True, True], ["SIGSEGV", True, True], ["SIGSYS", False, True], + ["SIGPIPE", True, True], ["SIGALRM", False, True], ["SIGTERM", True, True], ["SIGURG", False, True], + ["SIGSTOP", True, True], ["SIGTSTP", True, True], ["SIGCONT", True, True], ["SIGCHLD", False, True], + ["SIGTTIN", True, True], ["SIGTTOU", True, True], ["SIGIO", False, True], ["SIGXCPU", False, True], + ["SIGXFSZ", False, True], ["SIGVTALRM", False, True], ["SIGPROF", False, True], ["SIGWINCH", False, True], + ["SIGLOST", True, True], ["SIGUSR1", False, True], ["SIGUSR2", False, True], ["SIGPWR", False, True], + ["SIGPOLL", False, True], ["SIGWIND", True, True], ["SIGPHONE", True, True], ["SIGWAITING", False, True], + ["SIGLWP", False, True], ["SIGDANGER", True, True], ["SIGGRANT", True, True], ["SIGRETRACT", True, True], + ["SIGMSG", True, True], ["SIGSOUND", True, True], ["SIGSAK", True, True], ["SIGPRIO", False, True], + ["SIGCANCEL", False, True], ["SIGINFO", True, True], ["EXC_BAD_ACCESS", True, True], + ["EXC_BAD_INSTRUCTION", True, True], ["EXC_ARITHMETIC", True, True], ["EXC_EMULATION", True, True], + ["EXC_SOFTWARE", True, True], ["EXC_BREAKPOINT", True, True], ["SIGLIBRT", False, True], + # + ['SIG32', True, True], + ['SIG33', True, True], ['SIG34', True, True], ['SIG35', True, True], ['SIG36', True, True], ['SIG37', True, True], + ['SIG38', True, True], ['SIG39', True, True], ['SIG40', True, True], ['SIG41', True, True], ['SIG42', True, True], + ['SIG43', True, True], ['SIG44', True, True], ['SIG45', True, True], ['SIG46', True, True], ['SIG47', True, True], + ['SIG48', True, True], ['SIG49', True, True], ['SIG50', True, True], ['SIG51', True, True], ['SIG52', True, True], + ['SIG53', True, True], ['SIG54', True, True], ['SIG55', True, True], ['SIG56', True, True], ['SIG57', True, True], + ['SIG58', True, True], ['SIG59', True, True], ['SIG60', True, True], ['SIG61', True, True], ['SIG62', True, True], + ['SIG63', True, True], ['SIG64', True, True], ['SIG65', True, True], ['SIG66', True, True], ['SIG67', True, True], + ['SIG68', True, True], ['SIG69', True, True], ['SIG70', True, True], ['SIG71', True, True], ['SIG72', True, True], + ['SIG73', True, True], ['SIG74', True, True], ['SIG75', True, True], ['SIG76', True, True], ['SIG77', True, True], + ['SIG78', True, True], ['SIG79', True, True], ['SIG80', True, True], ['SIG81', True, True], ['SIG82', True, True], + ['SIG83', True, True], ['SIG84', True, True], ['SIG85', True, True], ['SIG86', True, True], ['SIG87', True, True], + ['SIG88', True, True], ['SIG89', True, True], ['SIG90', True, True], ['SIG91', True, True], ['SIG92', True, True], + ['SIG93', True, True], ['SIG94', True, True], ['SIG95', True, True], ['SIG96', True, True], ['SIG97', True, True], + ['SIG98', True, True], ['SIG99', True, True], ['SIG100', True, True], ['SIG101', True, True], + ['SIG102', True, True], ['SIG103', True, True], ['SIG104', True, True], ['SIG105', True, True], + ['SIG106', True, True], ['SIG107', True, True], ['SIG108', True, True], ['SIG109', True, True], + ['SIG110', True, True], ['SIG111', True, True], ['SIG112', True, True], ['SIG113', True, True], + ['SIG114', True, True], ['SIG115', True, True], ['SIG116', True, True], ['SIG117', True, True], + ['SIG118', True, True], ['SIG119', True, True], ['SIG120', True, True], ['SIG121', True, True], + ['SIG122', True, True], ['SIG123', True, True], ['SIG124', True, True], ['SIG125', True, True], + ['SIG126', True, True], ['SIG127', True, True]] diff --git a/PINCE.py b/PINCE.py index 4881c32e..62595107 100755 --- a/PINCE.py +++ b/PINCE.py @@ -20,7 +20,9 @@ """ import gi +import GUI.Settings.settings as settings from GUI.Settings.hotkeys import Hotkeys +from GUI.Settings.settings import current_settings_version, gdb_logging, default_signals # This fixes GTK version mismatch issues and crashes on gnome # See #153 and #159 for more information @@ -130,47 +132,6 @@ def get_locale(): instances = [] # Holds temporary instances that will be deleted later on -# settings -current_settings_version = "31" # Increase version by one if you change settings -update_table = bool -table_update_interval = int -freeze_interval = int -gdb_output_mode = tuple -auto_attach_list = str -auto_attach_regex = bool -locale = str -logo_path = str -theme = str - -code_injection_method = int -bring_disassemble_to_front = bool -instructions_per_scroll = int -gdb_path = str -gdb_logging = bool -interrupt_signal = str -handle_signals = list - -# Due to community feedback, these signals are disabled by default: SIGUSR1, SIGUSR2, SIGPWR, SIGXCPU, SIGXFSZ, SIGSYS -# Rest is the same with GDB defaults -default_signals = [ - ["SIGHUP", True, True], ["SIGINT", True, False], ["SIGQUIT", True, True], ["SIGILL", True, True], - ["SIGTRAP", True, False], ["SIGABRT", True, True], ["SIGEMT", True, True], ["SIGFPE", True, True], - ["SIGKILL", True, True], ["SIGBUS", True, True], ["SIGSEGV", True, True], ["SIGSYS", False, True], - ["SIGPIPE", True, True], ["SIGALRM", False, True], ["SIGTERM", True, True], ["SIGURG", False, True], - ["SIGSTOP", True, True], ["SIGTSTP", True, True], ["SIGCONT", True, True], ["SIGCHLD", False, True], - ["SIGTTIN", True, True], ["SIGTTOU", True, True], ["SIGIO", False, True], ["SIGXCPU", False, True], - ["SIGXFSZ", False, True], ["SIGVTALRM", False, True], ["SIGPROF", False, True], ["SIGWINCH", False, True], - ["SIGLOST", True, True], ["SIGUSR1", False, True], ["SIGUSR2", False, True], ["SIGPWR", False, True], - ["SIGPOLL", False, True], ["SIGWIND", True, True], ["SIGPHONE", True, True], ["SIGWAITING", False, True], - ["SIGLWP", False, True], ["SIGDANGER", True, True], ["SIGGRANT", True, True], ["SIGRETRACT", True, True], - ["SIGMSG", True, True], ["SIGSOUND", True, True], ["SIGSAK", True, True], ["SIGPRIO", False, True], - ["SIGCANCEL", False, True], ["SIGINFO", True, True], ["EXC_BAD_ACCESS", True, True], - ["EXC_BAD_INSTRUCTION", True, True], ["EXC_ARITHMETIC", True, True], ["EXC_EMULATION", True, True], - ["EXC_SOFTWARE", True, True], ["EXC_BREAKPOINT", True, True], ["SIGLIBRT", False, True] -] -for x in range(32, 128): # Add signals SIG32-SIG127 - default_signals.append([f"SIG{x}", True, True]) - # represents the index of columns in instructions restore table INSTR_ADDR_COL = 0 INSTR_AOB_COL = 1 @@ -398,6 +359,12 @@ def run(self): class MainForm(QMainWindow, MainWindow): + table_update_interval: int = 500 + freeze_interval: int = 100 + update_table: bool = True + auto_attach_list: str = "" + auto_attach_regex: bool = False + def __init__(self): """ Declare regular expressions for hexadecimal and decimal input @@ -431,6 +398,10 @@ def __init__(self): self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) self.settings = QSettings() + self.memory_view_window = MemoryViewWindowForm(self) + self.about_widget = AboutWidgetForm() + self.await_exit_thread = AwaitProcessExit() + if not os.path.exists(self.settings.fileName()): self.set_default_settings() try: @@ -449,14 +420,11 @@ def __init__(self): self.settings.clear() self.set_default_settings() try: - debugcore.init_gdb(gdb_path) + debugcore.init_gdb(settings.gdb_path) except pexpect.EOF: InputDialogForm(item_list=[(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() else: self.apply_after_init() - self.memory_view_window = MemoryViewWindowForm(self) - self.about_widget = AboutWidgetForm() - self.await_exit_thread = AwaitProcessExit() self.await_exit_thread.process_exited.connect(self.on_inferior_exit) self.await_exit_thread.start() self.check_status_thread = CheckInferiorStatus() @@ -544,12 +512,12 @@ def __init__(self): # Using python objects causes issues when filenames change def set_default_settings(self): self.settings.beginGroup("General") - self.settings.setValue("auto_update_address_table", True) - self.settings.setValue("address_table_update_interval", 500) - self.settings.setValue("freeze_interval", 100) + self.settings.setValue("auto_update_address_table", MainForm.update_table) + self.settings.setValue("address_table_update_interval", MainForm.table_update_interval) + self.settings.setValue("freeze_interval", MainForm.freeze_interval) self.settings.setValue("gdb_output_mode", json.dumps([True, True, True])) - self.settings.setValue("auto_attach_list", "") - self.settings.setValue("auto_attach_regex", False) + self.settings.setValue("auto_attach_list", MainForm.auto_attach_list) + self.settings.setValue("auto_attach_regex", MainForm.auto_attach_regex) self.settings.setValue("locale", get_locale()) self.settings.setValue("logo_path", "ozgurozbek/pince_small_transparent.png") self.settings.setValue("theme", "System Default") @@ -563,7 +531,7 @@ def set_default_settings(self): self.settings.endGroup() self.settings.beginGroup("Disassemble") self.settings.setValue("bring_disassemble_to_front", False) - self.settings.setValue("instructions_per_scroll", 2) + self.settings.setValue("instructions_per_scroll", MemoryViewWindowForm.instructions_per_scroll) self.settings.endGroup() self.settings.beginGroup("Debug") self.settings.setValue("gdb_path", typedefs.PATHS.GDB) @@ -580,78 +548,61 @@ def set_default_settings(self): self.apply_settings() def apply_after_init(self): - global gdb_logging - global interrupt_signal - global handle_signals global exp_cache exp_cache.clear() - gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) - interrupt_signal = self.settings.value("Debug/interrupt_signal", type=str) - handle_signals = json.loads(self.settings.value("Debug/handle_signals", type=str)) + settings.gdb_logging = self.settings.value("Debug/gdb_logging", type=bool) + settings.interrupt_signal = self.settings.value("Debug/interrupt_signal", type=str) + settings.handle_signals = json.loads(self.settings.value("Debug/handle_signals", type=str)) java_ignore_segfault = self.settings.value("Java/ignore_segfault", type=bool) - debugcore.set_logging(gdb_logging) + debugcore.set_logging(settings.gdb_logging) # Don't handle signals if a process isn't present, a small optimization to gain time on launch and detach if debugcore.currentpid != -1: - debugcore.handle_signals(handle_signals) + debugcore.handle_signals(settings.handle_signals) # Not a great method but okayish until the implementation of the libpince engine and the java dissector # "jps" command could be used instead if we ever need to install openjdk if java_ignore_segfault and utils.get_process_name(debugcore.currentpid).startswith("java"): debugcore.handle_signal("SIGSEGV", False, True) - debugcore.set_interrupt_signal(interrupt_signal) # Needs to be called after handle_signals + debugcore.set_interrupt_signal(settings.interrupt_signal) # Needs to be called after handle_signals def apply_settings(self): - global update_table - global table_update_interval - global gdb_output_mode - global auto_attach_list - global auto_attach_regex - global locale - global logo_path - global theme - global code_injection_method - global bring_disassemble_to_front - global instructions_per_scroll - global gdb_path - global freeze_interval - - update_table = self.settings.value("General/auto_update_address_table", type=bool) - table_update_interval = self.settings.value("General/address_table_update_interval", type=int) - freeze_interval = self.settings.value("General/freeze_interval", type=int) - gdb_output_mode = json.loads(self.settings.value("General/gdb_output_mode", type=str)) - gdb_output_mode = typedefs.gdb_output_mode(*gdb_output_mode) - auto_attach_list = self.settings.value("General/auto_attach_list", type=str) - auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) - locale = self.settings.value("General/locale", type=str) - logo_path = self.settings.value("General/logo_path", type=str) - app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), logo_path))) - theme = self.settings.value("General/theme", type=str) - app.setPalette(get_theme(theme)) - debugcore.set_gdb_output_mode(gdb_output_mode) + + self.update_table = self.settings.value("General/auto_update_address_table", type=bool) + self.table_update_interval = self.settings.value("General/address_table_update_interval", type=int) + self.freeze_interval = self.settings.value("General/freeze_interval", type=int) + settings.gdb_output_mode = json.loads(self.settings.value("General/gdb_output_mode", type=str)) + settings.gdb_output_mode = typedefs.gdb_output_mode(*settings.gdb_output_mode) + self.auto_attach_list = self.settings.value("General/auto_attach_list", type=str) + self.auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) + settings.locale = self.settings.value("General/locale", type=str) + app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), + self.settings.value("General/logo_path", type=str)))) + app.setPalette(get_theme(self.settings.value("General/theme", type=str))) + debugcore.set_gdb_output_mode(settings.gdb_output_mode) for hotkey in Hotkeys.get_hotkeys(): hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) try: self.memory_view_window.set_dynamic_debug_hotkeys() except AttributeError: pass - code_injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) - bring_disassemble_to_front = self.settings.value("Disassemble/bring_disassemble_to_front", type=bool) - instructions_per_scroll = self.settings.value("Disassemble/instructions_per_scroll", type=int) - gdb_path = self.settings.value("Debug/gdb_path", type=str) + settings.code_injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) + self.memory_view_window.bring_disassemble_to_front = self.settings.value("Disassemble/bring_disassemble_to_front", type=bool) + self.memory_view_window.instructions_per_scroll = self.settings.value("Disassemble/instructions_per_scroll", type=int) + settings.gdb_path = self.settings.value("Debug/gdb_path", type=str) if debugcore.gdb_initialized: self.apply_after_init() # Check if any process should be attached to automatically # Patterns at former positions have higher priority if regex is off def auto_attach(self): - if not auto_attach_list: + if not self.auto_attach_list: return - if auto_attach_regex: + if self.auto_attach_regex: try: - compiled_re = re.compile(auto_attach_list) + compiled_re = re.compile(self.auto_attach_list) except: - print("Auto-attach failed: " + auto_attach_list + " isn't a valid regex") + print("Auto-attach failed: " + self.auto_attach_list + " isn't a valid regex") return for pid, _, name in utils.get_process_list(): if compiled_re.search(name): @@ -659,7 +610,7 @@ def auto_attach(self): self.flashAttachButton = False return else: - for target in auto_attach_list.split(";"): + for target in self.auto_attach_list.split(";"): for pid, _, name in utils.get_process_list(): if name.find(target) != -1: self.attach_to_pid(pid) @@ -1387,7 +1338,7 @@ def pushButton_Save_clicked(self): # Returns: a bool value indicates whether the operation succeeded. def attach_to_pid(self, pid): - attach_result = debugcore.attach(pid, gdb_path) + attach_result = debugcore.attach(pid, settings.gdb_path) if attach_result == typedefs.ATTACH_RESULT.SUCCESSFUL: self.apply_after_init() scanmem.pid(pid) @@ -1474,7 +1425,7 @@ def on_inferior_exit(self): self.lineEdit_Scan.setText("") self.reset_scan() self.on_status_running() - debugcore.init_gdb(gdb_path) + debugcore.init_gdb(settings.gdb_path) self.apply_after_init() self.flashAttachButton = True self.flashAttachButtonTimer.start(100) @@ -1533,12 +1484,12 @@ def update_progress_bar(self): # Loop restarts itself to wait for function execution, same for the functions below def address_table_loop(self): - if update_table and not exiting: + if self.update_table and not exiting: try: self.update_address_table() except: traceback.print_exc() - self.address_table_timer.start(table_update_interval) + self.address_table_timer.start(self.table_update_interval) def search_table_loop(self): if not exiting: @@ -1554,7 +1505,7 @@ def freeze_loop(self): self.freeze() except: traceback.print_exc() - self.freeze_timer.start(freeze_interval) + self.freeze_timer.start(self.freeze_interval) # ---------------------------------------------------- @@ -2388,7 +2339,7 @@ def accept(self): injection_method = typedefs.INJECTION_METHOD.DLOPEN elif self.radioButton_AdvancedInjection.isChecked(): injection_method = typedefs.INJECTION_METHOD.ADVANCED - self.settings.setValue("CodeInjection/code_injection_method", injection_method) + self.settings.setValue("CodeInjection/code_injection_method", settings.code_injection_method) self.settings.setValue("Disassemble/bring_disassemble_to_front", self.checkBox_BringDisassembleToFront.isChecked()) self.settings.setValue("Disassemble/instructions_per_scroll", current_instructions_shown) @@ -2450,11 +2401,12 @@ def config_gui(self): for hotkey in Hotkeys.get_hotkeys(): self.listWidget_Functions.addItem(hotkey.desc) self.hotkey_to_value[hotkey.name] = self.settings.value("Hotkeys/" + hotkey.name) - injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) - if injection_method == typedefs.INJECTION_METHOD.DLOPEN: + settings.code_injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) + if settings.code_injection_method == typedefs.INJECTION_METHOD.DLOPEN: self.radioButton_SimpleDLopenCall.setChecked(True) - elif injection_method == typedefs.INJECTION_METHOD.ADVANCED: + elif settings.code_injection_method == typedefs.INJECTION_METHOD.ADVANCED: self.radioButton_AdvancedInjection.setChecked(True) + self.checkBox_BringDisassembleToFront.setChecked( self.settings.value("Disassemble/bring_disassemble_to_front", type=bool)) self.lineEdit_InstructionsPerScroll.setText( @@ -2728,6 +2680,8 @@ def __init__(self, parent=None): class MemoryViewWindowForm(QMainWindow, MemoryViewWindow): process_stopped = pyqtSignal() process_running = pyqtSignal() + bring_disassemble_to_front: bool = False + instructions_per_scroll: int = 3 def set_dynamic_debug_hotkeys(self): self.actionBreak.setText(tr.BREAK.format(Hotkeys.break_hotkey.get_active_key())) @@ -3122,9 +3076,9 @@ def disassemble_scrollbar_sliderchanged(self, even): # self.bDisassemblyScrolling = False # return if current_value < midst: - self.tableWidget_Disassemble_scroll("previous", instructions_per_scroll) + self.tableWidget_Disassemble_scroll("previous", self.instructions_per_scroll) else: - self.tableWidget_Disassemble_scroll("next", instructions_per_scroll) + self.tableWidget_Disassemble_scroll("next", self.instructions_per_scroll) guiutils.center_scroll_bar(self.verticalScrollBar_Disassemble) self.bDisassemblyScrolling = False @@ -3471,7 +3425,7 @@ def on_process_stop(self): if self.tableWidget_Stack.rowCount() == 0: self.update_stack() self.refresh_hex_view() - if bring_disassemble_to_front: + if self.bring_disassemble_to_front: self.showMaximized() self.activateWindow() try: @@ -3737,9 +3691,9 @@ def widget_Disassemble_wheel_event(self, event): return steps = event.angleDelta() if steps.y() > 0: - self.tableWidget_Disassemble_scroll("previous", instructions_per_scroll) + self.tableWidget_Disassemble_scroll("previous", self.instructions_per_scroll) else: - self.tableWidget_Disassemble_scroll("next", instructions_per_scroll) + self.tableWidget_Disassemble_scroll("next", self.instructions_per_scroll) def disassemble_check_viewport(self, where, instruction_count): if debugcore.currentpid == -1: From 33e90ca3c061dc595adbefe7a680d160392a94eb Mon Sep 17 00:00:00 2001 From: Viktor Horsmanheimo Date: Wed, 7 Feb 2024 23:30:48 +0200 Subject: [PATCH 358/487] Simplify locale configuration In order to remove a global setting locale has been refactored. --- GUI/Settings/settings.py | 2 -- PINCE.py | 48 ++++++++++++++++++---------------------- tr/tr.py | 12 +++++++++- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/GUI/Settings/settings.py b/GUI/Settings/settings.py index ab28c3d3..ef0b2086 100644 --- a/GUI/Settings/settings.py +++ b/GUI/Settings/settings.py @@ -2,8 +2,6 @@ current_settings_version = "32" # Increase version by one if you change settings - -locale: str = "" # Unused, will be re-added in the future code_injection_method: int = 0 diff --git a/PINCE.py b/PINCE.py index 62595107..967fbded 100755 --- a/PINCE.py +++ b/PINCE.py @@ -30,9 +30,10 @@ gi.require_version('Gtk', '3.0') from tr.tr import TranslationConstants as tr +from tr.tr import language_list, get_locale from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ - QRegularExpressionValidator, QShortcut, QColorConstants + QRegularExpressionValidator, QShortcut, QColorConstants, QStandardItemModel, QStandardItem from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy @@ -92,22 +93,6 @@ from operator import add as opAdd, sub as opSub -# TODO: Carry all settings related things to their own script if possible -language_list = [ - ("English", "en_US"), - ("Italiano", "it_IT"), - ("简体中文", "zh_CN") -] - - -def get_locale(): - system_locale = QLocale.system().name() - for _, locale in language_list: - if system_locale == locale: - return locale - return language_list[0][1] - - if __name__ == '__main__': app = QApplication(sys.argv) app.setOrganizationName("PINCE") @@ -575,7 +560,6 @@ def apply_settings(self): settings.gdb_output_mode = typedefs.gdb_output_mode(*settings.gdb_output_mode) self.auto_attach_list = self.settings.value("General/auto_attach_list", type=str) self.auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) - settings.locale = self.settings.value("General/locale", type=str) app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), self.settings.value("General/logo_path", type=str)))) app.setPalette(get_theme(self.settings.value("General/theme", type=str))) @@ -2279,6 +2263,22 @@ def __init__(self, set_default_settings_func, parent=None): self.comboBox_Logo.currentIndexChanged.connect(self.comboBox_Logo_current_index_changed) self.comboBox_Theme.currentIndexChanged.connect(self.comboBox_Theme_current_index_changed) self.pushButton_HandleSignals.clicked.connect(self.pushButton_HandleSignals_clicked) + cur_loc = self.settings.value("General/locale", type=str) + + locale_model = QStandardItemModel() + for loc, name in language_list.items(): + item = QStandardItem() + item.setData(name, Qt.ItemDataRole.DisplayRole) + item.setData(loc, Qt.ItemDataRole.UserRole) + locale_model.appendRow(item) + + self.comboBox_Language.setModel(locale_model) + self.comboBox_Language.setCurrentText(language_list.get(cur_loc, "en_US")) + self.comboBox_Language.currentIndexChanged.connect( + lambda _: QMessageBox.information(self, tr.INFO, tr.LANG_RESET)) + + self.comboBox_Language.setCurrentText(cur_loc) + self.config_gui() def accept(self): @@ -2327,10 +2327,9 @@ def accept(self): return self.settings.setValue("General/auto_attach_list", self.lineEdit_AutoAttachList.text()) self.settings.setValue("General/auto_attach_regex", self.checkBox_AutoAttachRegex.isChecked()) - new_locale = language_list[self.comboBox_Language.currentIndex()][1] + new_locale = self.comboBox_Language.currentData(Qt.ItemDataRole.UserRole) self.settings.setValue("General/locale", new_locale) - if locale != new_locale: - QMessageBox.information(self, tr.INFO, tr.LANG_RESET) + self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) self.settings.setValue("General/theme", self.comboBox_Theme.currentText()) for hotkey in Hotkeys.get_hotkeys(): @@ -2376,12 +2375,7 @@ def config_gui(self): self.checkBox_OutputModeCommandInfo.setChecked(output_mode.command_info) self.lineEdit_AutoAttachList.setText(self.settings.value("General/auto_attach_list", type=str)) self.checkBox_AutoAttachRegex.setChecked(self.settings.value("General/auto_attach_regex", type=bool)) - self.comboBox_Language.clear() - cur_loc = self.settings.value("General/locale", type=str) - for lang, loc in language_list: - self.comboBox_Language.addItem(lang) - if loc == cur_loc: - self.comboBox_Language.setCurrentIndex(self.comboBox_Language.count()-1) + with QSignalBlocker(self.comboBox_Theme): self.comboBox_Theme.clear() cur_theme = self.settings.value("General/theme", type=str) diff --git a/tr/tr.py b/tr/tr.py index 26e4074f..f1f742ec 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -1,4 +1,14 @@ -from PyQt6.QtCore import QObject, QT_TR_NOOP, QT_TRANSLATE_NOOP +from PyQt6.QtCore import QObject, QLocale, QT_TR_NOOP, QT_TRANSLATE_NOOP + +language_list = { + "en_US": "English", + "it_IT": "Italiano", + "zh_CN": "简体中文" +} + +def get_locale(): + system_locale = QLocale.system().name() + return language_list.get(system_locale, "en_US") # This handles the default translations for QDialogButtonBox.StandardButton # Some of the standard button labels have an ampersand (&). It's used to denote an access key or keyboard shortcut From 7e1113c5116929bdcbc25e90f4fe025fda9f61e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 12 Feb 2024 23:21:51 +0300 Subject: [PATCH 359/487] Add ability to choose GDB version for install_gdb.sh --- install_gdb.sh | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/install_gdb.sh b/install_gdb.sh index 1eed7358..a61b623a 100755 --- a/install_gdb.sh +++ b/install_gdb.sh @@ -19,7 +19,11 @@ along with this program. If not, see . # This script installs a specific gdb version locally, the default installation script doesn't need this anymore, you can use it as a fallback if system gdb is being problematic # After installing a local gdb, you must specify its binary location via the Settings->Debug -GDB_VERSION="gdb-11.2" +echo "This script will install GDB locally in the gdb_pince folder" +echo "To see the available GDB versions, visit -> https://ftp.gnu.org/gnu/gdb/" +read -r -p "Enter the GDB version number (e.g., 14.1): " version_number + +GDB_VERSION="gdb-$version_number" if [ -z "$NUM_MAKE_JOBS" ]; then NUM_MAKE_JOBS=$(lscpu -p=core | uniq | awk '!/#/' | wc -l) @@ -36,20 +40,20 @@ mkdir -p gdb_pince cd gdb_pince || exit # clean the directory if another installation happened -rm -rf $GDB_VERSION +rm -rf "$GDB_VERSION" -if [ ! -e ${GDB_VERSION}.tar.gz ] ; then - wget "http://ftp.gnu.org/gnu/gdb/${GDB_VERSION}.tar.gz" +if [ ! -e "${GDB_VERSION}".tar.gz ] ; then + wget "http://ftp.gnu.org/gnu/gdb/${GDB_VERSION}.tar.gz" || exit fi -tar -zxvf ${GDB_VERSION}.tar.gz -cd $GDB_VERSION || exit +tar -zxvf "${GDB_VERSION}".tar.gz +cd "$GDB_VERSION" || exit echo "-------------------------------------------------------------------------" echo "DISCLAIMER" echo "-------------------------------------------------------------------------" echo "If you're not on debian or a similar distro with the 'apt' package manager the follow will not work if you don't have gcc and g++ installed" echo "Please install them manually for this to work, this issue will be addressed at a later date" -sudo apt-get install python3-dev libgmp3-dev +sudo apt-get install python3-dev libgmp3-dev libmpc-dev CC=gcc CXX=g++ ./configure --prefix="$(pwd)" --with-python=python3 && make -j"$NUM_MAKE_JOBS" MAKEINFO=true && sudo make -C gdb install From d3bd071e9b44d83f4b353339f8fd8fb4c6688358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 13 Feb 2024 17:11:35 +0300 Subject: [PATCH 360/487] Bugfixes and optimizations for settings --- GUI/Settings/settings.py | 31 +++---------- PINCE.py | 97 +++++++++++++++++----------------------- tr/tr.py | 13 +++--- 3 files changed, 55 insertions(+), 86 deletions(-) diff --git a/GUI/Settings/settings.py b/GUI/Settings/settings.py index ef0b2086..5864f9d4 100644 --- a/GUI/Settings/settings.py +++ b/GUI/Settings/settings.py @@ -1,12 +1,13 @@ import libpince.typedefs as typedefs -current_settings_version = "32" # Increase version by one if you change settings +current_settings_version = "33" # Increase version by one if you change settings # Unused, will be re-added in the future code_injection_method: int = 0 gdb_path: str = typedefs.PATHS.GDB gdb_output_mode: tuple = (True, True, True) +locale: str = "en_US" gdb_logging: bool = False interrupt_signal: str handle_signals: list = [] @@ -25,27 +26,7 @@ ["SIGMSG", True, True], ["SIGSOUND", True, True], ["SIGSAK", True, True], ["SIGPRIO", False, True], ["SIGCANCEL", False, True], ["SIGINFO", True, True], ["EXC_BAD_ACCESS", True, True], ["EXC_BAD_INSTRUCTION", True, True], ["EXC_ARITHMETIC", True, True], ["EXC_EMULATION", True, True], - ["EXC_SOFTWARE", True, True], ["EXC_BREAKPOINT", True, True], ["SIGLIBRT", False, True], - # - ['SIG32', True, True], - ['SIG33', True, True], ['SIG34', True, True], ['SIG35', True, True], ['SIG36', True, True], ['SIG37', True, True], - ['SIG38', True, True], ['SIG39', True, True], ['SIG40', True, True], ['SIG41', True, True], ['SIG42', True, True], - ['SIG43', True, True], ['SIG44', True, True], ['SIG45', True, True], ['SIG46', True, True], ['SIG47', True, True], - ['SIG48', True, True], ['SIG49', True, True], ['SIG50', True, True], ['SIG51', True, True], ['SIG52', True, True], - ['SIG53', True, True], ['SIG54', True, True], ['SIG55', True, True], ['SIG56', True, True], ['SIG57', True, True], - ['SIG58', True, True], ['SIG59', True, True], ['SIG60', True, True], ['SIG61', True, True], ['SIG62', True, True], - ['SIG63', True, True], ['SIG64', True, True], ['SIG65', True, True], ['SIG66', True, True], ['SIG67', True, True], - ['SIG68', True, True], ['SIG69', True, True], ['SIG70', True, True], ['SIG71', True, True], ['SIG72', True, True], - ['SIG73', True, True], ['SIG74', True, True], ['SIG75', True, True], ['SIG76', True, True], ['SIG77', True, True], - ['SIG78', True, True], ['SIG79', True, True], ['SIG80', True, True], ['SIG81', True, True], ['SIG82', True, True], - ['SIG83', True, True], ['SIG84', True, True], ['SIG85', True, True], ['SIG86', True, True], ['SIG87', True, True], - ['SIG88', True, True], ['SIG89', True, True], ['SIG90', True, True], ['SIG91', True, True], ['SIG92', True, True], - ['SIG93', True, True], ['SIG94', True, True], ['SIG95', True, True], ['SIG96', True, True], ['SIG97', True, True], - ['SIG98', True, True], ['SIG99', True, True], ['SIG100', True, True], ['SIG101', True, True], - ['SIG102', True, True], ['SIG103', True, True], ['SIG104', True, True], ['SIG105', True, True], - ['SIG106', True, True], ['SIG107', True, True], ['SIG108', True, True], ['SIG109', True, True], - ['SIG110', True, True], ['SIG111', True, True], ['SIG112', True, True], ['SIG113', True, True], - ['SIG114', True, True], ['SIG115', True, True], ['SIG116', True, True], ['SIG117', True, True], - ['SIG118', True, True], ['SIG119', True, True], ['SIG120', True, True], ['SIG121', True, True], - ['SIG122', True, True], ['SIG123', True, True], ['SIG124', True, True], ['SIG125', True, True], - ['SIG126', True, True], ['SIG127', True, True]] + ["EXC_SOFTWARE", True, True], ["EXC_BREAKPOINT", True, True], ["SIGLIBRT", False, True] +] +for x in range(32, 128): # Add signals SIG32-SIG127 + default_signals.append([f"SIG{x}", True, True]) \ No newline at end of file diff --git a/PINCE.py b/PINCE.py index 967fbded..fb58289d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -22,7 +22,6 @@ import GUI.Settings.settings as settings from GUI.Settings.hotkeys import Hotkeys -from GUI.Settings.settings import current_settings_version, gdb_logging, default_signals # This fixes GTK version mismatch issues and crashes on gnome # See #153 and #159 for more information @@ -100,14 +99,14 @@ app.setApplicationName("PINCE") QSettings.setPath(QSettings.Format.NativeFormat, QSettings.Scope.UserScope, utils.get_user_path(typedefs.USER_PATHS.CONFIG)) - settings = QSettings() + settings_instance = QSettings() translator = QTranslator() try: - locale = settings.value("General/locale", type=str) + locale = settings_instance.value("General/locale", type=str) except SystemError: # We're reading the settings for the first time here # If there's an error due to python objects, clear settings - settings.clear() + settings_instance.clear() locale = None if not locale: locale = get_locale() @@ -394,7 +393,7 @@ def __init__(self): except Exception as e: print("An exception occurred while reading settings version\n", e) settings_version = None - if settings_version != current_settings_version: + if settings_version != settings.current_settings_version: print("Settings version mismatch, rolling back to the default configuration") self.settings.clear() self.set_default_settings() @@ -522,13 +521,13 @@ def set_default_settings(self): self.settings.setValue("gdb_path", typedefs.PATHS.GDB) self.settings.setValue("gdb_logging", False) self.settings.setValue("interrupt_signal", "SIGINT") - self.settings.setValue("handle_signals", json.dumps(default_signals)) + self.settings.setValue("handle_signals", json.dumps(settings.default_signals)) self.settings.endGroup() self.settings.beginGroup("Java") self.settings.setValue("ignore_segfault", True) self.settings.endGroup() self.settings.beginGroup("Misc") - self.settings.setValue("version", current_settings_version) + self.settings.setValue("version", settings.current_settings_version) self.settings.endGroup() self.apply_settings() @@ -552,7 +551,6 @@ def apply_after_init(self): debugcore.set_interrupt_signal(settings.interrupt_signal) # Needs to be called after handle_signals def apply_settings(self): - self.update_table = self.settings.value("General/auto_update_address_table", type=bool) self.table_update_interval = self.settings.value("General/address_table_update_interval", type=int) self.freeze_interval = self.settings.value("General/freeze_interval", type=int) @@ -560,6 +558,7 @@ def apply_settings(self): settings.gdb_output_mode = typedefs.gdb_output_mode(*settings.gdb_output_mode) self.auto_attach_list = self.settings.value("General/auto_attach_list", type=str) self.auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) + settings.locale = self.settings.value("General/locale", type=str) app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), self.settings.value("General/logo_path", type=str)))) app.setPalette(get_theme(self.settings.value("General/theme", type=str))) @@ -2250,9 +2249,28 @@ def __init__(self, set_default_settings_func, parent=None): self.set_default_settings = set_default_settings_func self.hotkey_to_value = {} # Dict[str:str]-->Dict[Hotkey.name:settings_value] self.handle_signals_data = "" - self.listWidget_Options.currentRowChanged.connect(self.change_display) icons_directory = guiutils.get_icons_directory() self.pushButton_GDBPath.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) + locale_model = QStandardItemModel() + for loc, name in language_list.items(): + item = QStandardItem() + item.setData(name, Qt.ItemDataRole.DisplayRole) + item.setData(loc, Qt.ItemDataRole.UserRole) + locale_model.appendRow(item) + self.comboBox_Language.setModel(locale_model) + self.comboBox_InterruptSignal.addItem("SIGINT") + self.comboBox_InterruptSignal.addItems([f"SIG{x}" for x in range(signal.SIGRTMIN, signal.SIGRTMAX+1)]) + self.comboBox_InterruptSignal.setStyleSheet("combobox-popup: 0;") # maxVisibleItems doesn't work otherwise + self.comboBox_Theme.addItems(theme_list) + logo_directory = utils.get_logo_directory() + logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") + for logo in logo_list: + self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) + for hotkey in Hotkeys.get_hotkeys(): + self.listWidget_Functions.addItem(hotkey.desc) + self.config_gui() + + self.listWidget_Options.currentRowChanged.connect(self.change_display) self.listWidget_Functions.currentRowChanged.connect(self.listWidget_Functions_current_row_changed) self.keySequenceEdit_Hotkey.keySequenceChanged.connect(self.keySequenceEdit_Hotkey_key_sequence_changed) self.pushButton_ClearHotkey.clicked.connect(self.pushButton_ClearHotkey_clicked) @@ -2263,23 +2281,6 @@ def __init__(self, set_default_settings_func, parent=None): self.comboBox_Logo.currentIndexChanged.connect(self.comboBox_Logo_current_index_changed) self.comboBox_Theme.currentIndexChanged.connect(self.comboBox_Theme_current_index_changed) self.pushButton_HandleSignals.clicked.connect(self.pushButton_HandleSignals_clicked) - cur_loc = self.settings.value("General/locale", type=str) - - locale_model = QStandardItemModel() - for loc, name in language_list.items(): - item = QStandardItem() - item.setData(name, Qt.ItemDataRole.DisplayRole) - item.setData(loc, Qt.ItemDataRole.UserRole) - locale_model.appendRow(item) - - self.comboBox_Language.setModel(locale_model) - self.comboBox_Language.setCurrentText(language_list.get(cur_loc, "en_US")) - self.comboBox_Language.currentIndexChanged.connect( - lambda _: QMessageBox.information(self, tr.INFO, tr.LANG_RESET)) - - self.comboBox_Language.setCurrentText(cur_loc) - - self.config_gui() def accept(self): try: @@ -2328,8 +2329,9 @@ def accept(self): self.settings.setValue("General/auto_attach_list", self.lineEdit_AutoAttachList.text()) self.settings.setValue("General/auto_attach_regex", self.checkBox_AutoAttachRegex.isChecked()) new_locale = self.comboBox_Language.currentData(Qt.ItemDataRole.UserRole) + if new_locale != settings.locale: + QMessageBox.information(self, tr.INFO, tr.LANG_RESET) self.settings.setValue("General/locale", new_locale) - self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) self.settings.setValue("General/theme", self.comboBox_Theme.currentText()) for hotkey in Hotkeys.get_hotkeys(): @@ -2338,7 +2340,7 @@ def accept(self): injection_method = typedefs.INJECTION_METHOD.DLOPEN elif self.radioButton_AdvancedInjection.isChecked(): injection_method = typedefs.INJECTION_METHOD.ADVANCED - self.settings.setValue("CodeInjection/code_injection_method", settings.code_injection_method) + self.settings.setValue("CodeInjection/code_injection_method", injection_method) self.settings.setValue("Disassemble/bring_disassemble_to_front", self.checkBox_BringDisassembleToFront.isChecked()) self.settings.setValue("Disassemble/instructions_per_scroll", current_instructions_shown) @@ -2375,30 +2377,20 @@ def config_gui(self): self.checkBox_OutputModeCommandInfo.setChecked(output_mode.command_info) self.lineEdit_AutoAttachList.setText(self.settings.value("General/auto_attach_list", type=str)) self.checkBox_AutoAttachRegex.setChecked(self.settings.value("General/auto_attach_regex", type=bool)) - + current_locale = self.settings.value("General/locale", type=str) + self.comboBox_Language.setCurrentText(language_list.get(current_locale, "en_US")) with QSignalBlocker(self.comboBox_Theme): - self.comboBox_Theme.clear() - cur_theme = self.settings.value("General/theme", type=str) - for thm in theme_list: - self.comboBox_Theme.addItem(thm) - if thm == cur_theme: - self.comboBox_Theme.setCurrentIndex(self.comboBox_Theme.count()-1) - logo_directory = utils.get_logo_directory() - logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") + self.comboBox_Theme.setCurrentText(self.settings.value("General/theme", type=str)) with QSignalBlocker(self.comboBox_Logo): - self.comboBox_Logo.clear() - for logo in logo_list: - self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) - self.comboBox_Logo.setCurrentIndex(logo_list.index(self.settings.value("General/logo_path", type=str))) - self.listWidget_Functions.clear() + self.comboBox_Logo.setCurrentText(self.settings.value("General/logo_path", type=str)) self.hotkey_to_value.clear() for hotkey in Hotkeys.get_hotkeys(): - self.listWidget_Functions.addItem(hotkey.desc) self.hotkey_to_value[hotkey.name] = self.settings.value("Hotkeys/" + hotkey.name) - settings.code_injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) - if settings.code_injection_method == typedefs.INJECTION_METHOD.DLOPEN: + self.listWidget_Functions_current_row_changed(self.listWidget_Functions.currentRow()) + code_injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) + if code_injection_method == typedefs.INJECTION_METHOD.DLOPEN: self.radioButton_SimpleDLopenCall.setChecked(True) - elif settings.code_injection_method == typedefs.INJECTION_METHOD.ADVANCED: + elif code_injection_method == typedefs.INJECTION_METHOD.ADVANCED: self.radioButton_AdvancedInjection.setChecked(True) self.checkBox_BringDisassembleToFront.setChecked( @@ -2407,12 +2399,7 @@ def config_gui(self): str(self.settings.value("Disassemble/instructions_per_scroll", type=int))) self.lineEdit_GDBPath.setText(str(self.settings.value("Debug/gdb_path", type=str))) self.checkBox_GDBLogging.setChecked(self.settings.value("Debug/gdb_logging", type=bool)) - cur_signal = self.settings.value("Debug/interrupt_signal", type=str) - self.comboBox_InterruptSignal.clear() - self.comboBox_InterruptSignal.addItem("SIGINT") - self.comboBox_InterruptSignal.addItems([f"SIG{x}" for x in range(signal.SIGRTMIN, signal.SIGRTMAX+1)]) - self.comboBox_InterruptSignal.setCurrentIndex(self.comboBox_InterruptSignal.findText(cur_signal)) - self.comboBox_InterruptSignal.setStyleSheet("combobox-popup: 0;") # maxVisibleItems doesn't work otherwise + self.comboBox_InterruptSignal.setCurrentText(self.settings.value("Debug/interrupt_signal", type=str)) self.checkBox_JavaSegfault.setChecked(self.settings.value("Java/ignore_segfault", type=bool)) def change_display(self, index): @@ -5419,14 +5406,14 @@ def refresh_contents(self): log_path = utils.get_logging_file(debugcore.currentpid) self.setWindowTitle(tr.LOG_FILE.format(debugcore.currentpid)) self.label_FilePath.setText(tr.LOG_CONTENTS.format(log_path, 20000)) - logging_status = f"{tr.ON}" if gdb_logging else f"{tr.OFF}" - self.label_LoggingStatus.setText(f"{tr.LOG_STATUS.format(logging_status)}") + log_status = f"{tr.ON}" if settings.gdb_logging else f"{tr.OFF}" + self.label_LoggingStatus.setText(f"{tr.LOG_STATUS.format(log_status)}") try: log_file = open(log_path) except OSError: self.textBrowser_LogContent.clear() error_message = tr.LOG_READ_ERROR.format(log_path) + "\n" - if not gdb_logging: + if not settings.gdb_logging: error_message += tr.SETTINGS_ENABLE_LOG self.textBrowser_LogContent.setText(error_message) return diff --git a/tr/tr.py b/tr/tr.py index f1f742ec..3f338a00 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -1,14 +1,15 @@ from PyQt6.QtCore import QObject, QLocale, QT_TR_NOOP, QT_TRANSLATE_NOOP +from collections import OrderedDict -language_list = { - "en_US": "English", - "it_IT": "Italiano", - "zh_CN": "简体中文" -} +language_list = OrderedDict([ + ("en_US", "English"), + ("it_IT", "Italiano"), + ("zh_CN", "简体中文") +]) def get_locale(): system_locale = QLocale.system().name() - return language_list.get(system_locale, "en_US") + return system_locale if system_locale in language_list else "en_US" # This handles the default translations for QDialogButtonBox.StandardButton # Some of the standard button labels have an ampersand (&). It's used to denote an access key or keyboard shortcut From 5c906d77812c1cbfa4c63564dc1aee203c0922ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 14 Feb 2024 16:29:23 +0300 Subject: [PATCH 361/487] Redesign hotkeys and fix translations --- GUI/Settings/hotkeys.py | 105 +++++++++++++++++++++------------------- PINCE.py | 39 +++++++-------- 2 files changed, 74 insertions(+), 70 deletions(-) diff --git a/GUI/Settings/hotkeys.py b/GUI/Settings/hotkeys.py index ee5497a4..d66a56fb 100644 --- a/GUI/Settings/hotkeys.py +++ b/GUI/Settings/hotkeys.py @@ -1,56 +1,59 @@ from keyboard import add_hotkey, remove_hotkey - +from typing import Callable from tr.tr import TranslationConstants as tr +class Hotkey: + def __init__(self, name="", desc="", default="", func=None, custom="", handle=None) -> None: + self.name = name + self.desc = desc + self.default = default + self.func = func + self.custom = custom + if default == "" or func is None: + self.handle = handle + else: + self.handle = add_hotkey(default, func) + + def change_key(self, custom: str) -> None: + if self.handle is not None: + remove_hotkey(self.handle) + self.handle = None + self.custom = custom + if custom == '': + return + self.handle = add_hotkey(custom.lower(), self.func) + + def change_func(self, func: Callable) -> None: + self.func = func + if self.handle is not None: + remove_hotkey(self.handle) + if self.custom != "": + self.handle = add_hotkey(self.custom, func) + elif self.default != "": + self.handle = add_hotkey(self.default, func) + + def get_active_key(self) -> str: + if self.custom == "": + return self.default + return self.custom + + class Hotkeys: - class Hotkey: - def __init__(self, name="", desc="", default="", func=None, custom="", handle=None): - self.name = name - self.desc = desc - self.default = default - self.func = func - self.custom = custom - if default == "" or func is None: - self.handle = handle - else: - self.handle = add_hotkey(default, func) - - def change_key(self, custom): - if self.handle is not None: - remove_hotkey(self.handle) - self.handle = None - self.custom = custom - if custom == '': - return - self.handle = add_hotkey(custom.lower(), self.func) - - def change_func(self, func): - self.func = func - if self.handle is not None: - remove_hotkey(self.handle) - if self.custom != "": - self.handle = add_hotkey(self.custom, func) - elif self.default != "": - self.handle = add_hotkey(self.default, func) - - def get_active_key(self): - if self.custom == "": - return self.default - return self.custom - - pause_hotkey = Hotkey("pause_hotkey", tr.PAUSE_HOTKEY, "F1") - break_hotkey = Hotkey("break_hotkey", tr.BREAK_HOTKEY, "F2") - continue_hotkey = Hotkey("continue_hotkey", tr.CONTINUE_HOTKEY, "F3") - toggle_attach_hotkey = Hotkey("toggle_attach_hotkey", tr.TOGGLE_ATTACH_HOTKEY, "Shift+F10") - exact_scan_hotkey = Hotkey("exact_scan_hotkey", tr.EXACT_SCAN_HOTKEY, "") - increased_scan_hotkey = Hotkey("increased_scan_hotkey", tr.INC_SCAN_HOTKEY, "") - decreased_scan_hotkey = Hotkey("decreased_scan_hotkey", tr.DEC_SCAN_HOTKEY, "") - changed_scan_hotkey = Hotkey("changed_scan_hotkey", tr.CHANGED_SCAN_HOTKEY, "") - unchanged_scan_hotkey = Hotkey("unchanged_scan_hotkey", tr.UNCHANGED_SCAN_HOTKEY, "") - - @staticmethod - def get_hotkeys(): - return Hotkeys.pause_hotkey, Hotkeys.break_hotkey, Hotkeys.continue_hotkey, Hotkeys.toggle_attach_hotkey, \ - Hotkeys.exact_scan_hotkey, Hotkeys.increased_scan_hotkey, Hotkeys.decreased_scan_hotkey, \ - Hotkeys.changed_scan_hotkey, Hotkeys.unchanged_scan_hotkey + def __init__(self) -> None: + self.pause_hotkey = Hotkey("pause_hotkey", tr.PAUSE_HOTKEY, "F1") + self.break_hotkey = Hotkey("break_hotkey", tr.BREAK_HOTKEY, "F2") + self.continue_hotkey = Hotkey("continue_hotkey", tr.CONTINUE_HOTKEY, "F3") + self.toggle_attach_hotkey = Hotkey("toggle_attach_hotkey", tr.TOGGLE_ATTACH_HOTKEY, "Shift+F10") + self.exact_scan_hotkey = Hotkey("exact_scan_hotkey", tr.EXACT_SCAN_HOTKEY, "") + self.increased_scan_hotkey = Hotkey("increased_scan_hotkey", tr.INC_SCAN_HOTKEY, "") + self.decreased_scan_hotkey = Hotkey("decreased_scan_hotkey", tr.DEC_SCAN_HOTKEY, "") + self.changed_scan_hotkey = Hotkey("changed_scan_hotkey", tr.CHANGED_SCAN_HOTKEY, "") + self.unchanged_scan_hotkey = Hotkey("unchanged_scan_hotkey", tr.UNCHANGED_SCAN_HOTKEY, "") + + def get_hotkeys(self) -> list[Hotkey]: + hotkey_list = [] + for _, value in vars(self).items(): + if isinstance(value, Hotkey): + hotkey_list.append(value) + return hotkey_list diff --git a/PINCE.py b/PINCE.py index fb58289d..36b3a48e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -113,6 +113,7 @@ translator.load(f'i18n/qm/{locale}.qm') app.installTranslator(translator) tr.translate() + hotkeys = Hotkeys() # Create the instance after translations to ensure hotkeys are translated instances = [] # Holds temporary instances that will be deleted later on @@ -362,15 +363,15 @@ def __init__(self): self.setupUi(self) self.hotkey_to_shortcut = {} hotkey_to_func = { - Hotkeys.pause_hotkey: self.pause_hotkey_pressed, - Hotkeys.break_hotkey: self.break_hotkey_pressed, - Hotkeys.continue_hotkey: self.continue_hotkey_pressed, - Hotkeys.toggle_attach_hotkey: self.toggle_attach_hotkey_pressed, - Hotkeys.exact_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.EXACT), - Hotkeys.increased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.INCREASED), - Hotkeys.decreased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.DECREASED), - Hotkeys.changed_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.CHANGED), - Hotkeys.unchanged_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.UNCHANGED) + hotkeys.pause_hotkey: self.pause_hotkey_pressed, + hotkeys.break_hotkey: self.break_hotkey_pressed, + hotkeys.continue_hotkey: self.continue_hotkey_pressed, + hotkeys.toggle_attach_hotkey: self.toggle_attach_hotkey_pressed, + hotkeys.exact_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.EXACT), + hotkeys.increased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.INCREASED), + hotkeys.decreased_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.DECREASED), + hotkeys.changed_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.CHANGED), + hotkeys.unchanged_scan_hotkey: lambda: self.nextscan_hotkey_pressed(typedefs.SCAN_TYPE.UNCHANGED) } for hotkey, func in hotkey_to_func.items(): hotkey.change_func(func) @@ -507,7 +508,7 @@ def set_default_settings(self): self.settings.setValue("theme", "System Default") self.settings.endGroup() self.settings.beginGroup("Hotkeys") - for hotkey in Hotkeys.get_hotkeys(): + for hotkey in hotkeys.get_hotkeys(): self.settings.setValue(hotkey.name, hotkey.default) self.settings.endGroup() self.settings.beginGroup("CodeInjection") @@ -563,7 +564,7 @@ def apply_settings(self): self.settings.value("General/logo_path", type=str)))) app.setPalette(get_theme(self.settings.value("General/theme", type=str))) debugcore.set_gdb_output_mode(settings.gdb_output_mode) - for hotkey in Hotkeys.get_hotkeys(): + for hotkey in hotkeys.get_hotkeys(): hotkey.change_key(self.settings.value("Hotkeys/" + hotkey.name)) try: self.memory_view_window.set_dynamic_debug_hotkeys() @@ -2266,7 +2267,7 @@ def __init__(self, set_default_settings_func, parent=None): logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") for logo in logo_list: self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) - for hotkey in Hotkeys.get_hotkeys(): + for hotkey in hotkeys.get_hotkeys(): self.listWidget_Functions.addItem(hotkey.desc) self.config_gui() @@ -2334,7 +2335,7 @@ def accept(self): self.settings.setValue("General/locale", new_locale) self.settings.setValue("General/logo_path", self.comboBox_Logo.currentText()) self.settings.setValue("General/theme", self.comboBox_Theme.currentText()) - for hotkey in Hotkeys.get_hotkeys(): + for hotkey in hotkeys.get_hotkeys(): self.settings.setValue("Hotkeys/" + hotkey.name, self.hotkey_to_value[hotkey.name]) if self.radioButton_SimpleDLopenCall.isChecked(): injection_method = typedefs.INJECTION_METHOD.DLOPEN @@ -2384,7 +2385,7 @@ def config_gui(self): with QSignalBlocker(self.comboBox_Logo): self.comboBox_Logo.setCurrentText(self.settings.value("General/logo_path", type=str)) self.hotkey_to_value.clear() - for hotkey in Hotkeys.get_hotkeys(): + for hotkey in hotkeys.get_hotkeys(): self.hotkey_to_value[hotkey.name] = self.settings.value("Hotkeys/" + hotkey.name) self.listWidget_Functions_current_row_changed(self.listWidget_Functions.currentRow()) code_injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) @@ -2409,7 +2410,7 @@ def listWidget_Functions_current_row_changed(self, index): if index == -1: self.keySequenceEdit_Hotkey.clear() else: - self.keySequenceEdit_Hotkey.setKeySequence(self.hotkey_to_value[Hotkeys.get_hotkeys()[index].name]) + self.keySequenceEdit_Hotkey.setKeySequence(self.hotkey_to_value[hotkeys.get_hotkeys()[index].name]) def keySequenceEdit_Hotkey_key_sequence_changed(self): index = self.listWidget_Functions.currentIndex().row() @@ -2417,7 +2418,7 @@ def keySequenceEdit_Hotkey_key_sequence_changed(self): self.keySequenceEdit_Hotkey.clear() else: self.hotkey_to_value[ - Hotkeys.get_hotkeys()[index].name] = self.keySequenceEdit_Hotkey.keySequence().toString() + hotkeys.get_hotkeys()[index].name] = self.keySequenceEdit_Hotkey.keySequence().toString() def pushButton_ClearHotkey_clicked(self): self.keySequenceEdit_Hotkey.clear() @@ -2665,9 +2666,9 @@ class MemoryViewWindowForm(QMainWindow, MemoryViewWindow): instructions_per_scroll: int = 3 def set_dynamic_debug_hotkeys(self): - self.actionBreak.setText(tr.BREAK.format(Hotkeys.break_hotkey.get_active_key())) - self.actionRun.setText(tr.RUN.format(Hotkeys.continue_hotkey.get_active_key())) - self.actionToggle_Attach.setText(tr.TOGGLE_ATTACH.format(Hotkeys.toggle_attach_hotkey.get_active_key())) + self.actionBreak.setText(tr.BREAK.format(hotkeys.break_hotkey.get_active_key())) + self.actionRun.setText(tr.RUN.format(hotkeys.continue_hotkey.get_active_key())) + self.actionToggle_Attach.setText(tr.TOGGLE_ATTACH.format(hotkeys.toggle_attach_hotkey.get_active_key())) def set_debug_menu_shortcuts(self): self.shortcut_step = QShortcut(QKeySequence("F7"), self) From f4e36e82bfc63f3da42db57ae67b437d4c379a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 15 Feb 2024 21:57:35 +0300 Subject: [PATCH 362/487] Remove instances hack and fix minor bugs --- GUI/AddAddressManuallyDialog.py | 2 +- GUI/AddAddressManuallyDialog.ui | 2 +- GUI/EditTypeDialog.py | 2 +- GUI/EditTypeDialog.ui | 2 +- GUI/Labels/FlagRegisterLabel.py | 14 +- GUI/Labels/RegisterLabel.py | 34 +-- GUI/LoadingDialog.py | 28 +- GUI/LoadingDialog.ui | 49 +-- GUI/Utils/guiutils.py | 17 +- PINCE.py | 512 ++++++++++++++------------------ 10 files changed, 265 insertions(+), 397 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 93897d95..5c8579ec 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -12,7 +12,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(273, 431) + Dialog.resize(240, 431) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.verticalLayout_3 = QtWidgets.QVBoxLayout() diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index babbffc6..a24939e1 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -6,7 +6,7 @@ 0 0 - 273 + 240 431 diff --git a/GUI/EditTypeDialog.py b/GUI/EditTypeDialog.py index 5521ffad..ab428ac3 100644 --- a/GUI/EditTypeDialog.py +++ b/GUI/EditTypeDialog.py @@ -12,7 +12,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(343, 163) + Dialog.resize(235, 163) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_3 = QtWidgets.QHBoxLayout() diff --git a/GUI/EditTypeDialog.ui b/GUI/EditTypeDialog.ui index 8e024ceb..5ee137c3 100644 --- a/GUI/EditTypeDialog.ui +++ b/GUI/EditTypeDialog.ui @@ -6,7 +6,7 @@ 0 0 - 343 + 235 163 diff --git a/GUI/Labels/FlagRegisterLabel.py b/GUI/Labels/FlagRegisterLabel.py index 4c15aa01..5d4ca795 100644 --- a/GUI/Labels/FlagRegisterLabel.py +++ b/GUI/Labels/FlagRegisterLabel.py @@ -15,10 +15,11 @@ along with this program. If not, see . """ from PyQt6.QtWidgets import QLabel -from PyQt6.QtGui import QCursor +from PyQt6.QtGui import QCursor, QMouseEvent, QEnterEvent from PyQt6.QtCore import Qt from libpince import debugcore, typedefs from PINCE import InputDialogForm +from GUI.Utils import guiutils from tr.tr import TranslationConstants as tr @@ -35,16 +36,19 @@ def set_value(self, value): self.setStyleSheet("") self.setText(new) - def enterEvent(self, QEvent): + def enterEvent(self, event: QEnterEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + super().enterEvent(event) - def mouseDoubleClickEvent(self, QMouseEvent): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + def mouseDoubleClickEvent(self, event: QMouseEvent): + if event.button() != Qt.MouseButton.LeftButton or debugcore.currentpid == -1 or \ + debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return registers = debugcore.read_registers() current_flag = self.objectName().lower() label_text = tr.ENTER_FLAG_VALUE.format(self.objectName()) - register_dialog = InputDialogForm(item_list=[(label_text, ["0", "1", int(registers[current_flag])])]) + parent = guiutils.search_parents_by_function(self, "set_debug_menu_shortcuts") + register_dialog = InputDialogForm(parent, [(label_text, ["0", "1", int(registers[current_flag])])]) if register_dialog.exec(): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return diff --git a/GUI/Labels/RegisterLabel.py b/GUI/Labels/RegisterLabel.py index 48baa78f..4e5923ab 100644 --- a/GUI/Labels/RegisterLabel.py +++ b/GUI/Labels/RegisterLabel.py @@ -15,7 +15,7 @@ along with this program. If not, see . """ from PyQt6.QtWidgets import QLabel, QMenu, QApplication -from PyQt6.QtGui import QCursor +from PyQt6.QtGui import QCursor, QMouseEvent, QEnterEvent, QContextMenuEvent from PyQt6.QtCore import Qt from libpince import debugcore, typedefs from PINCE import InputDialogForm @@ -35,23 +35,26 @@ def set_value(self, value): self.setStyleSheet("") self.setText(new) - def enterEvent(self, QEvent): + def enterEvent(self, event: QEnterEvent): self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + super().enterEvent(event) - def mouseDoubleClickEvent(self, QMouseEvent): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + def mouseDoubleClickEvent(self, event: QMouseEvent): + if event.button() != Qt.MouseButton.LeftButton or debugcore.currentpid == -1 or \ + debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return registers = debugcore.read_registers() current_register = self.objectName().lower() - register_dialog = InputDialogForm( - item_list=[(tr.ENTER_REGISTER_VALUE.format(self.objectName()), registers[current_register])]) + items = [(tr.ENTER_REGISTER_VALUE.format(self.objectName()), registers[current_register])] + memory_view = guiutils.search_parents_by_function(self, "set_debug_menu_shortcuts") + register_dialog = InputDialogForm(memory_view, items) if register_dialog.exec(): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return debugcore.set_convenience_variable(current_register, register_dialog.get_values()) self.set_value(debugcore.read_registers()[current_register]) - def contextMenuEvent(self, QContextMenuEvent): + def contextMenuEvent(self, event: QContextMenuEvent): menu = QMenu() copy = menu.addAction(tr.COPY) menu.addSeparator() @@ -59,17 +62,14 @@ def contextMenuEvent(self, QContextMenuEvent): show_in_disassembler = menu.addAction(tr.SHOW_DISASSEMBLER) font_size = self.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec(QContextMenuEvent.globalPos()) + action = menu.exec(event.globalPos()) + memory_view = guiutils.search_parents_by_function(self, "set_debug_menu_shortcuts") if action == show_in_hex_view: - parent = guiutils.search_parents_by_function(self, "hex_dump_address") - if parent.objectName() == "MainWindow_MemoryView": - address = self.text().split("=")[-1] - address_int = int(address, 16) - parent.hex_dump_address(address_int) + address = self.text().split("=")[-1] + address_int = int(address, 16) + memory_view.hex_dump_address(address_int) elif action == show_in_disassembler: - parent = guiutils.search_parents_by_function(self, "disassemble_expression") - if parent.objectName() == "MainWindow_MemoryView": - address = self.text().split("=")[-1] - parent.disassemble_expression(address) + address = self.text().split("=")[-1] + memory_view.disassemble_expression(address) elif action == copy: QApplication.instance().clipboard().setText(self.text().split("=")[1]) diff --git a/GUI/LoadingDialog.py b/GUI/LoadingDialog.py index 15858c26..f7066e80 100644 --- a/GUI/LoadingDialog.py +++ b/GUI/LoadingDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'LoadingDialog.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,14 +12,14 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(208, 89) - self.gridLayout_2 = QtWidgets.QGridLayout(Dialog) - self.gridLayout_2.setObjectName("gridLayout_2") + Dialog.resize(107, 71) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) - self.label_Animated = QtWidgets.QLabel(Dialog) + self.label_Animated = QtWidgets.QLabel(parent=Dialog) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -29,30 +29,20 @@ def setupUi(self, Dialog): self.label_Animated.setScaledContents(False) self.label_Animated.setObjectName("label_Animated") self.horizontalLayout.addWidget(self.label_Animated) - self.label_StatusText = QtWidgets.QLabel(Dialog) + self.label_StatusText = QtWidgets.QLabel(parent=Dialog) self.label_StatusText.setObjectName("label_StatusText") self.horizontalLayout.addWidget(self.label_StatusText) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem1) - 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.setObjectName("gridLayout") - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.gridLayout.addItem(spacerItem2, 0, 0, 1, 1) - self.pushButton_Cancel = QtWidgets.QPushButton(self.widget_Cancel) + self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.pushButton_Cancel = QtWidgets.QPushButton(parent=Dialog) self.pushButton_Cancel.setObjectName("pushButton_Cancel") - self.gridLayout.addWidget(self.pushButton_Cancel, 0, 1, 1, 1) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.gridLayout.addItem(spacerItem3, 0, 2, 1, 1) - self.gridLayout_2.addWidget(self.widget_Cancel, 1, 0, 1, 1) + self.gridLayout.addWidget(self.pushButton_Cancel, 1, 0, 1, 1) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) 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 0f6ad516..2c02b567 100644 --- a/GUI/LoadingDialog.ui +++ b/GUI/LoadingDialog.ui @@ -6,14 +6,11 @@ 0 0 - 208 - 89 + 107 + 71 - - Dialog - - + @@ -68,42 +65,10 @@ - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Cancel - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + Cancel + diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index e4ce643e..f0fea38d 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -43,24 +43,13 @@ def center(window: QWidget): #:tag:GUI def center_to_parent(window: QWidget): - """Center the given window to it's parent + """Center the given window to its parent Args: - window (QWidget): The window that'll be centered to it's parent + window (QWidget): The window that'll be centered to its parent """ parent: QWidget = window.parent() - window.move(parent.frameGeometry().center() - window.frameGeometry().center()) - - -#:tag:GUI -def center_to_window(window_secondary: QWidget, window_main: QWidget): - """Center the given window_secondary to window_main - - Args: - window_secondary (QQWidget): The window that'll be centered to window_main - window_main (QWidget): The window that window_secondary will centered to - """ - window_secondary.move(window_main.frameGeometry().center() - window_secondary.frameGeometry().center()) + window.move(parent.frameGeometry().center() - window.rect().center()) #:tag:GUI diff --git a/PINCE.py b/PINCE.py index 36b3a48e..48c6f76d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -32,7 +32,7 @@ from tr.tr import language_list, get_locale from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ - QRegularExpressionValidator, QShortcut, QColorConstants, QStandardItemModel, QStandardItem + QRegularExpressionValidator, QShortcut, QColorConstants, QStandardItemModel, QStandardItem, QCloseEvent from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy @@ -115,8 +115,6 @@ tr.translate() hotkeys = Hotkeys() # Create the instance after translations to ensure hotkeys are translated -instances = [] # Holds temporary instances that will be deleted later on - # represents the index of columns in instructions restore table INSTR_ADDR_COL = 0 INSTR_AOB_COL = 1 @@ -239,7 +237,7 @@ class WorkerSignals(QObject): class Worker(QRunnable): def __init__(self, fn, *args, **kwargs): - super(Worker, self).__init__() + super().__init__() self.fn = fn self.args = args self.kwargs = kwargs @@ -311,7 +309,7 @@ class AwaitAsyncOutput(QThread): async_output_ready = pyqtSignal(str) def __init__(self): - super(AwaitAsyncOutput, self).__init__() + super().__init__() self.queue_active = True def run(self): @@ -375,7 +373,6 @@ def __init__(self): } for hotkey, func in hotkey_to_func.items(): hotkey.change_func(func) - guiutils.center(self) self.treeWidget_AddressTable.setColumnWidth(FROZEN_COL, 50) self.treeWidget_AddressTable.setColumnWidth(DESC_COL, 150) self.treeWidget_AddressTable.setColumnWidth(ADDR_COL, 150) @@ -384,7 +381,6 @@ def __init__(self): self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) self.settings = QSettings() self.memory_view_window = MemoryViewWindowForm(self) - self.about_widget = AboutWidgetForm() self.await_exit_thread = AwaitProcessExit() if not os.path.exists(self.settings.fileName()): @@ -407,7 +403,7 @@ def __init__(self): try: debugcore.init_gdb(settings.gdb_path) except pexpect.EOF: - InputDialogForm(item_list=[(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() + InputDialogForm(self, [(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() else: self.apply_after_init() self.await_exit_thread.process_exited.connect(self.on_inferior_exit) @@ -492,6 +488,7 @@ def __init__(self): self.flashAttachButton_gradiantState = 0 self.flashAttachButtonTimer.start(100) self.auto_attach() + guiutils.center(self) # Please refrain from using python specific objects in settings, use json-compatible ones instead # Using python objects causes issues when filenames change @@ -737,7 +734,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): address = selected_row.text(ADDR_COL).strip("P->") # @todo Maybe rework address grabbing logic in the future address_data = selected_row.data(ADDR_COL, Qt.ItemDataRole.UserRole) if isinstance(address_data, typedefs.PointerType): - selection_dialog = TrackSelectorDialogForm() + selection_dialog = TrackSelectorDialogForm(self) selection_dialog.exec() if not selection_dialog.selection: return @@ -752,7 +749,7 @@ def exec_track_watchpoint_widget(self, watchpoint_type): byte_len = value_type.length else: byte_len = typedefs.index_to_valuetype_dict[value_type.value_index][0] - TrackWatchpointWidgetForm(address, byte_len, watchpoint_type, self).show() + TrackWatchpointWidgetForm(self, address, byte_len, watchpoint_type) def browse_region_for_selected_row(self): row = guiutils.get_current_item(self.treeWidget_AddressTable) @@ -895,7 +892,7 @@ def group_records(self): last_item.setExpanded(True) def create_group(self): - dialog = InputDialogForm(item_list=[(tr.ENTER_DESCRIPTION, tr.GROUP)]) + dialog = InputDialogForm(self, [(tr.ENTER_DESCRIPTION, tr.GROUP)]) if dialog.exec(): desc = dialog.get_values() self.add_entry_to_addresstable(desc, "0x0") @@ -1011,7 +1008,7 @@ def resize_address_table(self): # gets the information from the dialog then adds it to addresstable def pushButton_AddAddressManually_clicked(self): - manual_address_dialog = ManualAddressDialogForm() + manual_address_dialog = ManualAddressDialogForm(self) if manual_address_dialog.exec(): desc, address_expr, vt = manual_address_dialog.get_values() self.add_entry_to_addresstable(desc, address_expr, vt) @@ -1030,16 +1027,17 @@ def pushButton_Wiki_clicked(self): utils.execute_command_as_user('python3 -m webbrowser "https://github.com/korcankaraokcu/PINCE/wiki"') def pushButton_About_clicked(self): - self.about_widget.show() - self.about_widget.activateWindow() + about_widget = AboutWidgetForm(self) + about_widget.show() + about_widget.activateWindow() def pushButton_Settings_clicked(self): - settings_dialog = SettingsDialogForm(self.set_default_settings) + settings_dialog = SettingsDialogForm(self, self.set_default_settings) if settings_dialog.exec(): self.apply_settings() def pushButton_Console_clicked(self): - console_widget = ConsoleWidgetForm() + console_widget = ConsoleWidgetForm(self) console_widget.showMaximized() def checkBox_Hex_stateChanged(self, state): @@ -1374,7 +1372,7 @@ def on_new_process(self): def clear_address_table(self): if self.treeWidget_AddressTable.topLevelItemCount() == 0: return - confirm_dialog = InputDialogForm(item_list=[(tr.CLEAR_TABLE,)]) + confirm_dialog = InputDialogForm(self, [(tr.CLEAR_TABLE,)]) if confirm_dialog.exec(): self.treeWidget_AddressTable.clear() @@ -1579,7 +1577,7 @@ def treeWidget_AddressTable_edit_value(self): return value = row.text(VALUE_COL) value_index = row.data(TYPE_COL, Qt.ItemDataRole.UserRole).value_index - dialog = InputDialogForm(item_list=[(tr.ENTER_VALUE, value)], parsed_index=0, value_index=value_index) + dialog = InputDialogForm(self, [(tr.ENTER_VALUE, value)], 0, value_index) if dialog.exec(): new_value = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): @@ -1599,7 +1597,7 @@ def treeWidget_AddressTable_edit_desc(self): if not row: return description = row.text(DESC_COL) - dialog = InputDialogForm(item_list=[(tr.ENTER_DESCRIPTION, description)]) + dialog = InputDialogForm(self, [(tr.ENTER_DESCRIPTION, description)]) if dialog.exec(): description_text = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): @@ -1610,7 +1608,7 @@ def treeWidget_AddressTable_edit_address(self): if not row: return desc, address_expr, vt = self.read_address_table_entries(row) - manual_address_dialog = ManualAddressDialogForm(description=desc, address=address_expr, value_type=vt) + manual_address_dialog = ManualAddressDialogForm(self, desc, address_expr, vt) manual_address_dialog.setWindowTitle(tr.EDIT_ADDRESS) if manual_address_dialog.exec(): desc, address_expr, vt = manual_address_dialog.get_values() @@ -1622,7 +1620,7 @@ def treeWidget_AddressTable_edit_type(self): if not row: return vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - dialog = EditTypeDialogForm(value_type=vt) + dialog = EditTypeDialogForm(self, vt) if dialog.exec(): vt = dialog.get_values() for row in self.treeWidget_AddressTable.selectedItems(): @@ -1683,15 +1681,15 @@ def flash_attach_button(self): # process select window class ProcessForm(QMainWindow, ProcessWindow): def __init__(self, parent=None): - super().__init__(parent=parent) + super().__init__(parent) self.setupUi(self) - guiutils.center_to_parent(self) self.refresh_process_table(self.tableWidget_ProcessTable, utils.get_process_list()) self.pushButton_Close.clicked.connect(self.close) self.pushButton_Open.clicked.connect(self.pushButton_Open_clicked) self.pushButton_CreateProcess.clicked.connect(self.pushButton_CreateProcess_clicked) self.lineEdit_SearchProcess.textChanged.connect(self.generate_new_list) self.tableWidget_ProcessTable.itemDoubleClicked.connect(self.pushButton_Open_clicked) + guiutils.center_to_parent(self) # refreshes process list def generate_new_list(self): @@ -1741,7 +1739,7 @@ def pushButton_CreateProcess_clicked(self): file_path = QFileDialog.getOpenFileName(self, tr.SELECT_BINARY)[0] if file_path: items = [(tr.ENTER_OPTIONAL_ARGS, ""), (tr.LD_PRELOAD_OPTIONAL, "")] - arg_dialog = InputDialogForm(item_list=items) + arg_dialog = InputDialogForm(self, items) if arg_dialog.exec(): args, ld_preload_path = arg_dialog.get_values() else: @@ -1754,8 +1752,8 @@ def pushButton_CreateProcess_clicked(self): # Add Address Manually Dialog class ManualAddressDialogForm(QDialog, ManualAddressDialog): - def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", value_type=None): - super().__init__(parent=parent) + def __init__(self, parent, description=tr.NO_DESCRIPTION, address="0x", value_type=None): + super().__init__(parent) self.setupUi(self) vt = typedefs.ValueType() if not value_type else value_type self.lineEdit_Length.setValidator(QHexValidator(99, self)) @@ -1811,6 +1809,7 @@ def __init__(self, parent=None, description=tr.NO_DESCRIPTION, address="0x", val self.pushButton_RemoveOffset.clicked.connect(self.removeOffsetLayout) self.label_Value.contextMenuEvent = self.label_Value_context_menu_event self.update_value() + guiutils.center_to_parent(self) def label_Value_context_menu_event(self, event): menu = QMenu() @@ -1922,7 +1921,7 @@ def checkBox_IsPointer_state_changed(self): self.update_value() def reject(self): - super(ManualAddressDialogForm, self).reject() + super().reject() def accept(self): if self.label_Length.isVisible(): @@ -1935,7 +1934,7 @@ def accept(self): if not length > 0: QMessageBox.information(self, tr.ERROR, tr.LENGTH_GT) return - super(ManualAddressDialogForm, self).accept() + super().accept() def get_values(self): description = self.lineEdit_Description.text() @@ -1991,8 +1990,8 @@ def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): class EditTypeDialogForm(QDialog, EditTypeDialog): - def __init__(self, parent=None, value_type=None): - super().__init__(parent=parent) + def __init__(self, parent, value_type=None): + super().__init__(parent) self.setupUi(self) vt = typedefs.ValueType() if not value_type else value_type self.lineEdit_Length.setValidator(QHexValidator(99, self)) @@ -2029,6 +2028,7 @@ def __init__(self, parent=None, value_type=None): self.checkBox_Hex.stateChanged.connect(self.repr_changed) app.processEvents() self.adjustSize() + guiutils.center_to_parent(self) def comboBox_ValueType_current_index_changed(self): if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): @@ -2049,7 +2049,7 @@ def repr_changed(self): self.checkBox_Signed.setEnabled(True) def reject(self): - super(EditTypeDialogForm, self).reject() + super().reject() def accept(self): if self.label_Length.isVisible(): @@ -2062,7 +2062,7 @@ def accept(self): if not length > 0: QMessageBox.information(self, tr.ERROR, tr.LENGTH_GT) return - super(EditTypeDialogForm, self).accept() + super().accept() def get_values(self): value_index = self.comboBox_ValueType.currentIndex() @@ -2083,12 +2083,13 @@ def get_values(self): class TrackSelectorDialogForm(QDialog, TrackSelectorDialog): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) self.selection = None self.pushButton_Pointer.clicked.connect(lambda: self.change_selection("pointer")) self.pushButton_Pointed.clicked.connect(lambda: self.change_selection("pointed")) + guiutils.center_to_parent(self) def change_selection(self, selection): self.selection = selection @@ -2096,13 +2097,10 @@ def change_selection(self, selection): class LoadingDialogForm(QDialog, LoadingDialog): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.setWindowFlags(self.windowFlags() | Qt.WindowType.FramelessWindowHint) - self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) - if parent: - guiutils.center_to_parent(self) + self.setWindowFlags(self.windowFlags()) self.keyPressEvent = QEvent.ignore # Make use of this background_thread when you spawn a LoadingDialogForm @@ -2111,7 +2109,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) + self.pushButton_Cancel.clicked.connect(self.close) media_directory = utils.get_media_directory() self.movie = QMovie(media_directory + "/LoadingDialog/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) @@ -2119,15 +2117,20 @@ def __init__(self, parent=None): self.movie.setCacheMode(QMovie.CacheMode.CacheAll) self.movie.setSpeed(100) self.movie.start() + guiutils.center_to_parent(self) - # This function only cancels the last command sent - # Override this if you want to do dangerous stuff like, God forbid, background_thread.terminate() + # TODO: This function only cancels the last command sent, redesign this if it's needed to cancel non-gdb functions def cancel_thread(self): debugcore.cancel_last_command() + self.background_thread.wait() def exec(self): self.background_thread.start() - super(LoadingDialogForm, self).exec() + super().exec() + + def closeEvent(self, event: QCloseEvent): + self.cancel_thread() + super().closeEvent(event) class BackgroundThread(QThread): output_ready = pyqtSignal(object) @@ -2157,9 +2160,9 @@ class InputDialogForm(QDialog, InputDialog): # that points the current index of the QComboBox, for instance: ["0", "1", 1] will create a QCombobox with the items # "0" and "1" then will set current index to 1 (which is the item "1") # label_alignment is optional - def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typedefs.VALUE_INDEX.INT32, + def __init__(self, parent, item_list=None, parsed_index=-1, value_index=typedefs.VALUE_INDEX.INT32, buttons=(QDialogButtonBox.StandardButton.Ok, QDialogButtonBox.StandardButton.Cancel)): - super().__init__(parent=parent) + super().__init__(parent) self.setupUi(self) for button in buttons: self.buttonBox.addButton(button) @@ -2203,6 +2206,7 @@ def __init__(self, parent=None, item_list=None, parsed_index=-1, value_index=typ break self.parsed_index = parsed_index self.value_index = value_index + guiutils.center_to_parent(self) def get_text(self, item): try: @@ -2221,16 +2225,17 @@ def accept(self): if utils.parse_string(self.get_text(item), self.value_index) is None: QMessageBox.information(self, tr.ERROR, tr.PARSE_ERROR) return - super(InputDialogForm, self).accept() + super().accept() class TextEditDialogForm(QDialog, TextEditDialog): - def __init__(self, parent=None, text=""): - super().__init__(parent=parent) + def __init__(self, parent, text=""): + super().__init__(parent) self.setupUi(self) self.textEdit.setPlainText(str(text)) self.accept_shortcut = QShortcut(QKeySequence("Ctrl+Return"), self) self.accept_shortcut.activated.connect(self.accept) + guiutils.center_to_parent(self) def get_values(self): return self.textEdit.toPlainText() @@ -2239,12 +2244,12 @@ def keyPressEvent(self, QKeyEvent): if QKeyEvent.key() == Qt.Key.Key_Enter: pass else: - super(TextEditDialogForm, self).keyPressEvent(QKeyEvent) + super().keyPressEvent(QKeyEvent) class SettingsDialogForm(QDialog, SettingsDialog): - def __init__(self, set_default_settings_func, parent=None): - super().__init__(parent=parent) + def __init__(self, parent, set_default_settings_func): + super().__init__(parent) self.setupUi(self) self.settings = QSettings() self.set_default_settings = set_default_settings_func @@ -2282,6 +2287,7 @@ def __init__(self, set_default_settings_func, parent=None): self.comboBox_Logo.currentIndexChanged.connect(self.comboBox_Logo_current_index_changed) self.comboBox_Theme.currentIndexChanged.connect(self.comboBox_Theme_current_index_changed) self.pushButton_HandleSignals.clicked.connect(self.pushButton_HandleSignals_clicked) + guiutils.center_to_parent(self) def accept(self): try: @@ -2308,10 +2314,10 @@ def accept(self): QMessageBox.information(self, tr.ERROR, tr.INTERVAL_ASSERT_NEGATIVE) return elif current_table_update_interval == 0 or current_freeze_interval == 0: - if not InputDialogForm(item_list=[(tr.ASKING_FOR_TROUBLE,)]).exec(): # Easter egg + if not InputDialogForm(self, [(tr.ASKING_FOR_TROUBLE,)]).exec(): # Easter egg return elif current_table_update_interval < 100: - if not InputDialogForm(item_list=[(tr.UPDATE_ASSERT_GT.format(100),)]).exec(): + if not InputDialogForm(self, [(tr.UPDATE_ASSERT_GT.format(100),)]).exec(): return self.settings.setValue("General/auto_update_address_table", self.checkBox_AutoUpdateAddressTable.isChecked()) @@ -2348,7 +2354,7 @@ def accept(self): selected_gdb_path = self.lineEdit_GDBPath.text() current_gdb_path = self.settings.value("Debug/gdb_path", type=str) if selected_gdb_path != current_gdb_path: - if InputDialogForm(item_list=[(tr.GDB_RESET,)]).exec(): + if InputDialogForm(self, [(tr.GDB_RESET,)]).exec(): debugcore.init_gdb(selected_gdb_path) self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) @@ -2424,7 +2430,7 @@ def pushButton_ClearHotkey_clicked(self): self.keySequenceEdit_Hotkey.clear() def pushButton_ResetSettings_clicked(self): - confirm_dialog = InputDialogForm(item_list=[(tr.RESET_DEFAULT_SETTINGS,)]) + confirm_dialog = InputDialogForm(self, [(tr.RESET_DEFAULT_SETTINGS,)]) if confirm_dialog.exec(): self.set_default_settings() self.handle_signals_data = "" @@ -2460,14 +2466,14 @@ def pushButton_GDBPath_clicked(self): def pushButton_HandleSignals_clicked(self): if not self.handle_signals_data: self.handle_signals_data = self.settings.value("Debug/handle_signals", type=str) - signal_dialog = HandleSignalsDialogForm(self.handle_signals_data) + signal_dialog = HandleSignalsDialogForm(self, self.handle_signals_data) if signal_dialog.exec(): self.handle_signals_data = signal_dialog.get_values() class HandleSignalsDialogForm(QDialog, HandleSignalsDialog): - def __init__(self, signal_data, parent=None): - super().__init__(parent=parent) + def __init__(self, parent, signal_data): + super().__init__(parent) self.setupUi(self) self.signal_data = json.loads(signal_data) self.tableWidget_Signals.setRowCount(len(self.signal_data)) @@ -2486,6 +2492,7 @@ def __init__(self, signal_data, parent=None): else: checkbox.setCheckState(Qt.CheckState.Unchecked) self.tableWidget_Signals.resizeColumnsToContents() + guiutils.center_to_parent(self) def create_checkbox_widget(self): @@ -2513,12 +2520,10 @@ def get_values(self): class ConsoleWidgetForm(QWidget, ConsoleWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - global instances - instances.append(self) - guiutils.center(self) + self.setWindowFlags(Qt.WindowType.Window) self.completion_model = QStringListModel() self.completer = QCompleter() self.completer.setModel(self.completion_model) @@ -2545,6 +2550,7 @@ def __init__(self, parent=None): self.lineEdit.keyPressEvent_original = self.lineEdit.keyPressEvent self.lineEdit.keyPressEvent = self.lineEdit_key_press_event self.reset_console_text() + guiutils.center_to_parent(self) def communicate(self): self.current_history_index = -1 @@ -2584,7 +2590,7 @@ def scroll_to_bottom(self): self.textBrowser.ensureCursorVisible() def enter_multiline_mode(self): - multiline_dialog = TextEditDialogForm(text=self.lineEdit.text()) + multiline_dialog = TextEditDialogForm(self, self.lineEdit.text()) if multiline_dialog.exec(): self.lineEdit.setText(multiline_dialog.get_values()) self.communicate() @@ -2629,17 +2635,15 @@ def complete_command(self): else: self.finish_completion() - def closeEvent(self, QCloseEvent): + def closeEvent(self, event): self.await_async_output_thread.stop() - global instances - instances.remove(self) class AboutWidgetForm(QTabWidget, AboutWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - guiutils.center(self) + self.setWindowFlags(Qt.WindowType.Window) # This section has untranslated text since it's just a placeholder license_text = open("COPYING").read() @@ -2657,6 +2661,7 @@ def __init__(self, parent=None): self.textBrowser_Contributors.append("#THANKS#") self.textBrowser_Contributors.append("#######\n") self.textBrowser_Contributors.append(thanks_text) + guiutils.center_to_parent(self) class MemoryViewWindowForm(QMainWindow, MemoryViewWindow): @@ -2717,12 +2722,12 @@ def initialize_tools_context_menu(self): def initialize_help_context_menu(self): self.actionlibpince.triggered.connect(self.actionlibpince_triggered) - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - guiutils.center(self) self.updating_memoryview = False + self.stacktrace_info_widget = StackTraceInfoWidgetForm(self) + self.float_registers_widget = FloatRegisterWidgetForm(self) self.process_stopped.connect(self.on_process_stop) self.process_running.connect(self.on_process_running) self.set_debug_menu_shortcuts() @@ -2743,6 +2748,7 @@ def __init__(self, parent=None): self.splitter_MainMiddle.setStretchFactor(1, 1) self.widget_StackView.resize(660, self.widget_StackView.height()) self.widget_Registers.resize(330, self.widget_Registers.height()) + guiutils.center(self) def initialize_register_view(self): self.pushButton_ShowFloatRegisters.clicked.connect(self.pushButton_ShowFloatRegisters_clicked) @@ -2838,7 +2844,7 @@ def initialize_hex_view(self): self.hex_update_timer.start(200) def show_trace_window(self): - TraceInstructionsWindowForm(prompt_dialog=False) + TraceInstructionsWindowForm(self, prompt_dialog=False) def step_instruction(self): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or \ @@ -2872,7 +2878,7 @@ def edit_instruction(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = utils.extract_address(current_address_text) bytes_aob = self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() - EditInstructionDialogForm(current_address, bytes_aob, self).exec() + EditInstructionDialogForm(self, current_address, bytes_aob).exec() def nop_instruction(self): if debugcore.currentpid == -1: @@ -2981,13 +2987,13 @@ def widget_HexView_context_menu_event(self, event): def exec_hex_view_edit_dialog(self): if debugcore.currentpid == -1: return - HexEditDialogForm(self.hex_selection_address_begin, self.get_hex_selection_length()).exec() + HexEditDialogForm(self, self.hex_selection_address_begin, self.get_hex_selection_length()).exec() self.refresh_hex_view() def exec_hex_view_go_to_dialog(self): if debugcore.currentpid == -1: return - go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, hex(self.hex_selection_address_begin))]) + go_to_dialog = InputDialogForm(self, [(tr.ENTER_EXPRESSION, hex(self.hex_selection_address_begin))]) if go_to_dialog.exec(): expression = go_to_dialog.get_values() dest_address = debugcore.examine_expression(expression).address @@ -3000,9 +3006,9 @@ def exec_hex_view_add_address_dialog(self): if debugcore.currentpid == -1: return vt = typedefs.ValueType(typedefs.VALUE_INDEX.AOB, self.get_hex_selection_length()) - manual_address_dialog = ManualAddressDialogForm(address=hex(self.hex_selection_address_begin), value_type=vt) - if manual_address_dialog.exec(): - desc, address, vt = manual_address_dialog.get_values() + address_dialog = ManualAddressDialogForm(self, address=hex(self.hex_selection_address_begin), value_type=vt) + if address_dialog.exec(): + desc, address, vt = address_dialog.get_values() self.parent().add_entry_to_addresstable(desc, address, vt) self.parent().update_address_table() @@ -3410,16 +3416,10 @@ def on_process_stop(self): if self.bring_disassemble_to_front: self.showMaximized() self.activateWindow() - try: - if self.stacktrace_info_widget.isVisible(): - self.stacktrace_info_widget.update_stacktrace() - except AttributeError: - pass - try: - if self.float_registers_widget.isVisible(): - self.float_registers_widget.update_registers() - except AttributeError: - pass + if self.stacktrace_info_widget.isVisible(): + self.stacktrace_info_widget.update_stacktrace() + if self.float_registers_widget.isVisible(): + self.float_registers_widget.update_registers() app.processEvents() time1 = time() print("UPDATED MEMORYVIEW IN:" + str(time1 - time0)) @@ -3436,8 +3436,8 @@ def add_breakpoint_condition(self, int_address, length=1): condition_line_edit_text = breakpoints[0].condition else: condition_line_edit_text = "" - condition_dialog = InputDialogForm( - item_list=[(tr.ENTER_BP_CONDITION, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)]) + items = [(tr.ENTER_BP_CONDITION, condition_line_edit_text, Qt.AlignmentFlag.AlignLeft)] + condition_dialog = InputDialogForm(self, items) if condition_dialog.exec(): condition = condition_dialog.get_values() for bp in breakpoints: @@ -3917,7 +3917,7 @@ def dissect_current_region(self): selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = utils.extract_address(current_address_text) - dissect_code_dialog = DissectCodeDialogForm(int_address=int(current_address, 16)) + dissect_code_dialog = DissectCodeDialogForm(self, int(current_address, 16)) dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec() self.refresh_disassemble_view() @@ -3929,7 +3929,7 @@ def exec_examine_referrers_widget(self, current_address_text): return current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) - examine_referrers_widget = ExamineReferrersWidgetForm(current_address_int, self) + examine_referrers_widget = ExamineReferrersWidgetForm(self, current_address_int) examine_referrers_widget.show() def exec_trace_instructions_dialog(self): @@ -3940,7 +3940,7 @@ def exec_trace_instructions_dialog(self): selected_row = 0 current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = utils.extract_address(current_address_text) - TraceInstructionsWindowForm(current_address, parent=self) + TraceInstructionsWindowForm(self, current_address) def exec_track_breakpoint_dialog(self): if debugcore.currentpid == -1: @@ -3949,11 +3949,10 @@ def exec_track_breakpoint_dialog(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = utils.extract_address(current_address_text) current_instruction = self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() - register_expression_dialog = InputDialogForm(item_list=[(tr.ENTER_TRACK_BP_EXPRESSION, "")]) + register_expression_dialog = InputDialogForm(self, [(tr.ENTER_TRACK_BP_EXPRESSION, "")]) if register_expression_dialog.exec(): exp = register_expression_dialog.get_values() - track_breakpoint_widget = TrackBreakpointWidgetForm(current_address, current_instruction, exp, self) - track_breakpoint_widget.show() + TrackBreakpointWidgetForm(self, current_address, current_instruction, exp) def exec_disassemble_go_to_dialog(self): if debugcore.currentpid == -1: @@ -3964,7 +3963,7 @@ def exec_disassemble_go_to_dialog(self): current_address_text = self.tableWidget_Disassemble.item(selected_row, DISAS_ADDR_COL).text() current_address = utils.extract_address(current_address_text) - go_to_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, current_address)]) + go_to_dialog = InputDialogForm(self, [(tr.ENTER_EXPRESSION, current_address)]) if go_to_dialog.exec(): traveled_exp = go_to_dialog.get_values() self.disassemble_expression(traveled_exp, append_to_travel_history=True) @@ -3975,7 +3974,7 @@ def bookmark_address(self, int_address): if int_address in self.tableWidget_Disassemble.bookmarks: QMessageBox.information(app.focusWidget(), tr.ERROR, tr.ALREADY_BOOKMARKED) return - comment_dialog = InputDialogForm(item_list=[(tr.ENTER_BOOKMARK_COMMENT, "")]) + comment_dialog = InputDialogForm(self, [(tr.ENTER_BOOKMARK_COMMENT, "")]) if comment_dialog.exec(): comment = comment_dialog.get_values() else: @@ -3987,7 +3986,7 @@ def change_bookmark_comment(self, int_address): if debugcore.currentpid == -1: return current_comment = self.tableWidget_Disassemble.bookmarks[int_address] - comment_dialog = InputDialogForm(item_list=[(tr.ENTER_BOOKMARK_COMMENT, current_comment)]) + comment_dialog = InputDialogForm(self, [(tr.ENTER_BOOKMARK_COMMENT, current_comment)]) if comment_dialog.exec(): new_comment = comment_dialog.get_values() else: @@ -4010,8 +4009,10 @@ def actionBookmarks_triggered(self): def actionStackTrace_Info_triggered(self): if debugcore.currentpid == -1: return - self.stacktrace_info_widget = StackTraceInfoWidgetForm() + self.stacktrace_info_widget.update_stacktrace() + guiutils.center_to_parent(self.stacktrace_info_widget) self.stacktrace_info_widget.show() + self.stacktrace_info_widget.activateWindow() def actionBreakpoints_triggered(self): if debugcore.currentpid == -1: @@ -4027,7 +4028,7 @@ def actionFunctions_triggered(self): functions_info_widget.show() def actionGDB_Log_File_triggered(self): - log_file_widget = LogFileWidgetForm() + log_file_widget = LogFileWidgetForm(self) log_file_widget.showMaximized() def actionMemory_Regions_triggered(self): @@ -4041,6 +4042,7 @@ def actionRestore_Instructions_triggered(self): return restore_instructions_widget = RestoreInstructionsWidgetForm(self) restore_instructions_widget.show() + restore_instructions_widget.activateWindow() def actionReferenced_Strings_triggered(self): if debugcore.currentpid == -1: @@ -4067,7 +4069,7 @@ def actionInject_so_file_triggered(self): def actionCall_Function_triggered(self): if debugcore.currentpid == -1: return - call_dialog = InputDialogForm(item_list=[(tr.ENTER_CALL_EXPRESSION, "")]) + call_dialog = InputDialogForm(self, [(tr.ENTER_CALL_EXPRESSION, "")]) if call_dialog.exec(): result = debugcore.call_function_from_inferior(call_dialog.get_values()) if result[0]: @@ -4080,36 +4082,33 @@ def actionSearch_Opcode_triggered(self): return start_address = int(self.disassemble_currently_displayed_address, 16) end_address = start_address + 0x30000 - search_opcode_widget = SearchOpcodeWidgetForm(hex(start_address), hex(end_address), self) + search_opcode_widget = SearchOpcodeWidgetForm(self, hex(start_address), hex(end_address)) search_opcode_widget.show() def actionDissect_Code_triggered(self): if debugcore.currentpid == -1: return - self.dissect_code_dialog = DissectCodeDialogForm() - self.dissect_code_dialog.exec() + dissect_code_dialog = DissectCodeDialogForm(self) + dissect_code_dialog.exec() self.refresh_disassemble_view() def actionlibpince_triggered(self): - libpince_widget = LibpinceReferenceWidgetForm(is_window=True) + libpince_widget = LibpinceReferenceWidgetForm(self) libpince_widget.showMaximized() def pushButton_ShowFloatRegisters_clicked(self): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return - self.float_registers_widget = FloatRegisterWidgetForm() + self.float_registers_widget.update_registers() + guiutils.center_to_parent(self.float_registers_widget) self.float_registers_widget.show() - guiutils.center_to_window(self.float_registers_widget, self.widget_Registers) + self.float_registers_widget.activateWindow() class BookmarkWidgetForm(QWidget, BookmarkWidget): - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.listWidget.contextMenuEvent = self.listWidget_context_menu_event self.listWidget.currentRowChanged.connect(self.change_display) @@ -4119,6 +4118,7 @@ def __init__(self, parent=None): self.shortcut_refresh = QShortcut(QKeySequence("R"), self) self.shortcut_refresh.activated.connect(self.refresh_table) self.refresh_table() + guiutils.center_to_parent(self) def refresh_table(self): self.listWidget.clear() @@ -4140,7 +4140,7 @@ def listWidget_item_double_clicked(self, item): self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) def exec_add_entry_dialog(self): - entry_dialog = InputDialogForm(item_list=[(tr.ENTER_EXPRESSION, "")]) + entry_dialog = InputDialogForm(self, [(tr.ENTER_EXPRESSION, "")]) if entry_dialog.exec(): text = entry_dialog.get_values() address = debugcore.examine_expression(text).address @@ -4194,17 +4194,12 @@ def delete_record(self): self.parent().delete_bookmark(current_address) self.refresh_table() - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class FloatRegisterWidgetForm(QTabWidget, FloatRegisterWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) self.setWindowFlags(Qt.WindowType.Window) - self.update_registers() self.tableWidget_FPU.itemDoubleClicked.connect(self.set_register) self.tableWidget_XMM.itemDoubleClicked.connect(self.set_register) @@ -4233,7 +4228,7 @@ def set_register(self, index): current_register = current_table_widget.item(current_row, FLOAT_REGISTERS_NAME_COL).text() current_value = current_table_widget.item(current_row, FLOAT_REGISTERS_VALUE_COL).text() label_text = tr.ENTER_REGISTER_VALUE.format(current_register.upper()) - register_dialog = InputDialogForm(item_list=[(label_text, current_value)]) + register_dialog = InputDialogForm(self, [(label_text, current_value)]) if register_dialog.exec(): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return @@ -4244,13 +4239,11 @@ def set_register(self, index): class StackTraceInfoWidgetForm(QWidget, StackTraceInfoWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.listWidget_ReturnAddresses.currentRowChanged.connect(self.update_frame_info) - self.update_stacktrace() def update_stacktrace(self): self.listWidget_ReturnAddresses.clear() @@ -4268,13 +4261,9 @@ def update_frame_info(self, index): class RestoreInstructionsWidgetForm(QWidget, RestoreInstructionsWidget): - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) # Saving the original function because super() doesn't work when we override functions like this @@ -4283,6 +4272,7 @@ def __init__(self, parent=None): self.tableWidget_Instructions.contextMenuEvent = self.tableWidget_Instructions_context_menu_event self.tableWidget_Instructions.itemDoubleClicked.connect(self.tableWidget_Instructions_double_clicked) self.refresh() + guiutils.center_to_parent(self) def tableWidget_Instructions_context_menu_event(self, event): selected_row = guiutils.get_current_row(self.tableWidget_Instructions) @@ -4345,19 +4335,11 @@ def tableWidget_Instructions_double_clicked(self, index): current_address = utils.extract_address(current_address_text) self.parent().disassemble_expression(current_address, append_to_travel_history=True) - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class BreakpointInfoWidgetForm(QTabWidget, BreakpointInfoWidget): - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_BreakpointInfo.contextMenuEvent = self.tableWidget_BreakpointInfo_context_menu_event @@ -4366,6 +4348,7 @@ def __init__(self, parent=None): self.tableWidget_BreakpointInfo.keyPressEvent = self.tableWidget_BreakpointInfo_key_press_event self.tableWidget_BreakpointInfo.itemDoubleClicked.connect(self.tableWidget_BreakpointInfo_double_clicked) self.refresh() + guiutils.center_to_parent(self) def refresh(self): break_info = debugcore.get_breakpoint_info() @@ -4410,7 +4393,7 @@ def tableWidget_BreakpointInfo_key_press_event(self, event): self.tableWidget_BreakpointInfo.keyPressEvent_original(event) def exec_enable_count_dialog(self, current_address): - hit_count_dialog = InputDialogForm(item_list=[(tr.ENTER_HIT_COUNT.format(1), "")]) + hit_count_dialog = InputDialogForm(self, [(tr.ENTER_HIT_COUNT.format(1), "")]) if hit_count_dialog.exec(): count = hit_count_dialog.get_values() try: @@ -4490,19 +4473,11 @@ def tableWidget_BreakpointInfo_double_clicked(self, index): else: self.parent().hex_dump_address(current_address_int) - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class TrackWatchpointWidgetForm(QWidget, TrackWatchpointWidget): - def __init__(self, address, length, watchpoint_type, parent=None): - super().__init__() + def __init__(self, parent, address, length, watchpoint_type): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.update_timer = QTimer(timeout=self.update_list) self.stopped = False @@ -4528,6 +4503,8 @@ def __init__(self, address, length, watchpoint_type, parent=None): self.tableWidget_Opcodes.itemDoubleClicked.connect(self.tableWidget_Opcodes_item_double_clicked) self.tableWidget_Opcodes.selectionModel().currentChanged.connect(self.tableWidget_Opcodes_current_changed) self.update_timer.start(100) + guiutils.center_to_parent(self) + self.show() def update_list(self): info = debugcore.get_track_watchpoint_info(self.breakpoints) @@ -4576,25 +4553,21 @@ def pushButton_Stop_clicked(self): self.stopped = True self.pushButton_Stop.setText(tr.CLOSE) - def closeEvent(self, QCloseEvent): - global instances + def closeEvent(self, event: QCloseEvent): self.update_timer.stop() - if not self.stopped: - debugcore.delete_breakpoint(self.address) - watchpoint_file = utils.get_track_watchpoint_file(debugcore.currentpid, self.breakpoints) - if os.path.exists(watchpoint_file): - os.remove(watchpoint_file) - self.deleteLater() - instances.remove(self) + if self.breakpoints: + if not self.stopped: + debugcore.delete_breakpoint(self.address) + watchpoint_file = utils.get_track_watchpoint_file(debugcore.currentpid, self.breakpoints) + if os.path.exists(watchpoint_file): + os.remove(watchpoint_file) + super().closeEvent(event) class TrackBreakpointWidgetForm(QWidget, TrackBreakpointWidget): - def __init__(self, address, instruction, register_expressions, parent=None): - super().__init__() + def __init__(self, parent, address, instruction, register_expressions): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) self.update_list_timer = QTimer(timeout=self.update_list) self.update_values_timer = QTimer(timeout=self.update_values) self.stopped = False @@ -4602,7 +4575,6 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.info = {} self.last_selected_row = 0 self.setWindowFlags(Qt.WindowType.Window) - guiutils.center_to_parent(self) self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) self.breakpoint = debugcore.track_breakpoint(address, register_expressions) if not self.breakpoint: @@ -4617,6 +4589,8 @@ def __init__(self, address, instruction, register_expressions, parent=None): self.update_list_timer.start(100) self.update_values_timer.start(500) self.parent().refresh_disassemble_view() + guiutils.center_to_parent(self) + self.show() def update_list(self): info = debugcore.get_track_breakpoint_info(self.breakpoint) @@ -4669,24 +4643,24 @@ def pushButton_Stop_clicked(self): self.pushButton_Stop.setText(tr.CLOSE) self.parent().refresh_disassemble_view() - def closeEvent(self, QCloseEvent): - global instances + def closeEvent(self, event: QCloseEvent): self.update_list_timer.stop() self.update_values_timer.stop() - if not self.stopped: - debugcore.delete_breakpoint(self.address) - breakpoint_file = utils.get_track_breakpoint_file(debugcore.currentpid, self.breakpoint) - if os.path.exists(breakpoint_file): - os.remove(breakpoint_file) + if self.breakpoint: + if not self.stopped: + debugcore.delete_breakpoint(self.address) + breakpoint_file = utils.get_track_breakpoint_file(debugcore.currentpid, self.breakpoint) + if os.path.exists(breakpoint_file): + os.remove(breakpoint_file) self.parent().refresh_disassemble_view() - self.deleteLater() - instances.remove(self) + super().closeEvent(event) class TraceInstructionsPromptDialogForm(QDialog, TraceInstructionsPromptDialog): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) + guiutils.center_to_parent(self) def get_values(self): max_trace_count = int(self.lineEdit_MaxTraceCount.text()) @@ -4706,7 +4680,7 @@ def get_values(self): def accept(self): if int(self.lineEdit_MaxTraceCount.text()) >= 1: - super(TraceInstructionsPromptDialogForm, self).accept() + super().accept() else: QMessageBox.information(self, tr.ERROR, tr.MAX_TRACE_COUNT_ASSERT_GT.format(1)) @@ -4714,8 +4688,8 @@ def accept(self): class TraceInstructionsWaitWidgetForm(QWidget, TraceInstructionsWaitWidget): widget_closed = pyqtSignal() - def __init__(self, address, breakpoint, parent=None): - super().__init__(parent=parent) + def __init__(self, parent, address, breakpoint): + super().__init__(parent) self.setupUi(self) self.status_to_text = { typedefs.TRACE_STATUS.IDLE: tr.WAITING_FOR_BREAKPOINT, @@ -4724,7 +4698,6 @@ def __init__(self, address, breakpoint, parent=None): typedefs.TRACE_STATUS.FINISHED: tr.TRACING_COMPLETED } self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) - guiutils.center(self) self.address = address self.breakpoint = breakpoint media_directory = utils.get_media_directory() @@ -4740,6 +4713,7 @@ def __init__(self, address, breakpoint, parent=None): self.status_timer.setInterval(30) self.status_timer.timeout.connect(self.change_status) self.status_timer.start() + guiutils.center_to_parent(self) def change_status(self): status_info = debugcore.get_trace_instructions_status(self.breakpoint) @@ -4752,7 +4726,7 @@ def change_status(self): self.label_StatusText.setText(self.status_to_text[status_info[0]]) app.processEvents() - def closeEvent(self, QCloseEvent): + def closeEvent(self, event: QCloseEvent): self.status_timer.stop() self.label_StatusText.setText(tr.PROCESSING_DATA) self.pushButton_Cancel.setVisible(False) @@ -4766,16 +4740,13 @@ def closeEvent(self, QCloseEvent): app.processEvents() debugcore.delete_breakpoint(self.address) self.widget_closed.emit() + super().closeEvent(event) class TraceInstructionsWindowForm(QMainWindow, TraceInstructionsWindow): - def __init__(self, address="", prompt_dialog=True, parent=None): - super().__init__() + def __init__(self, parent, address="", prompt_dialog=True): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.address = address self.trace_data = None self.treeWidget_InstructionInfo.currentItemChanged.connect(self.display_collected_data) @@ -4784,10 +4755,11 @@ def __init__(self, address="", prompt_dialog=True, parent=None): self.actionOpen.triggered.connect(self.load_file) self.actionSave.triggered.connect(self.save_file) self.splitter.setStretchFactor(0, 1) + guiutils.center_to_parent(self) if not prompt_dialog: self.showMaximized() return - prompt_dialog = TraceInstructionsPromptDialogForm() + prompt_dialog = TraceInstructionsPromptDialogForm(self) if prompt_dialog.exec(): params = (address,) + prompt_dialog.get_values() breakpoint = debugcore.trace_instructions(*params) @@ -4797,7 +4769,7 @@ def __init__(self, address="", prompt_dialog=True, parent=None): return self.showMaximized() self.breakpoint = breakpoint - self.wait_dialog = TraceInstructionsWaitWidgetForm(address, breakpoint, self) + self.wait_dialog = TraceInstructionsWaitWidgetForm(self, address, breakpoint) self.wait_dialog.widget_closed.connect(self.show_trace_info) self.wait_dialog.show() else: @@ -4885,19 +4857,11 @@ def treeWidget_InstructionInfo_item_double_clicked(self, index): if address: self.parent().disassemble_expression(address, append_to_travel_history=True) - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class FunctionsInfoWidgetForm(QWidget, FunctionsInfoWidget): - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.textBrowser_AddressInfo.setFixedHeight(100) self.pushButton_Search.clicked.connect(self.refresh_table) @@ -4909,6 +4873,7 @@ def __init__(self, parent=None): icons_directory = guiutils.get_icons_directory() self.pushButton_Help.setIcon(QIcon(QPixmap(icons_directory + "/help.png"))) self.pushButton_Help.clicked.connect(self.pushButton_Help_clicked) + guiutils.center_to_parent(self) def refresh_table(self): input_text = self.lineEdit_SearchInput.text() @@ -4984,17 +4949,13 @@ def tableWidget_SymbolInfo_item_double_clicked(self, index): self.parent().disassemble_expression(address, append_to_travel_history=True) def pushButton_Help_clicked(self): - InputDialogForm(item_list=[(tr.FUNCTIONS_INFO_HELPER, None, Qt.AlignmentFlag.AlignLeft)], + InputDialogForm(self, [(tr.FUNCTIONS_INFO_HELPER, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class EditInstructionDialogForm(QDialog, EditInstructionDialog): - def __init__(self, address, bytes_aob, parent=None): - super().__init__(parent=parent) + def __init__(self, parent, address, bytes_aob): + super().__init__(parent) self.setupUi(self) self.orig_bytes = bytes_aob self.lineEdit_Address.setText(address) @@ -5002,6 +4963,7 @@ def __init__(self, address, bytes_aob, parent=None): self.lineEdit_Bytes_text_edited() self.lineEdit_Bytes.textEdited.connect(self.lineEdit_Bytes_text_edited) self.lineEdit_Instruction.textEdited.connect(self.lineEdit_Instruction_text_edited) + guiutils.center_to_parent(self) def set_valid(self, valid): if valid: @@ -5049,23 +5011,24 @@ def accept(self): if new_length < old_length: bytes_aob += " 90"*(old_length-new_length) # Append NOPs if we are short on bytes elif new_length > old_length: - if not InputDialogForm(item_list=[(tr.NEW_OPCODE.format(new_length, old_length),)]).exec(): + if not InputDialogForm(self, [(tr.NEW_OPCODE.format(new_length, old_length),)]).exec(): return debugcore.modify_instruction(address, bytes_aob) self.parent().refresh_hex_view() self.parent().refresh_disassemble_view() - super(EditInstructionDialogForm, self).accept() + super().accept() class HexEditDialogForm(QDialog, HexEditDialog): - def __init__(self, address, length=20, parent=None): - super().__init__(parent=parent) + def __init__(self, parent, address, length=20): + super().__init__(parent) self.setupUi(self) self.lineEdit_Length.setValidator(QHexValidator(999, self)) self.lineEdit_Address.setText(hex(address)) self.lineEdit_Length.setText(str(length)) self.refresh_view() self.lineEdit_AsciiView.selectionChanged.connect(self.lineEdit_AsciiView_selection_changed) + guiutils.center_to_parent(self) # TODO: Implement this # self.lineEdit_HexView.selectionChanged.connect(self.lineEdit_HexView_selection_changed) @@ -5134,7 +5097,7 @@ def accept(self): return value = self.lineEdit_HexView.text() debugcore.write_memory(address, typedefs.VALUE_INDEX.AOB, value) - super(HexEditDialogForm, self).accept() + super().accept() # This widget will be replaced with auto-generated documentation in the future, no need to translate @@ -5142,16 +5105,12 @@ class LibpinceReferenceWidgetForm(QWidget, LibpinceReferenceWidget): def convert_to_modules(self, module_strings): return [eval(item) for item in module_strings] - def __init__(self, is_window=False, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) self.found_count = 0 self.current_found = 0 - global instances - instances.append(self) - if is_window: - guiutils.center(self) - self.setWindowFlags(Qt.WindowType.Window) + self.setWindowFlags(Qt.WindowType.Window) self.show_typedefs() self.splitter.setStretchFactor(0, 1) self.widget_Resources.resize(700, self.widget_Resources.height()) @@ -5176,6 +5135,7 @@ def __init__(self, is_window=False, parent=None): self.treeWidget_ResourceTree.contextMenuEvent = self.treeWidget_ResourceTree_context_menu_event self.treeWidget_ResourceTree.expanded.connect(self.resize_resource_tree) self.treeWidget_ResourceTree.collapsed.connect(self.resize_resource_tree) + guiutils.center_to_parent(self) def tableWidget_ResourceTable_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -5383,18 +5343,11 @@ def show_typedefs(self): self.widget_TypeDefs.show() self.pushButton_ShowTypeDefs.setText("Hide typedefs") - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class LogFileWidgetForm(QWidget, LogFileWidget): - def __init__(self, parent=None): - super().__init__(parent=parent) + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - guiutils.center(self) - global instances - instances.append(self) self.setWindowFlags(Qt.WindowType.Window) self.contents = "" self.refresh_contents() @@ -5402,6 +5355,7 @@ def __init__(self, parent=None): self.refresh_timer.setInterval(500) self.refresh_timer.timeout.connect(self.refresh_contents) self.refresh_timer.start() + guiutils.center_to_parent(self) def refresh_contents(self): log_path = utils.get_logging_file(debugcore.currentpid) @@ -5437,20 +5391,15 @@ def refresh_contents(self): self.textBrowser_LogContent.ensureCursorVisible() log_file.close() - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) + def closeEvent(self, event: QCloseEvent): self.refresh_timer.stop() + super().closeEvent(event) class SearchOpcodeWidgetForm(QWidget, SearchOpcodeWidget): - def __init__(self, start="", end="", parent=None): - super().__init__() + def __init__(self, parent, start="", end=""): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.lineEdit_Start.setText(start) self.lineEdit_End.setText(end) @@ -5463,6 +5412,7 @@ def __init__(self, start="", end="", parent=None): self.shortcut_search.activated.connect(self.refresh_table) self.tableWidget_Opcodes.itemDoubleClicked.connect(self.tableWidget_Opcodes_item_double_clicked) self.tableWidget_Opcodes.contextMenuEvent = self.tableWidget_Opcodes_context_menu_event + guiutils.center_to_parent(self) def refresh_table(self): start_address = self.lineEdit_Start.text() @@ -5493,7 +5443,7 @@ def apply_data(self, disas_data): self.tableWidget_Opcodes.setSortingEnabled(True) def pushButton_Help_clicked(self): - InputDialogForm(item_list=[(tr.SEARCH_OPCODE_HELPER, None, Qt.AlignmentFlag.AlignLeft)], + InputDialogForm(self, [(tr.SEARCH_OPCODE_HELPER, None, Qt.AlignmentFlag.AlignLeft)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() def tableWidget_Opcodes_item_double_clicked(self, index): @@ -5524,25 +5474,18 @@ def copy_to_clipboard(row, column): except KeyError: pass - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class MemoryRegionsWidgetForm(QWidget, MemoryRegionsWidget): - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center(self) self.setWindowFlags(Qt.WindowType.Window) self.refresh_table() self.tableWidget_MemoryRegions.contextMenuEvent = self.tableWidget_MemoryRegions_context_menu_event self.tableWidget_MemoryRegions.itemDoubleClicked.connect(self.tableWidget_MemoryRegions_item_double_clicked) self.shortcut_refresh = QShortcut(QKeySequence("R"), self) self.shortcut_refresh.activated.connect(self.refresh_table) + guiutils.center_to_parent(self) def refresh_table(self): memory_regions = utils.get_regions(debugcore.currentpid) @@ -5590,16 +5533,12 @@ def tableWidget_MemoryRegions_item_double_clicked(self, index): address_int = int(address.split("-")[0], 16) self.parent().hex_dump_address(address_int) - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class DissectCodeDialogForm(QDialog, DissectCodeDialog): scan_finished_signal = pyqtSignal() - def __init__(self, parent=None, int_address=-1): - super().__init__(parent=parent) + def __init__(self, parent, int_address=-1): + super().__init__(parent) self.setupUi(self) self.init_pre_scan_gui() self.update_dissect_results() @@ -5623,6 +5562,7 @@ def __init__(self, parent=None, int_address=-1): else: if self.tableWidget_ExecutableMemoryRegions.rowCount() > 0: self.tableWidget_ExecutableMemoryRegions.selectRow(0) + guiutils.center_to_parent(self) class BackgroundThread(QThread): output_ready = pyqtSignal() @@ -5713,25 +5653,23 @@ def pushButton_StartCancel_clicked(self): self.refresh_timer.start() self.background_thread.start() - def closeEvent(self, QCloseEvent): + def closeEvent(self, event: QCloseEvent): debugcore.cancel_dissect_code() self.refresh_timer.stop() + super().closeEvent(event) class ReferencedStringsWidgetForm(QWidget, ReferencedStringsWidget): - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) guiutils.fill_value_combobox(self.comboBox_ValueType, typedefs.VALUE_INDEX.STRING_UTF8) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center_to_parent(self) self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_References.setColumnWidth(REF_STR_ADDR_COL, 150) self.tableWidget_References.setColumnWidth(REF_STR_COUNT_COL, 80) self.splitter.setStretchFactor(0, 1) self.listWidget_Referrers.resize(400, self.listWidget_Referrers.height()) + guiutils.center_to_parent(self) self.hex_len = 16 if debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64 else 8 str_dict, jmp_dict, call_dict = debugcore.get_dissect_code_data() str_dict_len, jmp_dict_len, call_dict_len = len(str_dict), len(jmp_dict), len(call_dict) @@ -5739,9 +5677,9 @@ def __init__(self, parent=None): jmp_dict.close() call_dict.close() if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: - confirm_dialog = InputDialogForm(item_list=[(tr.DISSECT_CODE,)]) + confirm_dialog = InputDialogForm(self, [(tr.DISSECT_CODE,)]) if confirm_dialog.exec(): - dissect_code_dialog = DissectCodeDialogForm() + dissect_code_dialog = DissectCodeDialogForm(self) dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec() self.refresh_table() @@ -5849,23 +5787,16 @@ def copy_to_clipboard(row): except KeyError: pass - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class ReferencedCallsWidgetForm(QWidget, ReferencedCallsWidget): - def __init__(self, parent=None): - super().__init__() + def __init__(self, parent): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center_to_parent(self) self.setWindowFlags(Qt.WindowType.Window) self.tableWidget_References.setColumnWidth(REF_CALL_ADDR_COL, 480) self.splitter.setStretchFactor(0, 1) self.listWidget_Referrers.resize(400, self.listWidget_Referrers.height()) + guiutils.center_to_parent(self) self.hex_len = 16 if debugcore.inferior_arch == typedefs.INFERIOR_ARCH.ARCH_64 else 8 str_dict, jmp_dict, call_dict = debugcore.get_dissect_code_data() str_dict_len, jmp_dict_len, call_dict_len = len(str_dict), len(jmp_dict), len(call_dict) @@ -5873,9 +5804,9 @@ def __init__(self, parent=None): jmp_dict.close() call_dict.close() if str_dict_len == 0 and jmp_dict_len == 0 and call_dict_len == 0: - confirm_dialog = InputDialogForm(item_list=[(tr.DISSECT_CODE,)]) + confirm_dialog = InputDialogForm(self, [(tr.DISSECT_CODE,)]) if confirm_dialog.exec(): - dissect_code_dialog = DissectCodeDialogForm() + dissect_code_dialog = DissectCodeDialogForm(self) dissect_code_dialog.scan_finished_signal.connect(dissect_code_dialog.accept) dissect_code_dialog.exec() self.refresh_table() @@ -5976,19 +5907,11 @@ def copy_to_clipboard(row): except KeyError: pass - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - class ExamineReferrersWidgetForm(QWidget, ExamineReferrersWidget): - def __init__(self, int_address, parent=None): - super().__init__() + def __init__(self, parent, int_address): + super().__init__(parent) self.setupUi(self) - self.parent = lambda: parent - global instances - instances.append(self) - guiutils.center_to_parent(self) self.setWindowFlags(Qt.WindowType.Window) self.splitter.setStretchFactor(0, 1) self.textBrowser_DisasInfo.resize(600, self.textBrowser_DisasInfo.height()) @@ -6003,6 +5926,7 @@ def __init__(self, int_address, parent=None): self.pushButton_Search.clicked.connect(self.refresh_table) self.shortcut_search = QShortcut(QKeySequence("Return"), self) self.shortcut_search.activated.connect(self.refresh_table) + guiutils.center_to_parent(self) def pad_hex(self, hex_str): index = hex_str.find(" ") @@ -6099,10 +6023,6 @@ def copy_to_clipboard(row): except KeyError: pass - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) - def handle_exit(): global exiting From 944c29dacadacc206a6cf2fd2a04924cd8e55b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 15 Feb 2024 22:17:03 +0300 Subject: [PATCH 363/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f4beaaec..563904c0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,31 +106,7 @@ A full PR will look like this: Here are some notes that explains some of the caveats and hacks, they also include a timestamp. As we upgrade the libraries and the methods we are working with, some of these notes might become obsolete. You are free to test and provide solutions to these tricks -- 27/3/2017 - All GUI classes that will be instanced multiple times must contain these code blocks to prevent getting removed by garbage collector: -```python - global instances - instances.append(self) - - def closeEvent(self, QCloseEvent): - global instances - instances.remove(self) -``` -If you need to only create one instance of a GUI class, use this instead to create the instance: -```python - try: - self.window.show() - except AttributeError: - self.window = WindowForm(self) # self parameter is optional - self.window.show() - self.window.activateWindow() -``` -If you need to pass self as a parameter, please don't use `super().__init__(parent=parent)` in the child class, it makes Qt hide the child window. Use this in the child instead: -```python - super().__init__() - self.parent = lambda: parent # A quick hack to make other functions see the correct parent(). But Qt won't see it, so there'll be no bugs -``` - -- 28/8/2018 - All QMessageBoxes that's called from outside of their classes(via parent() etc.) must use 'QApplication.focusWidget()' instead of 'self' in their first parameter. +- 28/08/2018 - All QMessageBoxes that's called from outside of their classes(via parent() etc.) must use 'QApplication.focusWidget()' instead of 'self' in their first parameter. Refer to issue #57 for more information - 23/11/2018 - Don't use get_current_item or get_current_row within currentItemChanged or currentChanged signals. @@ -139,7 +115,10 @@ Qt doesn't update selected rows on first currentChanged or currentItemChanged ca - 22/05/2023 - For QTableWidget and QTableView, disabling wordWrap and using ScrollPerPixel as the horizontal scroll mode can help the user experience. Consider doing these when creating a new QTableWidget or QTableView -- 2/9/2018 - All functions with docstrings should have their subfunctions written after their docstrings. For instance: +- 15/02/2024 - Don't always trust the "Adjust Size" button of the Qt Designer, it might expand widgets much more than needed, especially for smaller widgets. Consider the use cases +and adjust manually. This also helps functions like `guiutils.center_to_parent` work properly + +- 02/09/2018 - All functions with docstrings should have their subfunctions written after their docstrings. For instance: ```python def test(): """documentation for test""" @@ -168,11 +147,11 @@ OSError and ValueError exceptions. For instance: ``` OSError handles I/O related errors and ValueError handles the off_t limit error that prints "cannot fit 'int' into an offset-sized integer" -- 12/9/2018 - All namedtuples must have the same field name with their variable names. This makes the namedtuple transferable via pickle. For instance: +- 12/09/2018 - All namedtuples must have the same field name with their variable names. This makes the namedtuple transferable via pickle. For instance: ```python tuple_examine_expression = collections.namedtuple("tuple_examine_expression", "all address symbol") ``` -- 6/10/2016 - HexView section of MemoryViewerWindow.ui: Changed listWidget_HexView_Address to tableWidget_HexView_Address in order to prevent possible future visual bugs. +- 06/10/2016 - HexView section of MemoryViewerWindow.ui: Changed listWidget_HexView_Address to tableWidget_HexView_Address in order to prevent possible future visual bugs. Logically, it should stay as a listwidget considering its functionality. But it doesn't play nice with the other neighboring tablewidgets in different pyqt versions, forcing me to use magic numbers for adjusting, which is a bit hackish From 7affb53c234569e0cf0b0793ae47e57b8c22d92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 16 Feb 2024 14:19:19 +0300 Subject: [PATCH 364/487] Fix center_to_parent call order --- PINCE.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 48c6f76d..2cd3915f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4493,6 +4493,7 @@ def __init__(self, parent, address, length, watchpoint_type): else: raise Exception("Watchpoint type is invalid: " + str(watchpoint_type)) self.setWindowTitle(string) + guiutils.center_to_parent(self) # Called before the QMessageBox to center its position properly self.breakpoints = debugcore.track_watchpoint(address, length, watchpoint_type) if not self.breakpoints: QMessageBox.information(self, tr.ERROR, tr.TRACK_WATCHPOINT_FAILED.format(address)) @@ -4503,7 +4504,6 @@ def __init__(self, parent, address, length, watchpoint_type): self.tableWidget_Opcodes.itemDoubleClicked.connect(self.tableWidget_Opcodes_item_double_clicked) self.tableWidget_Opcodes.selectionModel().currentChanged.connect(self.tableWidget_Opcodes_current_changed) self.update_timer.start(100) - guiutils.center_to_parent(self) self.show() def update_list(self): @@ -4576,6 +4576,7 @@ def __init__(self, parent, address, instruction, register_expressions): self.last_selected_row = 0 self.setWindowFlags(Qt.WindowType.Window) self.setWindowTitle(tr.ACCESSED_BY_INSTRUCTION.format(instruction)) + guiutils.center_to_parent(self) # Called before the QMessageBox to center its position properly self.breakpoint = debugcore.track_breakpoint(address, register_expressions) if not self.breakpoint: QMessageBox.information(self, tr.ERROR, tr.TRACK_BREAKPOINT_FAILED.format(address)) @@ -4589,7 +4590,6 @@ def __init__(self, parent, address, instruction, register_expressions): self.update_list_timer.start(100) self.update_values_timer.start(500) self.parent().refresh_disassemble_view() - guiutils.center_to_parent(self) self.show() def update_list(self): From 4d09fe646a2e2a4c11eceb3d419bed4c9864c342 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sat, 17 Feb 2024 11:43:32 +0100 Subject: [PATCH 365/487] Add key press event handling for deleting rows in valuesearchtable --- PINCE.py | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/PINCE.py b/PINCE.py index 2cd3915f..3ea8d015 100755 --- a/PINCE.py +++ b/PINCE.py @@ -32,7 +32,8 @@ from tr.tr import language_list, get_locale from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ - QRegularExpressionValidator, QShortcut, QColorConstants, QStandardItemModel, QStandardItem, QCloseEvent + QRegularExpressionValidator, QShortcut, QColorConstants, QStandardItemModel, QStandardItem, QCloseEvent, \ + QKeyEvent from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy @@ -465,6 +466,8 @@ def __init__(self): self.pushButton_CleanAddressTable.clicked.connect(self.clear_address_table) self.tableWidget_valuesearchtable.cellDoubleClicked.connect( self.tableWidget_valuesearchtable_cell_double_clicked) + self.tableWidget_valuesearchtable.keyPressEvent_original = self.tableWidget_valuesearchtable.keyPressEvent + self.tableWidget_valuesearchtable.keyPressEvent = self.tableWidget_valuesearchtable_key_press_event self.treeWidget_AddressTable.itemClicked.connect(self.treeWidget_AddressTable_item_clicked) self.treeWidget_AddressTable.itemDoubleClicked.connect(self.treeWidget_AddressTable_item_double_clicked) self.treeWidget_AddressTable.expanded.connect(self.resize_address_table) @@ -1209,11 +1212,7 @@ def scan_callback(self): self.progress_bar_timer.stop() self.progressBar.setValue(100) matches = scanmem.matches() - match_count = scanmem.get_match_count() - if match_count > 1000: - self.label_MatchCount.setText(tr.MATCH_COUNT_LIMITED.format(match_count, 1000)) - else: - self.label_MatchCount.setText(tr.MATCH_COUNT.format(match_count)) + self.update_match_count() self.tableWidget_valuesearchtable.setRowCount(0) current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) length = self._scan_to_length(current_type) @@ -1250,6 +1249,13 @@ def _scan_to_length(self, type_index): if type_index == typedefs.SCAN_INDEX.STRING: return len(self.lineEdit_Scan.text()) return 0 + + def update_match_count(self): + match_count = scanmem.get_match_count() + if match_count > 1000: + self.label_MatchCount.setText(tr.MATCH_COUNT_LIMITED.format(match_count, 1000)) + else: + self.label_MatchCount.setText(tr.MATCH_COUNT.format(match_count)) def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): current_item = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL) @@ -1259,6 +1265,29 @@ def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): self.add_entry_to_addresstable(tr.NO_DESCRIPTION, current_item.text(), vt) self.update_address_table() + def tableWidget_valuesearchtable_key_press_event(self, event: QKeyEvent) -> None: + if event.key() == Qt.Key.Key_Delete: + # get selected rows + selected_rows = self.tableWidget_valuesearchtable.selectedItems() + if not selected_rows: + return + + # get the row indexes + rows = set() + for item in selected_rows: + rows.add(item.row()) + + scanmem.send_command("delete {}".format(",".join([str(row) for row in rows]))) + + # remove the rows from the table - removing in reverse sorted order to avoid index issues + for row in sorted(rows, reverse=True): + self.tableWidget_valuesearchtable.removeRow(row) + self.update_match_count() + + return + + self.tableWidget_valuesearchtable.keyPressEvent_original(event) + def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) validator_map = { From f65a367b4f8c9f045969f99585f2f7cc1d3d311f Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sat, 10 Feb 2024 13:06:31 +0100 Subject: [PATCH 366/487] QOL Add numpad Enter key for "edit Value" --- PINCE.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PINCE.py b/PINCE.py index 3ea8d015..c6905475 100755 --- a/PINCE.py +++ b/PINCE.py @@ -922,6 +922,8 @@ def treeWidget_AddressTable_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), lambda: self.paste_records(True)), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_value), + (QKeyCombination(Qt.KeyboardModifier.KeypadModifier, Qt.Key.Key_Enter), + self.treeWidget_AddressTable_edit_value), (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_desc), (QKeyCombination(Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), From 518d06b782e979d46b73b11e0eacaee79a65c8f2 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sat, 17 Feb 2024 11:48:38 +0100 Subject: [PATCH 367/487] QOL also add num enter key on select process --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index c6905475..8cbff495 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1731,7 +1731,7 @@ def generate_new_list(self): def keyPressEvent(self, event): if event.key() == Qt.Key.Key_Escape: self.close() - elif event.key() == Qt.Key.Key_Return: + elif event.key() == Qt.Key.Key_Return or event.key() == Qt.Key.Key_Enter: self.pushButton_Open_clicked() elif event.key() == Qt.Key.Key_F1: self.pushButton_CreateProcess_clicked() From 519bf67993189beef99af9395638510ec8ed3a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 17 Feb 2024 17:42:22 +0300 Subject: [PATCH 368/487] Remove redundant statement from value search table --- GUI/MainWindow.py | 1 - GUI/MainWindow.ui | 3 --- 2 files changed, 4 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index f141bfaa..68ba25b1 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -134,7 +134,6 @@ def setupUi(self, MainWindow): self.tableWidget_valuesearchtable.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_valuesearchtable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_valuesearchtable.setAlternatingRowColors(True) - self.tableWidget_valuesearchtable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection) self.tableWidget_valuesearchtable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_valuesearchtable.setShowGrid(False) self.tableWidget_valuesearchtable.setObjectName("tableWidget_valuesearchtable") diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index dd297348..5582b4ea 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -317,9 +317,6 @@ true - - QAbstractItemView::ExtendedSelection - QAbstractItemView::SelectRows From 8e41444782f076820cb667fade1002d5a0ee3824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 19 Feb 2024 12:47:07 +0300 Subject: [PATCH 369/487] Fix auto attach --- GUI/Settings/settings.py | 2 +- GUI/SettingsDialog.py | 8 +++---- GUI/SettingsDialog.ui | 4 ++-- PINCE.py | 46 +++++++++++++++++++++------------------- i18n/ts/it_IT.ts | 13 ++++++------ i18n/ts/zh_CN.ts | 15 ++++++------- libpince/utils.py | 4 ++-- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/GUI/Settings/settings.py b/GUI/Settings/settings.py index 5864f9d4..df8cdef6 100644 --- a/GUI/Settings/settings.py +++ b/GUI/Settings/settings.py @@ -1,6 +1,6 @@ import libpince.typedefs as typedefs -current_settings_version = "33" # Increase version by one if you change settings +current_settings_version = "34" # Increase version by one if you change settings # Unused, will be re-added in the future code_injection_method: int = 0 diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 560145ad..d456b670 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -131,9 +131,9 @@ def setupUi(self, Dialog): self.label_9 = QtWidgets.QLabel(parent=self.page) self.label_9.setObjectName("label_9") self.horizontalLayout_12.addWidget(self.label_9) - self.lineEdit_AutoAttachList = QtWidgets.QLineEdit(parent=self.page) - self.lineEdit_AutoAttachList.setObjectName("lineEdit_AutoAttachList") - self.horizontalLayout_12.addWidget(self.lineEdit_AutoAttachList) + self.lineEdit_AutoAttach = QtWidgets.QLineEdit(parent=self.page) + self.lineEdit_AutoAttach.setObjectName("lineEdit_AutoAttach") + self.horizontalLayout_12.addWidget(self.lineEdit_AutoAttach) self.checkBox_AutoAttachRegex = QtWidgets.QCheckBox(parent=self.page) self.checkBox_AutoAttachRegex.setObjectName("checkBox_AutoAttachRegex") self.horizontalLayout_12.addWidget(self.checkBox_AutoAttachRegex) @@ -383,7 +383,7 @@ def retranslateUi(self, Dialog): self.checkBox_OutputModeCommandInfo.setText(_translate("Dialog", "Command info")) self.label_9.setToolTip(_translate("Dialog", "On start, automatically attach to processes with name matching one of the entries\n" "Patterns at former positions have higher priority if regex is off")) - self.label_9.setText(_translate("Dialog", "Auto-attach on start")) + self.label_9.setText(_translate("Dialog", "Auto-attach to processes named")) self.checkBox_AutoAttachRegex.setText(_translate("Dialog", "Regex")) self.label_13.setText(_translate("Dialog", "Language")) self.label_11.setText(_translate("Dialog", "Logo")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 0cfc6241..8abe2185 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -254,12 +254,12 @@ Patterns at former positions have higher priority if regex is off - Auto-attach on start + Auto-attach to processes named - + diff --git a/PINCE.py b/PINCE.py index 8cbff495..68e816aa 100755 --- a/PINCE.py +++ b/PINCE.py @@ -346,7 +346,7 @@ class MainForm(QMainWindow, MainWindow): table_update_interval: int = 500 freeze_interval: int = 100 update_table: bool = True - auto_attach_list: str = "" + auto_attach: str = "" auto_attach_regex: bool = False def __init__(self): @@ -383,6 +383,7 @@ def __init__(self): self.settings = QSettings() self.memory_view_window = MemoryViewWindowForm(self) self.await_exit_thread = AwaitProcessExit() + self.auto_attach_timer = QTimer(timeout=self.auto_attach_loop) if not os.path.exists(self.settings.fileName()): self.set_default_settings() @@ -490,7 +491,6 @@ def __init__(self): self.flashAttachButtonTimer.timeout.connect(self.flash_attach_button) self.flashAttachButton_gradiantState = 0 self.flashAttachButtonTimer.start(100) - self.auto_attach() guiutils.center(self) # Please refrain from using python specific objects in settings, use json-compatible ones instead @@ -501,7 +501,7 @@ def set_default_settings(self): self.settings.setValue("address_table_update_interval", MainForm.table_update_interval) self.settings.setValue("freeze_interval", MainForm.freeze_interval) self.settings.setValue("gdb_output_mode", json.dumps([True, True, True])) - self.settings.setValue("auto_attach_list", MainForm.auto_attach_list) + self.settings.setValue("auto_attach", MainForm.auto_attach) self.settings.setValue("auto_attach_regex", MainForm.auto_attach_regex) self.settings.setValue("locale", get_locale()) self.settings.setValue("logo_path", "ozgurozbek/pince_small_transparent.png") @@ -557,8 +557,12 @@ def apply_settings(self): self.freeze_interval = self.settings.value("General/freeze_interval", type=int) settings.gdb_output_mode = json.loads(self.settings.value("General/gdb_output_mode", type=str)) settings.gdb_output_mode = typedefs.gdb_output_mode(*settings.gdb_output_mode) - self.auto_attach_list = self.settings.value("General/auto_attach_list", type=str) + self.auto_attach = self.settings.value("General/auto_attach", type=str) self.auto_attach_regex = self.settings.value("General/auto_attach_regex", type=bool) + if self.auto_attach: + self.auto_attach_timer.start(100) + else: + self.auto_attach_timer.stop() settings.locale = self.settings.value("General/locale", type=str) app.setWindowIcon(QIcon(os.path.join(utils.get_logo_directory(), self.settings.value("General/logo_path", type=str)))) @@ -579,26 +583,24 @@ def apply_settings(self): # Check if any process should be attached to automatically # Patterns at former positions have higher priority if regex is off - def auto_attach(self): - if not self.auto_attach_list: + def auto_attach_loop(self): + if debugcore.currentpid != -1: return if self.auto_attach_regex: try: - compiled_re = re.compile(self.auto_attach_list) + compiled_re = re.compile(self.auto_attach) except: - print("Auto-attach failed: " + self.auto_attach_list + " isn't a valid regex") + print(f"Auto-attach failed: {self.auto_attach} isn't a valid regex") return for pid, _, name in utils.get_process_list(): if compiled_re.search(name): - self.attach_to_pid(pid) - self.flashAttachButton = False + self.attach_to_pid(int(pid)) return else: - for target in self.auto_attach_list.split(";"): + for target in self.auto_attach.split(";"): for pid, _, name in utils.get_process_list(): if name.find(target) != -1: - self.attach_to_pid(pid) - self.flashAttachButton = False + self.attach_to_pid(int(pid)) return # Keyboard package has an issue with exceptions, any trigger function that throws an exception stops the event loop @@ -1350,7 +1352,7 @@ def pushButton_Save_clicked(self): QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) # Returns: a bool value indicates whether the operation succeeded. - def attach_to_pid(self, pid): + def attach_to_pid(self, pid: int): attach_result = debugcore.attach(pid, settings.gdb_path) if attach_result == typedefs.ATTACH_RESULT.SUCCESSFUL: self.apply_after_init() @@ -2360,11 +2362,11 @@ def accept(self): self.settings.setValue("General/gdb_output_mode", json.dumps(output_mode)) if self.checkBox_AutoAttachRegex.isChecked(): try: - re.compile(self.lineEdit_AutoAttachList.text()) + re.compile(self.lineEdit_AutoAttach.text()) except: - QMessageBox.information(self, tr.ERROR, tr.IS_INVALID_REGEX.format(self.lineEdit_AutoAttachList.text())) + QMessageBox.information(self, tr.ERROR, tr.IS_INVALID_REGEX.format(self.lineEdit_AutoAttach.text())) return - self.settings.setValue("General/auto_attach_list", self.lineEdit_AutoAttachList.text()) + self.settings.setValue("General/auto_attach", self.lineEdit_AutoAttach.text()) self.settings.setValue("General/auto_attach_regex", self.checkBox_AutoAttachRegex.isChecked()) new_locale = self.comboBox_Language.currentData(Qt.ItemDataRole.UserRole) if new_locale != settings.locale: @@ -2413,7 +2415,7 @@ def config_gui(self): self.checkBox_OutputModeAsync.setChecked(output_mode.async_output) self.checkBox_OutputModeCommand.setChecked(output_mode.command_output) self.checkBox_OutputModeCommandInfo.setChecked(output_mode.command_info) - self.lineEdit_AutoAttachList.setText(self.settings.value("General/auto_attach_list", type=str)) + self.lineEdit_AutoAttach.setText(self.settings.value("General/auto_attach", type=str)) self.checkBox_AutoAttachRegex.setChecked(self.settings.value("General/auto_attach_regex", type=bool)) current_locale = self.settings.value("General/locale", type=str) self.comboBox_Language.setCurrentText(language_list.get(current_locale, "en_US")) @@ -2475,11 +2477,11 @@ def checkBox_AutoUpdateAddressTable_state_changed(self): def checkBox_AutoAttachRegex_state_changed(self): if self.checkBox_AutoAttachRegex.isChecked(): - self.lineEdit_AutoAttachList.setPlaceholderText(tr.MOUSE_OVER_EXAMPLES) - self.lineEdit_AutoAttachList.setToolTip(tr.AUTO_ATTACH_TOOLTIP) + self.lineEdit_AutoAttach.setPlaceholderText(tr.MOUSE_OVER_EXAMPLES) + self.lineEdit_AutoAttach.setToolTip(tr.AUTO_ATTACH_TOOLTIP) else: - self.lineEdit_AutoAttachList.setPlaceholderText(tr.SEPARATE_PROCESSES_WITH.format(";")) - self.lineEdit_AutoAttachList.setToolTip("") + self.lineEdit_AutoAttach.setPlaceholderText(tr.SEPARATE_PROCESSES_WITH.format(";")) + self.lineEdit_AutoAttach.setToolTip("") def comboBox_Logo_current_index_changed(self): logo_path = self.comboBox_Logo.currentText() diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 875767bf..f7e52876 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -188,12 +188,6 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Refresh - - - - Dialog - - Processing @@ -282,7 +276,7 @@ Patterns at former positions have higher priority if regex is off - Auto-attach on start + Auto-attach to processes named @@ -370,6 +364,11 @@ Patterns at former positions have higher priority if regex is off Reset Settings + + + Dialog + + Hit Esc to cancel and Ctrl+Enter to accept diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index e3f369c4..a5438efe 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -189,12 +189,6 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Refresh 刷新 - - - - Dialog - 对话框 - Processing @@ -284,8 +278,8 @@ Patterns at former positions have higher priority if regex is off - Auto-attach on start - 启动时自动附加到 + Auto-attach to processes named + @@ -372,6 +366,11 @@ Patterns at former positions have higher priority if regex is off Reset Settings 重置设置 + + + Dialog + 对话框 + Hit Esc to cancel and Ctrl+Enter to accept diff --git a/libpince/utils.py b/libpince/utils.py index 50bd92d1..3ce9ad2f 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ - import os, shutil, sys, binascii, pickle, json, traceback, re, pwd, pathlib, distorm3 from . import typedefs, regexes from keystone import Ks, KsError, KS_ARCH_X86, KS_MODE_32, KS_MODE_64 @@ -27,8 +26,9 @@ ks_32 = Ks(KS_ARCH_X86, KS_MODE_32) ks_64 = Ks(KS_ARCH_X86, KS_MODE_64) + #:tag:Processes -def get_process_list(): +def get_process_list() -> list[str, str, str]: """Returns a list of processes Returns: From 6ae33742282fd365b421c5cf1d98fd534ecbd6bb Mon Sep 17 00:00:00 2001 From: Bastian Ebiko Jesuiter Date: Tue, 27 Feb 2024 18:22:21 +0100 Subject: [PATCH 370/487] Fix Hotkey implementation (#241) * Fix Hotkey implementation Now more hotkeys are possible * Fixed bug with ctrl + char/number not working * rewrite how hotkeys are read Apply hack-fix to the regex pattern from keyboard lib Apply guard to prevent invalid hotkeys from resetting complete settings --- GUI/SettingsDialog.py | 10 ++++--- GUI/SettingsDialog.ui | 9 +++++- GUI/Utils/__init__.py | 5 ++++ GUI/Utils/keyboard_hack.py | 42 +++++++++++++++++++++++++++ PINCE.py | 59 +++++++++++++++++++++++++++++--------- i18n/ts/it_IT.ts | 5 ++++ i18n/ts/zh_CN.ts | 5 ++++ 7 files changed, 117 insertions(+), 18 deletions(-) create mode 100644 GUI/Utils/__init__.py create mode 100644 GUI/Utils/keyboard_hack.py diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index d456b670..34b6a5a9 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SettingsDialog.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.6.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -197,9 +197,10 @@ def setupUi(self, Dialog): self.label_4 = QtWidgets.QLabel(parent=self.page_2) self.label_4.setObjectName("label_4") self.verticalLayout_Hotkey.addWidget(self.label_4) - self.keySequenceEdit_Hotkey = QtWidgets.QKeySequenceEdit(parent=self.page_2) - self.keySequenceEdit_Hotkey.setObjectName("keySequenceEdit_Hotkey") - self.verticalLayout_Hotkey.addWidget(self.keySequenceEdit_Hotkey) + self.lineEdit_Hotkey = QtWidgets.QLineEdit(parent=self.page_2) + self.lineEdit_Hotkey.setReadOnly(True) + self.lineEdit_Hotkey.setObjectName("lineEdit_Hotkey") + self.verticalLayout_Hotkey.addWidget(self.lineEdit_Hotkey) self.verticalLayout_6.addLayout(self.verticalLayout_Hotkey) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") @@ -390,6 +391,7 @@ def retranslateUi(self, Dialog): self.label_14.setText(_translate("Dialog", "Theme")) self.label_3.setText(_translate("Dialog", "Functions")) self.label_4.setText(_translate("Dialog", "Hotkey")) + self.lineEdit_Hotkey.setPlaceholderText(_translate("Dialog", "Press shortcut")) self.pushButton_ClearHotkey.setText(_translate("Dialog", "Clear")) self.label_5.setText(_translate("Dialog", "Code injection method:")) self.radioButton_SimpleDLopenCall.setText(_translate("Dialog", "Simp&le dlopen call")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 8abe2185..758f2082 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -402,7 +402,14 @@ Patterns at former positions have higher priority if regex is off - + + + true + + + Press shortcut + + diff --git a/GUI/Utils/__init__.py b/GUI/Utils/__init__.py new file mode 100644 index 00000000..9bd5e10d --- /dev/null +++ b/GUI/Utils/__init__.py @@ -0,0 +1,5 @@ +import keyboard +from . import keyboard_hack + +# replace keyboard.parse_hotkey() with fix for literal '+' in hotkey strings +keyboard.parse_hotkey = keyboard_hack.parse_hotkey diff --git a/GUI/Utils/keyboard_hack.py b/GUI/Utils/keyboard_hack.py new file mode 100644 index 00000000..2bd35335 --- /dev/null +++ b/GUI/Utils/keyboard_hack.py @@ -0,0 +1,42 @@ +from keyboard import key_to_scan_codes +import re as _re + +# copied from keyboard.__init__.py +_is_str = lambda x: isinstance(x, str) +_is_number = lambda x: isinstance(x, int) +_is_list = lambda x: isinstance(x, (list, tuple)) + +def parse_hotkey(hotkey): + ## function to replace keyboard.parse_hotkey() with fix for literal '+' in hotkey strings + """ + Parses a user-provided hotkey into nested tuples representing the + parsed structure, with the bottom values being lists of scan codes. + Also accepts raw scan codes, which are then wrapped in the required + number of nestings. + + Example: + + parse_hotkey("alt+shift+a, alt+b, c") + # Keys: ^~^ ^~~~^ ^ ^~^ ^ ^ + # Steps: ^~~~~~~~~~^ ^~~~^ ^ + + # ((alt_codes, shift_codes, a_codes), (alt_codes, b_codes), (c_codes,)) + """ + if _is_number(hotkey) or len(hotkey) == 1: + scan_codes = key_to_scan_codes(hotkey) + step = (scan_codes,) + steps = (step,) + return steps + elif _is_list(hotkey): + if not any(map(_is_list, hotkey)): + step = tuple(key_to_scan_codes(k) for k in hotkey) + steps = (step,) + return steps + return hotkey + + steps = [] + # since we dont have spaces in hotkey strings, we can ignore whitespace in the regex + for step in _re.split(r'(? "1" + ev.name = to_name[(ev.scan_code, ())][-1] + # keyboard does recognize meta key (win key) as alt, setting manually + if ev.scan_code == 125 or ev.scan_code == 126: + ev.name = "windows" + hotkey_string += ev.name + "+" + + # remove the last plus + hotkey_string = hotkey_string[:-1] + + # moved from old keySequenceChanged event + self.lineEdit_Hotkey.setText(hotkey_string) + index = self.listWidget_Functions.currentIndex().row() + if index == -1: + self.lineEdit_Hotkey.clear() + else: + self.hotkey_to_value[ + hotkeys.get_hotkeys()[index].name] = self.lineEdit_Hotkey.text() class HandleSignalsDialogForm(QDialog, HandleSignalsDialog): def __init__(self, parent, signal_data): diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index f7e52876..87a927e4 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -309,6 +309,11 @@ Patterns at former positions have higher priority if regex is off Hotkey + + + Press shortcut + + Clear diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index a5438efe..78b0ef98 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -311,6 +311,11 @@ Patterns at former positions have higher priority if regex is off Hotkey 快捷键 + + + Press shortcut + + Clear From d4cb1564324f31f20cd1300bdefc788e7b2351ef Mon Sep 17 00:00:00 2001 From: Bastian Ebiko Jesuiter Date: Mon, 4 Mar 2024 10:50:24 +0100 Subject: [PATCH 371/487] QOL Fix - keep hex validator between type-change (#243) * QOL Fix - keep hex validator between type-change Also cleanup some unnecessary code. Moved some duplicate code into guiutils as const. * QOL lineedit readonly instead of disabled Changes the lineEdit_Address in the Edit Address Form from disabled to readonly when pointer. * fix optional 0x in hex --- GUI/Utils/guiutils.py | 15 ++++++++++++-- PINCE.py | 48 +++++++++++++++---------------------------- libpince/regexes.py | 4 ++++ 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index f0fea38d..2045b1ef 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -16,8 +16,8 @@ along with this program. If not, see . """ from PyQt6.QtWidgets import QWidget, QScrollBar, QTableWidget, QComboBox, QMenu, QLayout -from PyQt6.QtCore import QObject -from PyQt6.QtGui import QShortcut +from PyQt6.QtCore import QObject, QRegularExpression +from PyQt6.QtGui import QShortcut, QRegularExpressionValidator from libpince import utils, typedefs, regexes from tr.tr import TranslationConstants as tr @@ -243,3 +243,14 @@ def append_shortcut_to_tooltip(qt_object: QObject, shortcut: QShortcut): shortcut (QShortcut): Self-explanatory """ qt_object.setToolTip(qt_object.toolTip() + "[" + shortcut.key().toString() + "]") + +#:tag:GUI +#:tag:CONSTANTS +validator_map:dict[str,QRegularExpressionValidator|None] = { + "int": QRegularExpressionValidator(QRegularExpression(regexes.decimal_number.pattern)), # integers + "int_hex": QRegularExpressionValidator(QRegularExpression(regexes.hex_number_gui.pattern)), # hexadecimals + "float": QRegularExpressionValidator(QRegularExpression(regexes.float_number.pattern)), # floats + "bytearray": QRegularExpressionValidator(QRegularExpression(regexes.bytearray_input.pattern)), + # array of bytes + "string": None +} diff --git a/PINCE.py b/PINCE.py index 176f8f15..a5520b7e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -32,13 +32,13 @@ from tr.tr import language_list, get_locale from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ - QRegularExpressionValidator, QShortcut, QColorConstants, QStandardItemModel, QStandardItem, QCloseEvent, \ + QShortcut, QColorConstants, QStandardItemModel, QStandardItem, QCloseEvent, \ QKeyEvent from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ - QItemSelectionModel, QTimer, QStringListModel, QRegularExpression, QRunnable, QObject, QThreadPool, \ + QItemSelectionModel, QTimer, QStringListModel, QRunnable, QObject, QThreadPool, \ QLocale, QSignalBlocker, QItemSelection from typing import Final from time import sleep, time @@ -353,14 +353,6 @@ class MainForm(QMainWindow, MainWindow): auto_attach_regex: bool = False def __init__(self): - """ - Declare regular expressions for hexadecimal and decimal input - to be used in checkBox_Hex_stateChanged (or anywhere else that - they are needed). - """ - self.qRegExp_hex: Final[QRegularExpression] = QRegularExpression("(0x)?[A-Fa-f0-9]*$") - self.qRegExp_dec: Final[QRegularExpression] = QRegularExpression("-?[0-9]*") - super().__init__() self.setupUi(self) self.hotkey_to_shortcut = {} @@ -449,10 +441,8 @@ def __init__(self): guiutils.fill_endianness_combobox(self.comboBox_Endianness) self.checkBox_Hex.stateChanged.connect(self.checkBox_Hex_stateChanged) self.comboBox_ValueType.currentIndexChanged.connect(self.comboBox_ValueType_current_index_changed) - self.lineEdit_Scan.setValidator( - QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan)) - self.lineEdit_Scan2.setValidator( - QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.setValidator(guiutils.validator_map.get("int")) + self.lineEdit_Scan2.setValidator(guiutils.validator_map.get("int")) self.lineEdit_Scan.keyPressEvent_original = self.lineEdit_Scan.keyPressEvent self.lineEdit_Scan2.keyPressEvent_original = self.lineEdit_Scan2.keyPressEvent self.lineEdit_Scan.keyPressEvent = self.lineEdit_Scan_on_key_press_event @@ -1059,12 +1049,12 @@ def pushButton_Console_clicked(self): def checkBox_Hex_stateChanged(self, state): if Qt.CheckState(state) == Qt.CheckState.Checked: # allows only things that are hex, can also start with 0x - self.lineEdit_Scan.setValidator(QRegularExpressionValidator(self.qRegExp_hex, parent=self.lineEdit_Scan)) - self.lineEdit_Scan2.setValidator(QRegularExpressionValidator(self.qRegExp_hex, parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.setValidator(guiutils.validator_map.get("int_hex")) + self.lineEdit_Scan2.setValidator(guiutils.validator_map.get("int_hex")) else: # sets it back to integers only - self.lineEdit_Scan.setValidator(QRegularExpressionValidator(self.qRegExp_dec, parent=self.lineEdit_Scan)) - self.lineEdit_Scan2.setValidator(QRegularExpressionValidator(self.qRegExp_dec, parent=self.lineEdit_Scan2)) + self.lineEdit_Scan.setValidator(guiutils.validator_map.get("int")) + self.lineEdit_Scan2.setValidator(guiutils.validator_map.get("int")) def pushButton_NewFirstScan_clicked(self): if debugcore.currentpid == -1: @@ -1303,15 +1293,6 @@ def tableWidget_valuesearchtable_key_press_event(self, event: QKeyEvent) -> None def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) - validator_map = { - "int": QRegularExpressionValidator(QRegularExpression("-?[0-9]*"), parent=self.lineEdit_Scan), # integers - "float": QRegularExpressionValidator(QRegularExpression("-?[0-9]+[.,]?[0-9]*")), - # floats, should work fine with the small amount of testing I did - "bytearray": QRegularExpressionValidator(QRegularExpression("^(([A-Fa-f0-9?]{2} +)+)$"), - parent=self.lineEdit_Scan), - # array of bytes - "string": None - } scanmem_type = typedefs.scan_index_to_scanmem_dict[current_type] validator_str = scanmem_type # used to get the correct validator @@ -1319,14 +1300,17 @@ def comboBox_ValueType_current_index_changed(self): if "int" in validator_str: validator_str = "int" self.checkBox_Hex.setEnabled(True) + # keep hex validator if hex is checked + if (self.checkBox_Hex.isChecked()): + validator_str = "int_hex" else: self.checkBox_Hex.setChecked(False) self.checkBox_Hex.setEnabled(False) if "float" in validator_str or validator_str == "number": validator_str = "float" - self.lineEdit_Scan.setValidator(validator_map[validator_str]) - self.lineEdit_Scan2.setValidator(validator_map[validator_str]) + self.lineEdit_Scan.setValidator(guiutils.validator_map[validator_str]) + self.lineEdit_Scan2.setValidator(guiutils.validator_map[validator_str]) scanmem.send_command("option scan_data_type {}".format(scanmem_type)) # according to scanmem instructions you should always do `reset` after changing type scanmem.reset() @@ -1808,7 +1792,7 @@ def __init__(self, parent, description=tr.NO_DESCRIPTION, address="0x", value_ty self.widget_Pointer.hide() else: self.checkBox_IsPointer.setChecked(True) - self.lineEdit_Address.setEnabled(False) + self.lineEdit_Address.setReadOnly(True) self.lineEdit_PtrStartAddress.setText(address.get_base_address()) self.create_offsets_list(address) self.widget_Pointer.show() @@ -1950,7 +1934,7 @@ def repr_changed(self): def checkBox_IsPointer_state_changed(self): if self.checkBox_IsPointer.isChecked(): - self.lineEdit_Address.setEnabled(False) + self.lineEdit_Address.setReadOnly(True) self.lineEdit_PtrStartAddress.setText(self.lineEdit_Address.text()) if len(self.offsetsList) == 0: self.addOffsetLayout(False) @@ -1958,7 +1942,7 @@ def checkBox_IsPointer_state_changed(self): else: self.lineEdit_Address.setText(self.lineEdit_PtrStartAddress.text()) self.lineEdit_PtrStartAddress.setText("") - self.lineEdit_Address.setEnabled(True) + self.lineEdit_Address.setReadOnly(False) self.widget_Pointer.hide() self.update_value() diff --git a/libpince/regexes.py b/libpince/regexes.py index 9bf660bf..076ed5f3 100644 --- a/libpince/regexes.py +++ b/libpince/regexes.py @@ -69,6 +69,10 @@ # --------------------------------------------guiutils------------------------------------------------------------------ reference_mark = compile(r"\{\d*\}") +float_number = compile(r"-?[0-9]+[.,]?[0-9]*") +bytearray_input = compile(r"^(([A-Fa-f0-9?]{2} +)+)$") +decimal_number = compile(r"-?\d+") +hex_number_gui = compile(r"(0x)?[0-9a-fA-F]*") # contains optional 0x prefix # --------------------------------------------gdbextensions------------------------------------------------------ From a548c73cdda1d82ceabac351a38871d454d9bde2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 4 Mar 2024 12:59:04 +0300 Subject: [PATCH 372/487] move validator_map to the beginning of guiutils --- GUI/Utils/guiutils.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index 2045b1ef..4debbda2 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -21,6 +21,15 @@ from libpince import utils, typedefs, regexes from tr.tr import TranslationConstants as tr +#:tag:GUI +validator_map: dict[str, QRegularExpressionValidator | None] = { + "int": QRegularExpressionValidator(QRegularExpression(regexes.decimal_number.pattern)), # integers + "int_hex": QRegularExpressionValidator(QRegularExpression(regexes.hex_number_gui.pattern)), # hexadecimals + "float": QRegularExpressionValidator(QRegularExpression(regexes.float_number.pattern)), # floats + "bytearray": QRegularExpressionValidator(QRegularExpression(regexes.bytearray_input.pattern)), # array of bytes + "string": None +} + #:tag:GUI def get_icons_directory(): """Gets the directory of the icons @@ -243,14 +252,3 @@ def append_shortcut_to_tooltip(qt_object: QObject, shortcut: QShortcut): shortcut (QShortcut): Self-explanatory """ qt_object.setToolTip(qt_object.toolTip() + "[" + shortcut.key().toString() + "]") - -#:tag:GUI -#:tag:CONSTANTS -validator_map:dict[str,QRegularExpressionValidator|None] = { - "int": QRegularExpressionValidator(QRegularExpression(regexes.decimal_number.pattern)), # integers - "int_hex": QRegularExpressionValidator(QRegularExpression(regexes.hex_number_gui.pattern)), # hexadecimals - "float": QRegularExpressionValidator(QRegularExpression(regexes.float_number.pattern)), # floats - "bytearray": QRegularExpressionValidator(QRegularExpression(regexes.bytearray_input.pattern)), - # array of bytes - "string": None -} From 71d9cc10cf1ba206fc1942b0627207a126d57396 Mon Sep 17 00:00:00 2001 From: detiam Date: Sat, 16 Mar 2024 19:01:56 +0800 Subject: [PATCH 373/487] Update zh_CN translation --- i18n/ts/zh_CN.ts | 88 ++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 78b0ef98..34cbbcab 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -22,13 +22,13 @@ Hex - 十六进制 + 十六进制 Signed - + 有符号 @@ -151,7 +151,7 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Endianness - + 字节序 @@ -172,12 +172,12 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Stop & Print - + 停止和打印 Pass to Program - + 传递到程序 @@ -212,7 +212,7 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Hotkeys - 快捷键 + 热键 @@ -232,7 +232,7 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Java - + Java @@ -279,7 +279,7 @@ Patterns at former positions have higher priority if regex is off Auto-attach to processes named - + 自动附加到的进程名为 @@ -299,7 +299,7 @@ Patterns at former positions have higher priority if regex is off Theme - + 主题 @@ -309,12 +309,12 @@ Patterns at former positions have higher priority if regex is off Hotkey - 快捷键 + 热键 Press shortcut - + 按下快捷键 @@ -359,12 +359,12 @@ Patterns at former positions have higher priority if regex is off Interruption signal - + 中断信号 Ignore SIGSEGV for Java processes (overrides signal settings if enabled) - + 忽略 Java 进程的分段错误(SIGSEGV)(如果启用,将会覆盖信号设置) @@ -1202,92 +1202,92 @@ Patterns at former positions have higher priority if regex is off OK - + 确认 &Open - + 打开[&O] &Save - + 保存[&S] Cancel - 取消 + 取消 Close - 关闭 + 关闭 Discard - + 撤销 Apply - + 应用 Reset - + 复位 Restore Defaults - + 恢复为默认 Help - 帮助 + 帮助 Save All - + 全部保存 &Yes - + 是[&Y] &No - + 否[&N] Abort - + 关于 Retry - + 重试 Ignore - 忽略 + 忽略 N&o to All - + 全部否[&o] Yes to &All - + 全部是[&A] @@ -1405,7 +1405,7 @@ Patterns at former positions have higher priority if regex is off Toggle attach/detach - 切换附加/分离 + 切换附加 / 分离 @@ -1489,12 +1489,12 @@ To change the current GDB path, check Settings->Debug Toggle - + 切换 Toggle including children - + 切换包括子项 @@ -1534,22 +1534,22 @@ To change the current GDB path, check Settings->Debug Cut - + 剪切 Copy - + 复制 Paste - + 粘贴 Paste inside - + 粘贴在里 @@ -1569,17 +1569,17 @@ To change the current GDB path, check Settings->Debug Add to a new group - + 加入一个新组 Create a new group - + 创建一个新组 Group - + @@ -2276,7 +2276,7 @@ $28 是分配的便利变量 Enter the new value of flag {} - + 输入标志(flag){}的新值 @@ -2682,12 +2682,12 @@ Proceed? Show in HexView - + 在十六进制视图中显示 Show in Disassembler - + 在反汇编器中显示 From 8766aa4de4c0c80c8e8a208d9ca04bca04655b8f Mon Sep 17 00:00:00 2001 From: Berk Date: Thu, 21 Mar 2024 21:22:29 +0000 Subject: [PATCH 374/487] Add pip3 upgrade upon venv creation to fix modules install --- install_pince.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install_pince.sh b/install_pince.sh index 297e8853..d473e829 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -201,6 +201,7 @@ if [ ! -d ".venv/PINCE" ]; then python3 -m venv .venv/PINCE fi . .venv/PINCE/bin/activate +pip3 install --upgrade pip # shellcheck disable=SC2086 pip3 install -r requirements.txt || exit_on_error From 172aac3f6b9b2b0cdfcd750c0646ac9c876829ca Mon Sep 17 00:00:00 2001 From: Berk Date: Thu, 21 Mar 2024 21:27:29 +0000 Subject: [PATCH 375/487] Add error check to pip3 upgrade in installer --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index d473e829..2dcb8e39 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -201,7 +201,7 @@ if [ ! -d ".venv/PINCE" ]; then python3 -m venv .venv/PINCE fi . .venv/PINCE/bin/activate -pip3 install --upgrade pip +pip3 install --upgrade pip || exit_on_error # shellcheck disable=SC2086 pip3 install -r requirements.txt || exit_on_error From 8ceac2690d1bb35b6281c58fdf32f2e8bd9a8b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sun, 24 Mar 2024 17:48:20 +0000 Subject: [PATCH 376/487] Update Arch package requirements in installer --- install_pince.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_pince.sh b/install_pince.sh index 2dcb8e39..542fe32d 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -130,7 +130,7 @@ PKG_NAMES_ALL="python3-pip gdb libtool" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-dev python3-venv pkg-config qt6-l10n-tools libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" -PKG_NAMES_ARCH="python-pip qt6-tools gdb lsb-release pkgconf" # arch defaults to py3 nowadays +PKG_NAMES_ARCH="python-pip qt6-tools gdb lsb-release pkgconf gobject-introspection-runtime" # arch defaults to py3 nowadays INSTALL_COMMAND="install" From 0e0ae0b8f52274d8144001d6d475f0789239ea1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 30 Mar 2024 10:10:30 +0000 Subject: [PATCH 377/487] Change startup script to use static python3 venv path instead of relying on sudo correctly preserving paths --- PINCE.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.sh b/PINCE.sh index f3f90806..23800f79 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -30,4 +30,4 @@ fi # Preserve env vars to keep settings like theme preferences. # Debian/Ubuntu does not preserve PATH through sudo even with -E for security reasons # so we need to force PATH preservation with venv activated user's PATH. -sudo -E --preserve-env=PATH PYTHONDONTWRITEBYTECODE=1 python3 PINCE.py +sudo -E --preserve-env=PATH PYTHONDONTWRITEBYTECODE=1 .venv/PINCE/bin/python3 PINCE.py From 4827de4d920f92c3804f3b63a2e7fe4d3ce1faaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Mon, 8 Apr 2024 18:48:54 +0100 Subject: [PATCH 378/487] Change pointer reading backend logic to store results on each dereference --- PINCE.py | 44 +++++++++++++++++++++++-------------------- libpince/debugcore.py | 33 ++++++++++++++++++-------------- libpince/typedefs.py | 33 +++++++++++++++++++++++++------- 3 files changed, 69 insertions(+), 41 deletions(-) diff --git a/PINCE.py b/PINCE.py index a5520b7e..ab8e1996 100755 --- a/PINCE.py +++ b/PINCE.py @@ -737,13 +737,13 @@ def exec_track_watchpoint_widget(self, watchpoint_type): return address = selected_row.text(ADDR_COL).strip("P->") # @todo Maybe rework address grabbing logic in the future address_data = selected_row.data(ADDR_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, typedefs.PointerType): + if isinstance(address_data, typedefs.PointerChainRequest): selection_dialog = TrackSelectorDialogForm(self) selection_dialog.exec() if not selection_dialog.selection: return if selection_dialog.selection == "pointer": - address = address_data.get_base_address() + address = address_data.get_base_address_as_str() value_type = selected_row.data(TYPE_COL, Qt.ItemDataRole.UserRole) if typedefs.VALUE_INDEX.is_string(value_type.value_index): value_text = selected_row.text(VALUE_COL) @@ -850,7 +850,7 @@ def insert_records(self, records, parent_row, insert_index): # Deserialize the address_expr & value_type param if type(rec[1]) in [list, tuple]: - address_expr = typedefs.PointerType(*rec[1]) + address_expr = typedefs.PointerChainType(*rec[1]) else: address_expr = rec[1] value_type = typedefs.ValueType(*rec[2]) @@ -950,7 +950,7 @@ def update_address_table(self): break it += 1 address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, typedefs.PointerType): + if isinstance(address_data, typedefs.PointerChainRequest): expression = address_data.base_address else: expression = address_data @@ -971,14 +971,16 @@ def update_address_table(self): address = debugcore.examine_expression(expression).address exp_cache[expression] = address vt = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, typedefs.PointerType): + if isinstance(address_data, typedefs.PointerChainRequest): # The original base could be a symbol so we have to save it # This little hack avoids the unnecessary examine_expression call # TODO: Consider implementing exp_cache inside libpince so we don't need this hack + pointer_chain_req = address_data if address: - old_base = address_data.base_address # save the old base - address_data.base_address = address - address = debugcore.read_pointer(address_data) + old_base = pointer_chain_req.base_address # save the old base + pointer_chain_req.base_address = address + pointer_chain_result = debugcore.read_pointer_chain(pointer_chain_req) + address = pointer_chain_result.get_final_address() address_data.base_address = old_base # then set it back if address: address = hex(address) @@ -1667,7 +1669,7 @@ def read_address_table_entries(self, row, serialize=False): description = row.text(DESC_COL) if serialize: address_data = row.data(ADDR_COL, Qt.ItemDataRole.UserRole) - if isinstance(address_data, typedefs.PointerType): + if isinstance(address_data, typedefs.PointerChainRequest): address_expr = address_data.serialize() else: address_expr = address_data @@ -1787,13 +1789,13 @@ def __init__(self, parent, description=tr.NO_DESCRIPTION, address="0x", value_ty guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) self.lineEdit_Description.setText(description) self.offsetsList = [] - if not isinstance(address, typedefs.PointerType): + if not isinstance(address, typedefs.PointerChainRequest): self.lineEdit_Address.setText(address) self.widget_Pointer.hide() else: self.checkBox_IsPointer.setChecked(True) self.lineEdit_Address.setReadOnly(True) - self.lineEdit_PtrStartAddress.setText(address.get_base_address()) + self.lineEdit_PtrStartAddress.setText(address.get_base_address_as_str()) self.create_offsets_list(address) self.widget_Pointer.show() if typedefs.VALUE_INDEX.is_string(self.comboBox_ValueType.currentIndex()): @@ -1888,10 +1890,12 @@ def removeOffsetLayout(self): def update_value(self): if self.checkBox_IsPointer.isChecked(): - pointer_type = typedefs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) - address = debugcore.read_pointer(pointer_type) - if address != None: - address_text = hex(address) + pointer_chain_req = typedefs.PointerChainRequest(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) + pointer_chain_result = debugcore.read_pointer_chain(pointer_chain_req) + address = None + if pointer_chain_result != None: + address_text = pointer_chain_result.get_final_address_as_hex() + address = pointer_chain_result.get_final_address() else: address_text = "??" self.lineEdit_Address.setText(address_text) @@ -1981,7 +1985,7 @@ def get_values(self): endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) vt = typedefs.ValueType(value_index, length, zero_terminate, value_repr, endian) if self.checkBox_IsPointer.isChecked(): - address = typedefs.PointerType(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) + address = typedefs.PointerChainRequest(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) return description, address, vt def get_offsets_int_list(self): @@ -1995,11 +1999,11 @@ def get_offsets_int_list(self): offsetsIntList.append(offsetValue) return offsetsIntList - def create_offsets_list(self, address): - if not isinstance(address, typedefs.PointerType): - raise TypeError("Passed non-pointer type to create_offsets_list!") + def create_offsets_list(self, pointer_chain_req: typedefs.PointerChainRequest): + if not isinstance(pointer_chain_req, typedefs.PointerChainRequest): + raise TypeError("Passed non-PointerChainRequest type to create_offsets_list!") - for offset in address.offsets_list: + for offset in pointer_chain_req.offsets_list: self.addOffsetLayout(False) frame = self.offsetsList[-1] frame.layout().itemAt(1).widget().setText(hex(offset)) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 63a41425..d14a3647 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -757,18 +757,18 @@ def inject_with_dlopen_call(library_path): #:tag:MemoryRW -def read_pointer(pointer_type): - """Reads the address pointed by this pointer +def read_pointer_chain(pointer_request: typedefs.PointerChainRequest) -> typedefs.PointerChainResult | None: + """Reads the addresses pointed by this pointer chain Args: - pointer_type (PointerType): typedefs.PointerType class containing a base_address and an offsets list + pointer_request (typedefs.PointerChainRequest): class containing a base_address and an offsets list Returns: - int: Final pointed address after dereferencing this pointer and it's offsets list + typedefs.PointerChainResult: Class containing every pointer dereference result while walking the chain None: If an error occurs while reading the given pointer """ - if not isinstance(pointer_type, typedefs.PointerType): - raise TypeError("Passed non-PointerType to read_pointer!") + if not isinstance(pointer_request, typedefs.PointerChainRequest): + raise TypeError("Passed non-PointerChainRequest type to read_pointer_chain!") if inferior_arch == typedefs.INFERIOR_ARCH.ARCH_32: value_index = typedefs.VALUE_INDEX.INT32 @@ -777,26 +777,31 @@ def read_pointer(pointer_type): # Simple addresses first, examine_expression takes much longer time, especially for larger tables try: - start_address = int(pointer_type.base_address, 0) + start_address = int(pointer_request.base_address, 0) except (ValueError, TypeError): - start_address = examine_expression(pointer_type.base_address).address + start_address = examine_expression(pointer_request.base_address).address + + pointer_results: typedefs.PointerChainResult = typedefs.PointerChainResult() try: with memory_handle() as mem_handle: - final_address = deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) + # Dereference the first address which is the base or (base + offset) + deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) if deref_address is None: # deref would be None if read an invalid address region return None + pointer_results.pointer_chain.append(deref_address) - for index, offset in enumerate(pointer_type.offsets_list): + for index, offset in enumerate(pointer_request.offsets_list): offset_address = deref_address + offset - if index != len(pointer_type.offsets_list) - 1: # CE derefs every offset except for the last one + if index != len(pointer_request.offsets_list) - 1: # CE derefs every offset except for the last one deref_address = read_memory(offset_address, value_index, mem_handle=mem_handle) if deref_address is None: return None else: - final_address = offset_address + deref_address = offset_address + pointer_results.pointer_chain.append(deref_address) except OSError: - final_address = start_address - return final_address + return None + return pointer_results def memory_handle(): diff --git a/libpince/typedefs.py b/libpince/typedefs.py index 2fe933e7..cc1ac057 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -462,21 +462,40 @@ def text(self): return returned_string -class PointerType: - def __init__(self, base_address, offsets_list=None): +class PointerChainResult: + def __init__(self): + self.pointer_chain: list[int] = [] + + def get_pointer_by_index(self, index) -> int | None: + if index >= size(self.pointer_chain): + return None + return self.pointer_chain[index] + + def get_final_address(self) -> int | None: + return self.pointer_chain[-1] if self.pointer_chain else None + + def get_final_address_as_hex(self) -> str | None: + """ + Returns the hex representation of this pointer chain's final/destination address + """ + return hex(self.pointer_chain[-1]) if self.pointer_chain else None + + +class PointerChainRequest: + def __init__(self, base_address: str | int, offsets_list: list[int] = None): """ Args: - base_address (str, int): The base address of where this pointer starts from. Can be str expression or int. + base_address (str, int): The base address of where this pointer chain starts from. Can be str expression or int. offsets_list (list): List of offsets to reach the final pointed data. Can be None for no offsets. Last offset in list won't be dereferenced to emulate CE behaviour. """ - self.base_address = base_address - self.offsets_list = [] if not offsets_list else offsets_list + self.base_address: str | int = base_address + self.offsets_list: list[int] = [] if not offsets_list else offsets_list - def serialize(self): + def serialize(self) -> tuple[str | int, list[int]]: return self.base_address, self.offsets_list - def get_base_address(self): + def get_base_address_as_str(self) -> str: """ Returns the text representation of this pointer's base address """ From 752f69d89500ecea69b623b03bc6316c37b4924c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Mon, 8 Apr 2024 20:26:42 +0100 Subject: [PATCH 379/487] Change pointer UI behaviour --- GUI/AddAddressManuallyDialog.py | 8 ++++++-- GUI/AddAddressManuallyDialog.ui | 11 +++++++++-- PINCE.py | 26 ++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 5c8579ec..130c87e4 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.6.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,7 +12,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(240, 431) + Dialog.resize(262, 486) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.verticalLayout_3 = QtWidgets.QVBoxLayout() @@ -93,6 +93,9 @@ def setupUi(self, Dialog): self.lineEdit_PtrStartAddress = QtWidgets.QLineEdit(parent=self.widget_Pointer) self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) + self.label_BaseAddressDeref = QtWidgets.QLabel(parent=self.widget_Pointer) + self.label_BaseAddressDeref.setObjectName("label_BaseAddressDeref") + self.horizontalLayout_4.addWidget(self.label_BaseAddressDeref) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") @@ -171,6 +174,7 @@ def retranslateUi(self, Dialog): self.label_Length.setText(_translate("Dialog", "Length:")) self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_BaseAddress.setText(_translate("Dialog", "Base Address:")) + self.label_BaseAddressDeref.setText(_translate("Dialog", "-> ??")) self.pushButton_AddOffset.setText(_translate("Dialog", "Add Offset")) self.pushButton_RemoveOffset.setText(_translate("Dialog", "Remove Offset")) self.label_4.setText(_translate("Dialog", "Description:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index a24939e1..0f16e55d 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -6,8 +6,8 @@ 0 0 - 240 - 431 + 262 + 486 @@ -222,6 +222,13 @@ + + + + -> <font color=red>??</font> + + + diff --git a/PINCE.py b/PINCE.py index ab8e1996..7cda69be 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1789,6 +1789,8 @@ def __init__(self, parent, description=tr.NO_DESCRIPTION, address="0x", value_ty guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) self.lineEdit_Description.setText(description) self.offsetsList = [] + self.offsetDerefLabels = [] + self.offsetTextLabels = [] if not isinstance(address, typedefs.PointerChainRequest): self.lineEdit_Address.setText(address) self.widget_Pointer.hide() @@ -1870,11 +1872,16 @@ def addOffsetLayout(self, should_update=True): offsetLayout.addWidget(buttonRight) # TODO: Replace this spacer with address calculation per offset spacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding) + derefLabel = QLabel(offsetFrame) + derefLabel.setText("-> ??") + offsetLayout.addWidget(derefLabel) offsetLayout.addItem(spacer) buttonLeft.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opSub)) buttonRight.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opAdd)) self.offsetsList.append(offsetFrame) + self.offsetDerefLabels.append(derefLabel) + self.offsetTextLabels.append(offsetText) self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) if should_update: self.update_value() @@ -1886,8 +1893,26 @@ def removeOffsetLayout(self): frame.deleteLater() self.verticalLayout_Pointers.removeWidget(frame) del self.offsetsList[-1] + del self.offsetDerefLabels[-1] + del self.offsetTextLabels[-1] self.update_value() + def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult): + if pointer_chain_result != None: + self.label_BaseAddressDeref.setText(f"-> {hex(pointer_chain_result.pointer_chain[0])}") + for index, derefLabel in enumerate(self.offsetDerefLabels): + previousDeref = hex(pointer_chain_result.pointer_chain[index]) + currentDeref = hex(pointer_chain_result.pointer_chain[index+1]) + offsetText = self.offsetTextLabels[index].text() + if index != len(self.offsetDerefLabels) - 1: + derefLabel.setText(f"[{previousDeref}+{offsetText}] -> {currentDeref}") + else: + derefLabel.setText(f"{previousDeref}+{offsetText} = {currentDeref}") + else: + self.label_BaseAddressDeref.setText(f"-> ??") + for derefLabel in self.offsetDerefLabels: + derefLabel.setText(f"-> ??") + def update_value(self): if self.checkBox_IsPointer.isChecked(): pointer_chain_req = typedefs.PointerChainRequest(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) @@ -1899,6 +1924,7 @@ def update_value(self): else: address_text = "??" self.lineEdit_Address.setText(address_text) + self.update_deref_labels(pointer_chain_result) else: address = debugcore.examine_expression(self.lineEdit_Address.text()).address if self.checkBox_Hex.isChecked(): From a0eea0a556bccf2d1831e96a8601e6e394dce2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 9 Apr 2024 10:37:29 +0100 Subject: [PATCH 380/487] Fix PointerChainType typo --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 7cda69be..d4121f92 100755 --- a/PINCE.py +++ b/PINCE.py @@ -850,7 +850,7 @@ def insert_records(self, records, parent_row, insert_index): # Deserialize the address_expr & value_type param if type(rec[1]) in [list, tuple]: - address_expr = typedefs.PointerChainType(*rec[1]) + address_expr = typedefs.PointerChainRequest(*rec[1]) else: address_expr = rec[1] value_type = typedefs.ValueType(*rec[2]) From d4fa050b49f442c23c44516694d8ca3820937b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 9 Apr 2024 21:34:35 +0100 Subject: [PATCH 381/487] Change read_pointer_chain to add 0 for invalid offset reads --- PINCE.py | 18 ++++++++++++++---- libpince/debugcore.py | 12 +++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index d4121f92..a95a0c23 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1901,13 +1901,23 @@ def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult) if pointer_chain_result != None: self.label_BaseAddressDeref.setText(f"-> {hex(pointer_chain_result.pointer_chain[0])}") for index, derefLabel in enumerate(self.offsetDerefLabels): - previousDeref = hex(pointer_chain_result.pointer_chain[index]) - currentDeref = hex(pointer_chain_result.pointer_chain[index+1]) + previousDerefValue = pointer_chain_result.pointer_chain[index] + if previousDerefValue == 0: + previousDerefText = "??" + else: + previousDerefText = hex(previousDerefValue) + + currentDerefValue = pointer_chain_result.pointer_chain[index+1] + if currentDerefValue == 0: + currentDerefText = "??" + else: + currentDerefText = hex(currentDerefValue) + offsetText = self.offsetTextLabels[index].text() if index != len(self.offsetDerefLabels) - 1: - derefLabel.setText(f"[{previousDeref}+{offsetText}] -> {currentDeref}") + derefLabel.setText(f"[{previousDerefText}+{offsetText}] -> {currentDerefText}") else: - derefLabel.setText(f"{previousDeref}+{offsetText} = {currentDeref}") + derefLabel.setText(f"{previousDerefText}+{offsetText} = {currentDerefText}") else: self.label_BaseAddressDeref.setText(f"-> ??") for derefLabel in self.offsetDerefLabels: diff --git a/libpince/debugcore.py b/libpince/debugcore.py index d14a3647..7f1a8e0a 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -765,7 +765,7 @@ def read_pointer_chain(pointer_request: typedefs.PointerChainRequest) -> typedef Returns: typedefs.PointerChainResult: Class containing every pointer dereference result while walking the chain - None: If an error occurs while reading the given pointer + None: If an error occurs while reading the given pointer chain """ if not isinstance(pointer_request, typedefs.PointerChainRequest): raise TypeError("Passed non-PointerChainRequest type to read_pointer_chain!") @@ -786,16 +786,22 @@ def read_pointer_chain(pointer_request: typedefs.PointerChainRequest) -> typedef with memory_handle() as mem_handle: # Dereference the first address which is the base or (base + offset) deref_address = read_memory(start_address, value_index, mem_handle=mem_handle) - if deref_address is None: # deref would be None if read an invalid address region + if deref_address is None: + # Simply return None because no point reading further if base is not valid return None pointer_results.pointer_chain.append(deref_address) for index, offset in enumerate(pointer_request.offsets_list): + # If deref_address is 0, we found an invalid read in the chain + # so we can just keep adding 0 until the end of offsets list + if deref_address == 0: + pointer_results.pointer_chain.append(0) + continue offset_address = deref_address + offset if index != len(pointer_request.offsets_list) - 1: # CE derefs every offset except for the last one deref_address = read_memory(offset_address, value_index, mem_handle=mem_handle) if deref_address is None: - return None + deref_address = 0 else: deref_address = offset_address pointer_results.pointer_chain.append(deref_address) From 18328de4af7eb233fe65a5bcd7b175f1b0d21109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 12 Apr 2024 17:22:41 +0300 Subject: [PATCH 382/487] Fixed lineEdit alignment for AddAddressManuallyDialog --- GUI/AddAddressManuallyDialog.py | 4 +++- GUI/AddAddressManuallyDialog.ui | 13 +++++++++++++ PINCE.py | 17 +++++++++-------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 130c87e4..afa18139 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt6 UI code generator 6.6.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -153,6 +153,8 @@ def setupUi(self, Dialog): self.label_Value.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_Value.setObjectName("label_Value") self.horizontalLayout.addWidget(self.label_Value) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem6) self.verticalLayout_2.addLayout(self.horizontalLayout) self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1) self.checkBox_IsPointer = QtWidgets.QCheckBox(parent=Dialog) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 0f16e55d..6eb00dcb 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -358,6 +358,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + diff --git a/PINCE.py b/PINCE.py index a95a0c23..64bc5610 100755 --- a/PINCE.py +++ b/PINCE.py @@ -32,15 +32,13 @@ from tr.tr import language_list, get_locale from PyQt6.QtGui import QIcon, QMovie, QPixmap, QCursor, QKeySequence, QColor, QTextCharFormat, QBrush, QTextCursor, \ - QShortcut, QColorConstants, QStandardItemModel, QStandardItem, QCloseEvent, \ - QKeyEvent + QShortcut, QColorConstants, QStandardItemModel, QStandardItem, QCloseEvent, QKeyEvent from PyQt6.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QMessageBox, QDialog, QWidget, QTabWidget, \ QMenu, QFileDialog, QAbstractItemView, QTreeWidgetItem, QTreeWidgetItemIterator, QCompleter, QLabel, QLineEdit, \ QComboBox, QDialogButtonBox, QCheckBox, QHBoxLayout, QPushButton, QFrame, QSpacerItem, QSizePolicy from PyQt6.QtCore import Qt, QThread, pyqtSignal, QSize, QByteArray, QSettings, QEvent, QKeyCombination, QTranslator, \ QItemSelectionModel, QTimer, QStringListModel, QRunnable, QObject, QThreadPool, \ QLocale, QSignalBlocker, QItemSelection -from typing import Final from time import sleep, time import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect, json, select @@ -1783,6 +1781,8 @@ class ManualAddressDialogForm(QDialog, ManualAddressDialog): def __init__(self, parent, description=tr.NO_DESCRIPTION, address="0x", value_type=None): super().__init__(parent) self.setupUi(self) + self.lineEdit_PtrStartAddress.setFixedWidth(180) + self.lineEdit_Address.setFixedWidth(180) vt = typedefs.ValueType() if not value_type else value_type self.lineEdit_Length.setValidator(QHexValidator(99, self)) guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) @@ -1865,12 +1865,12 @@ def addOffsetLayout(self, should_update=True): offsetLayout.addWidget(buttonLeft) offsetText = QLineEdit(offsetFrame) offsetText.setText(hex(0)) + offsetText.setFixedWidth(80) offsetText.textChanged.connect(self.update_value) offsetLayout.addWidget(offsetText) buttonRight = QPushButton(">", offsetFrame) buttonRight.setFixedWidth(40) offsetLayout.addWidget(buttonRight) - # TODO: Replace this spacer with address calculation per offset spacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding) derefLabel = QLabel(offsetFrame) derefLabel.setText("-> ??") @@ -1899,21 +1899,22 @@ def removeOffsetLayout(self): def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult): if pointer_chain_result != None: - self.label_BaseAddressDeref.setText(f"-> {hex(pointer_chain_result.pointer_chain[0])}") + base_deref = hex(pointer_chain_result.pointer_chain[0]).upper().replace("X","x") + self.label_BaseAddressDeref.setText(f"-> {base_deref}") for index, derefLabel in enumerate(self.offsetDerefLabels): previousDerefValue = pointer_chain_result.pointer_chain[index] if previousDerefValue == 0: previousDerefText = "??" else: - previousDerefText = hex(previousDerefValue) + previousDerefText = hex(previousDerefValue).upper().replace("X","x") currentDerefValue = pointer_chain_result.pointer_chain[index+1] if currentDerefValue == 0: currentDerefText = "??" else: - currentDerefText = hex(currentDerefValue) + currentDerefText = hex(currentDerefValue).upper().replace("X","x") - offsetText = self.offsetTextLabels[index].text() + offsetText = self.offsetTextLabels[index].text().upper().replace("X","x") if index != len(self.offsetDerefLabels) - 1: derefLabel.setText(f"[{previousDerefText}+{offsetText}] -> {currentDerefText}") else: From 5f398fff0700d2f1386d12469fde1661d5837f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Sat, 13 Apr 2024 17:43:26 +0100 Subject: [PATCH 383/487] Add check for invalid base_address pointer chain in update table logic --- PINCE.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 64bc5610..fecff58b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -978,10 +978,12 @@ def update_address_table(self): old_base = pointer_chain_req.base_address # save the old base pointer_chain_req.base_address = address pointer_chain_result = debugcore.read_pointer_chain(pointer_chain_req) - address = pointer_chain_result.get_final_address() + if pointer_chain_result and pointer_chain_result.get_final_address(): + address = pointer_chain_result.get_final_address_as_hex() + else: + address = None address_data.base_address = old_base # then set it back if address: - address = hex(address) row.setText(ADDR_COL, f'P->{address}') else: row.setText(ADDR_COL, 'P->??') From 127785d02e269adae125230b636fd883167752f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 13 Apr 2024 20:38:43 +0300 Subject: [PATCH 384/487] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6a70a4ce..3286152d 100644 --- a/README.md +++ b/README.md @@ -83,12 +83,13 @@ Want to help? Check out [CONTRIBUTING.md](CONTRIBUTING.md) GPLv3+. See [COPYING](COPYING) file for details # Supported platforms -- Ubuntu and its flavors, actively tested on Kubuntu -- Debian and Debian-based (Kali, Mint etc.) +PINCE should technically run on any distro that comes with **Python 3.10+** and **PyQt 6.6+** installed or available in the package manager, but below is the list of distros that we officially support, as in we actively test on these and help with issues: +- Ubuntu 22.04+ +- Debian 12+ (or Testing) - Archlinux -- SUSE -- Fedora +- Fedora 35+ +Should your distro not be officially supported, the installer can still try to install it for you by picking one of the base package managers appropriate for your distro but please **do not open** an issue if it does not work for you # Trusted Sources * [Official github page](https://github.com/korcankaraokcu/PINCE) * [AUR package for Archlinux](https://aur.archlinux.org/packages/pince-git/) From 136713ec8c2142e31866c0e8468d72cbeacb47e0 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 13 Apr 2024 18:49:41 +0100 Subject: [PATCH 385/487] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3286152d..1eae0494 100644 --- a/README.md +++ b/README.md @@ -82,14 +82,17 @@ Want to help? Check out [CONTRIBUTING.md](CONTRIBUTING.md) # License GPLv3+. See [COPYING](COPYING) file for details -# Supported platforms +# Officially supported platforms PINCE should technically run on any distro that comes with **Python 3.10+** and **PyQt 6.6+** installed or available in the package manager, but below is the list of distros that we officially support, as in we actively test on these and help with issues: - Ubuntu 22.04+ - Debian 12+ (or Testing) - Archlinux - Fedora 35+ -Should your distro not be officially supported, the installer can still try to install it for you by picking one of the base package managers appropriate for your distro but please **do not open** an issue if it does not work for you +Should your distro not be officially supported, the installer can still try to install it for you by picking one of the base package managers appropriate for your distro but please **do not open an issue on GitHub** if it does not work for you. + +If this happens and you can't figure out why, we might be able to guide you into making PINCE run in our Discord server, under the #issues channel, but remember that we only actively test the installer and PINCE on the distros listed above. + # Trusted Sources * [Official github page](https://github.com/korcankaraokcu/PINCE) * [AUR package for Archlinux](https://aur.archlinux.org/packages/pince-git/) From 2b724b18278395ee344fdf41c8b789cc76bac328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 16 Apr 2024 21:01:06 +0100 Subject: [PATCH 386/487] Fix Python 3.12 SyntaxWarning by changing strings using invalid escape characters to raw strings --- GUI/Utils/guiutils.py | 4 ++-- PINCE.py | 2 +- libpince/debugcore.py | 2 +- libpince/regexes.py | 2 +- tr/tr.py | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index 4debbda2..f56cb12f 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -119,7 +119,7 @@ def fill_endianness_combobox(combobox: QComboBox, current_index: int = typedefs. #:tag:GUI def get_current_row(tablewidget: QTableWidget): - """Returns the currently selected row index for the given QTableWidget + r"""Returns the currently selected row index for the given QTableWidget If you try to use only selectionModel().currentIndex().row() for this purpose, you'll get the last selected row even if it was unselected afterwards. This is why this function exists, it checks the selection state before returning the selected row @@ -145,7 +145,7 @@ def get_current_row(tablewidget: QTableWidget): #:tag:GUI def get_current_item(tablewidget: QTableWidget): - """Returns the currently selected item for the given QTableWidget + r"""Returns the currently selected item for the given QTableWidget If you try to use only selectionModel().currentItem() for this purpose, you'll get the last selected item even if it was unselected afterwards. This is why this function exists, it checks the selection state before returning the selected item. Unlike get_current_row, this function can be used with QTreeWidget diff --git a/PINCE.py b/PINCE.py index fecff58b..daa59e65 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2338,7 +2338,7 @@ def __init__(self, parent, set_default_settings_func): self.comboBox_InterruptSignal.setStyleSheet("combobox-popup: 0;") # maxVisibleItems doesn't work otherwise self.comboBox_Theme.addItems(theme_list) logo_directory = utils.get_logo_directory() - logo_list = utils.search_files(logo_directory, "\.(png|jpg|jpeg|svg)$") + logo_list = utils.search_files(logo_directory, r"\.(png|jpg|jpeg|svg)$") for logo in logo_list: self.comboBox_Logo.addItem(QIcon(os.path.join(logo_directory, logo)), logo) for hotkey in hotkeys.get_hotkeys(): diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 7f1a8e0a..24af8db1 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1430,7 +1430,7 @@ def get_breakpoint_info() -> list[typedefs.tuple_breakpoint_info]: raw_info = send_command("-break-list") # Temporary fix for https://sourceware.org/bugzilla/show_bug.cgi?id=9659 # TODO:Delete this line when gdb or pygdbmi fixes the problem - raw_info = re.sub("script={(.*?)}", "script=[\g<1>]", raw_info) # Please refer to issue #53 + raw_info = re.sub(r"script={(.*?)}", r"script=[\g<1>]", raw_info) # Please refer to issue #53 for item in utils.parse_response(raw_info)['payload']['BreakpointTable']['body']: item = defaultdict(lambda: "", item) number, breakpoint_type, disp, enabled, address, what, condition, hit_count, enable_count = \ diff --git a/libpince/regexes.py b/libpince/regexes.py index 076ed5f3..de63ec52 100644 --- a/libpince/regexes.py +++ b/libpince/regexes.py @@ -81,7 +81,7 @@ return_address = compile(r"saved.*=\s+" + hex_number_grouped.pattern) # saved rip = 0x7f633a853fe4 trace_instructions_ret = compile(r":\s+ret") # 0x7f71a4dc5ff8 : ret trace_instructions_call = compile(r":\s+call") # 0x7f71a4dc5fe4 : call 0x7f71a4de1100 -dissect_code_valid_address = compile(r"(\s+|\[|,)" + hex_number.pattern + "(\s+|\]|,|$)") +dissect_code_valid_address = compile(r"(\s+|\[|,)" + hex_number.pattern + r"(\s+|\]|,|$)") alphanumerics = compile(r"\w+") file_with_extension = compile(r".+?\.\w+") offset_expression = compile(r"[/*+\-][0-9a-fA-FxX/*+\-\[\]]+$") diff --git a/tr/tr.py b/tr/tr.py index 3f338a00..87058f32 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -137,7 +137,7 @@ def translate(): AUTO_ATTACH_TOOLTIP = QT_TR_NOOP("asdf|qwer --> search for asdf or qwer\n" "[as]df --> search for both adf and sdf\n" "Use the char \\ to escape special chars such as [\n" - "\[asdf\] --> search for opcodes that contain [asdf]") + r"\[asdf\] --> search for opcodes that contain [asdf]") SEPARATE_PROCESSES_WITH = QT_TR_NOOP("Separate processes with {}") SELECT_GDB_BINARY = QT_TR_NOOP("Select the gdb binary") QUIT_SESSION_CRASH = QT_TR_NOOP("Quitting current session will crash PINCE") @@ -316,7 +316,7 @@ def translate(): "call|rax --> search for opcodes that contain call or rax\n" "[re]cx --> search for both rcx and ecx\n" "Use the char \\ to escape special chars such as [\n" - "\[rsp\] --> search for opcodes that contain [rsp]") + r"\[rsp\] --> search for opcodes that contain [rsp]") COPY_ADDRESSES = QT_TR_NOOP("Copy Addresses") COPY_OFFSET = QT_TR_NOOP("Copy Offset") COPY_PATH = QT_TR_NOOP("Copy Path") @@ -350,4 +350,4 @@ def translate(): LITTLE = QT_TR_NOOP("Little") BIG = QT_TR_NOOP("Big") SHOW_HEXVIEW = QT_TR_NOOP("Show in HexView") - SHOW_DISASSEMBLER = QT_TR_NOOP("Show in Disassembler") \ No newline at end of file + SHOW_DISASSEMBLER = QT_TR_NOOP("Show in Disassembler") From 0152fe822fb55a38c8f6a3db872f71249ef39bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 16 Apr 2024 21:36:37 +0100 Subject: [PATCH 387/487] Fix rare SIGSEGV from invalid sys.argv --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index daa59e65..4a9cec65 100755 --- a/PINCE.py +++ b/PINCE.py @@ -95,7 +95,7 @@ from keyboard._nixkeyboard import to_name if __name__ == '__main__': - app = QApplication(sys.argv) + app = QApplication([]) app.setOrganizationName("PINCE") app.setOrganizationDomain("github.com/korcankaraokcu/PINCE") app.setApplicationName("PINCE") From 766bb39059214978c0d36df0f2c36b3e02641c26 Mon Sep 17 00:00:00 2001 From: bloodiko Date: Sun, 14 Apr 2024 14:49:48 +0200 Subject: [PATCH 388/487] improve ManualAddressDialog GUI --- GUI/AddAddressManuallyDialog.py | 8 +- GUI/AddAddressManuallyDialog.ui | 9 +++ .../PointerChainOffset.py | 62 +++++++++++++++ PINCE.py | 78 +++++++------------ 4 files changed, 106 insertions(+), 51 deletions(-) create mode 100644 GUI/ManualAddressDialogUtils/PointerChainOffset.py diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index afa18139..287ac2fe 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.6.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -94,6 +94,7 @@ def setupUi(self, Dialog): self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) self.label_BaseAddressDeref = QtWidgets.QLabel(parent=self.widget_Pointer) + self.label_BaseAddressDeref.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_BaseAddressDeref.setObjectName("label_BaseAddressDeref") self.horizontalLayout_4.addWidget(self.label_BaseAddressDeref) self.verticalLayout_Pointers.addLayout(self.horizontalLayout_4) @@ -116,6 +117,11 @@ def setupUi(self, Dialog): self.label_4.setObjectName("label_4") self.verticalLayout.addWidget(self.label_4) self.lineEdit_Description = QtWidgets.QLineEdit(parent=Dialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_Description.sizePolicy().hasHeightForWidth()) + self.lineEdit_Description.setSizePolicy(sizePolicy) self.lineEdit_Description.setText("") self.lineEdit_Description.setObjectName("lineEdit_Description") self.verticalLayout.addWidget(self.lineEdit_Description) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 6eb00dcb..3debe1cd 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -227,6 +227,9 @@ -> <font color=red>??</font> + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -278,6 +281,12 @@ + + + 0 + 0 + + diff --git a/GUI/ManualAddressDialogUtils/PointerChainOffset.py b/GUI/ManualAddressDialogUtils/PointerChainOffset.py new file mode 100644 index 00000000..0c15be65 --- /dev/null +++ b/GUI/ManualAddressDialogUtils/PointerChainOffset.py @@ -0,0 +1,62 @@ +from PyQt6.QtWidgets import QWidget, QFrame, QLabel, QLineEdit, QPushButton, QHBoxLayout, QSizePolicy, QSpacerItem +from PyQt6.QtCore import Qt, pyqtSignal +from operator import add as opAdd, sub as opSub + +from GUI.Utils import guiutils + + +# Only intended to be used by ManualAddressForm +class PointerChainOffset(QFrame): + offset_changed_signal = pyqtSignal(name="offsetChanged") + + def __init__(self, offset_index:int, parent:QWidget|None=None): + super().__init__(parent) + self.offset_index = offset_index + self.initUI() + + def initUI(self): + offsetLayout = QHBoxLayout(self) + offsetLayout.setContentsMargins(0, 3, 0, 3) + self.setLayout(offsetLayout) + buttonLeft = QPushButton("<", self) + buttonLeft.setFixedWidth(20) + offsetLayout.addWidget(buttonLeft) + self.offsetText = QLineEdit(self) + self.offsetText.setValidator(guiutils.validator_map["int_hex"]) + self.offsetText.setText(hex(0)) + self.offsetText.setFixedWidth(70) + self.offsetText.textChanged.connect(self.offset_changed) + offsetLayout.addWidget(self.offsetText) + buttonRight = QPushButton(">", self) + buttonRight.setFixedWidth(20) + offsetLayout.addWidget(buttonRight) + spacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding) + self.derefLabel = QLabel(self) + self.derefLabel.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + self.derefLabel.setText(" -> ??") + offsetLayout.addWidget(self.derefLabel) + offsetLayout.addItem(spacer) + buttonLeft.clicked.connect(lambda: self.on_offset_arrow_clicked(self.offsetText, opSub)) + buttonRight.clicked.connect(lambda: self.on_offset_arrow_clicked(self.offsetText, opAdd)) + + def get_offset_as_int(self): + return int(self.offsetText.text(), 16) + + def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): + offsetText = offsetTextWidget.text() + try: + offsetValue = int(offsetText, 16) + except ValueError: + offsetValue = 0 + # first parent is the widget_pointer, second parent is the ManualAddressDialog + sizeVal = self.parent().parent().get_type_size() if hasattr(self.parent().parent(), "get_type_size") else 1 + offsetValue = operator_func(offsetValue, sizeVal) + offsetTextWidget.setText(hex(offsetValue)) + + def offset_changed(self): + self.offset_changed_signal.emit() + + def update_deref_label(self, text:str): + self.derefLabel.setText(text) + + \ No newline at end of file diff --git a/PINCE.py b/PINCE.py index 4a9cec65..e90f62b5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -88,6 +88,7 @@ from GUI.AbstractTableModels.HexModel import QHexModel from GUI.AbstractTableModels.AsciiModel import QAsciiModel from GUI.Validators.HexValidator import QHexValidator +from GUI.ManualAddressDialogUtils.PointerChainOffset import PointerChainOffset from operator import add as opAdd, sub as opSub @@ -1790,9 +1791,8 @@ def __init__(self, parent, description=tr.NO_DESCRIPTION, address="0x", value_ty guiutils.fill_value_combobox(self.comboBox_ValueType, vt.value_index) guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) self.lineEdit_Description.setText(description) - self.offsetsList = [] - self.offsetDerefLabels = [] - self.offsetTextLabels = [] + self.lineEdit_Description.setFixedWidth(180) + self.offsetsList:list[PointerChainOffset] = [] if not isinstance(address, typedefs.PointerChainRequest): self.lineEdit_Address.setText(address) self.widget_Pointer.hide() @@ -1858,33 +1858,10 @@ def label_Value_context_menu_event(self, event): pass def addOffsetLayout(self, should_update=True): - offsetFrame = QFrame(self.widget_Pointer) - offsetLayout = QHBoxLayout(offsetFrame) - offsetLayout.setContentsMargins(0, 3, 0, 3) - offsetFrame.setLayout(offsetLayout) - buttonLeft = QPushButton("<", offsetFrame) - buttonLeft.setFixedWidth(40) - offsetLayout.addWidget(buttonLeft) - offsetText = QLineEdit(offsetFrame) - offsetText.setText(hex(0)) - offsetText.setFixedWidth(80) - offsetText.textChanged.connect(self.update_value) - offsetLayout.addWidget(offsetText) - buttonRight = QPushButton(">", offsetFrame) - buttonRight.setFixedWidth(40) - offsetLayout.addWidget(buttonRight) - spacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding) - derefLabel = QLabel(offsetFrame) - derefLabel.setText("-> ??") - offsetLayout.addWidget(derefLabel) - offsetLayout.addItem(spacer) - buttonLeft.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opSub)) - buttonRight.clicked.connect(lambda: self.on_offset_arrow_clicked(offsetText, opAdd)) - + offsetFrame = PointerChainOffset(len(self.offsetsList), self.widget_Pointer) self.offsetsList.append(offsetFrame) - self.offsetDerefLabels.append(derefLabel) - self.offsetTextLabels.append(offsetText) self.verticalLayout_Pointers.insertWidget(0, self.offsetsList[-1]) + offsetFrame.offset_changed_signal.connect(self.update_value) if should_update: self.update_value() @@ -1895,36 +1872,34 @@ def removeOffsetLayout(self): frame.deleteLater() self.verticalLayout_Pointers.removeWidget(frame) del self.offsetsList[-1] - del self.offsetDerefLabels[-1] - del self.offsetTextLabels[-1] self.update_value() def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult): if pointer_chain_result != None: base_deref = hex(pointer_chain_result.pointer_chain[0]).upper().replace("X","x") - self.label_BaseAddressDeref.setText(f"-> {base_deref}") - for index, derefLabel in enumerate(self.offsetDerefLabels): - previousDerefValue = pointer_chain_result.pointer_chain[index] - if previousDerefValue == 0: - previousDerefText = "??" + self.label_BaseAddressDeref.setText(f" → {base_deref}") + for index, offsetFrame in enumerate(self.offsetsList): + previousDerefText = self.caps_hex_or_error_indicator(pointer_chain_result.pointer_chain[index]) + currentDerefText = self.caps_hex_or_error_indicator(pointer_chain_result.pointer_chain[index + 1]) + offsetText = self.caps_hex(offsetFrame.offsetText.text()) + operationalSign = "" if offsetText.startswith("-") else "+" + calculation = f"{previousDerefText}{operationalSign}{offsetText}" + if index != len(self.offsetsList) - 1: + offsetFrame.update_deref_label(f" [{calculation}] → {currentDerefText}") else: - previousDerefText = hex(previousDerefValue).upper().replace("X","x") + offsetFrame.update_deref_label(f" {calculation} = {currentDerefText}") + else: + self.label_BaseAddressDeref.setText(" → ??") + for offsetFrame in self.offsetsList: + offsetFrame.update_deref_label(" → ??") - currentDerefValue = pointer_chain_result.pointer_chain[index+1] - if currentDerefValue == 0: - currentDerefText = "??" - else: - currentDerefText = hex(currentDerefValue).upper().replace("X","x") + def caps_hex_or_error_indicator(self, hex_int:int): + if hex_int == 0: + return "??" + return self.caps_hex(hex(hex_int)) - offsetText = self.offsetTextLabels[index].text().upper().replace("X","x") - if index != len(self.offsetDerefLabels) - 1: - derefLabel.setText(f"[{previousDerefText}+{offsetText}] -> {currentDerefText}") - else: - derefLabel.setText(f"{previousDerefText}+{offsetText} = {currentDerefText}") - else: - self.label_BaseAddressDeref.setText(f"-> ??") - for derefLabel in self.offsetDerefLabels: - derefLabel.setText(f"-> ??") + def caps_hex(self, hex_str:str): + return hex_str.upper().replace("X","x") def update_value(self): if self.checkBox_IsPointer.isChecked(): @@ -2057,6 +2032,9 @@ def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): offsetValue = operator_func(offsetValue, sizeVal) offsetTextWidget.setText(hex(offsetValue)) + def get_type_size(self): + return typedefs.index_to_valuetype_dict[self.comboBox_ValueType.currentIndex()][0] + class EditTypeDialogForm(QDialog, EditTypeDialog): def __init__(self, parent, value_type=None): From 8d98a2d6a5b9b5eea22eb124f2e131fa2bb0b8ad Mon Sep 17 00:00:00 2001 From: Bastian Ebiko Jesuiter Date: Sun, 14 Apr 2024 15:04:05 +0200 Subject: [PATCH 389/487] Update PINCE.py rename parameter to address --- PINCE.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index e90f62b5..ea21381b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1893,10 +1893,10 @@ def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult) for offsetFrame in self.offsetsList: offsetFrame.update_deref_label(" → ??") - def caps_hex_or_error_indicator(self, hex_int:int): - if hex_int == 0: + def caps_hex_or_error_indicator(self, address:int): + if address == 0: return "??" - return self.caps_hex(hex(hex_int)) + return self.caps_hex(hex(address)) def caps_hex(self, hex_str:str): return hex_str.upper().replace("X","x") From 423b2374f76a12510c750ebbde796a9706f3dc46 Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 14 Apr 2024 15:13:38 +0200 Subject: [PATCH 390/487] add space before typehints --- GUI/ManualAddressDialogUtils/PointerChainOffset.py | 4 ++-- PINCE.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/GUI/ManualAddressDialogUtils/PointerChainOffset.py b/GUI/ManualAddressDialogUtils/PointerChainOffset.py index 0c15be65..0f7c0a19 100644 --- a/GUI/ManualAddressDialogUtils/PointerChainOffset.py +++ b/GUI/ManualAddressDialogUtils/PointerChainOffset.py @@ -9,7 +9,7 @@ class PointerChainOffset(QFrame): offset_changed_signal = pyqtSignal(name="offsetChanged") - def __init__(self, offset_index:int, parent:QWidget|None=None): + def __init__(self, offset_index:int, parent: QWidget|None=None): super().__init__(parent) self.offset_index = offset_index self.initUI() @@ -56,7 +56,7 @@ def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): def offset_changed(self): self.offset_changed_signal.emit() - def update_deref_label(self, text:str): + def update_deref_label(self, text: str): self.derefLabel.setText(text) \ No newline at end of file diff --git a/PINCE.py b/PINCE.py index ea21381b..f7a9cbeb 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1792,7 +1792,7 @@ def __init__(self, parent, description=tr.NO_DESCRIPTION, address="0x", value_ty guiutils.fill_endianness_combobox(self.comboBox_Endianness, vt.endian) self.lineEdit_Description.setText(description) self.lineEdit_Description.setFixedWidth(180) - self.offsetsList:list[PointerChainOffset] = [] + self.offsetsList: list[PointerChainOffset] = [] if not isinstance(address, typedefs.PointerChainRequest): self.lineEdit_Address.setText(address) self.widget_Pointer.hide() @@ -1893,12 +1893,12 @@ def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult) for offsetFrame in self.offsetsList: offsetFrame.update_deref_label(" → ??") - def caps_hex_or_error_indicator(self, address:int): + def caps_hex_or_error_indicator(self, address: int): if address == 0: return "??" return self.caps_hex(hex(address)) - def caps_hex(self, hex_str:str): + def caps_hex(self, hex_str: str): return hex_str.upper().replace("X","x") def update_value(self): From f49c48f7c9b654539d33f771a5bf31859b713f5f Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 21 Apr 2024 10:05:00 +0200 Subject: [PATCH 391/487] Adjust int_hex regex to include possible leading - fix search_for and search_for2 in validate_search to reflect regex changes for possible leading - further change spacing on typehints based on review feedback --- GUI/ManualAddressDialogUtils/PointerChainOffset.py | 2 +- PINCE.py | 13 ++++++++----- libpince/regexes.py | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/GUI/ManualAddressDialogUtils/PointerChainOffset.py b/GUI/ManualAddressDialogUtils/PointerChainOffset.py index 0f7c0a19..92c54444 100644 --- a/GUI/ManualAddressDialogUtils/PointerChainOffset.py +++ b/GUI/ManualAddressDialogUtils/PointerChainOffset.py @@ -9,7 +9,7 @@ class PointerChainOffset(QFrame): offset_changed_signal = pyqtSignal(name="offsetChanged") - def __init__(self, offset_index:int, parent: QWidget|None=None): + def __init__(self, offset_index: int, parent: QWidget|None = None): super().__init__(parent) self.offset_index = offset_index self.initUI() diff --git a/PINCE.py b/PINCE.py index f7a9cbeb..ee5e92db 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1169,7 +1169,7 @@ def comboBox_ValueType_init(self): # :doc: # adds things like 0x when searching for etc, basically just makes the line valid for scanmem # this should cover most things, more things might be added later if need be - def validate_search(self, search_for, search_for2): + def validate_search(self, search_for: str, search_for2: str): type_index = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) symbol_map = { typedefs.SCAN_TYPE.INCREASED: "+", @@ -1194,10 +1194,13 @@ def validate_search(self, search_for, search_for2): elif scan_index == typedefs.SCAN_INDEX.STRING: search_for = "\" " + search_for elif self.checkBox_Hex.isChecked(): - if not search_for.startswith("0x"): - search_for = "0x" + search_for - if not search_for2.startswith("0x"): - search_for2 = "0x" + search_for2 + if not search_for.startswith(("0x", "-0x")): + negative_str = "-" if search_for.startswith("-") else "" + search_for = negative_str + "0x" + search_for.lstrip("-") + if not search_for2.startswith(("0x", "-0x")): + negative_str = "-" if search_for.startswith("-") else "" + search_for2 = negative_str + "0x" + search_for2.lstrip("-") + if type_index == typedefs.SCAN_TYPE.BETWEEN: return search_for + ".." + search_for2 cmp_symbols = { diff --git a/libpince/regexes.py b/libpince/regexes.py index de63ec52..c1758e10 100644 --- a/libpince/regexes.py +++ b/libpince/regexes.py @@ -72,7 +72,7 @@ float_number = compile(r"-?[0-9]+[.,]?[0-9]*") bytearray_input = compile(r"^(([A-Fa-f0-9?]{2} +)+)$") decimal_number = compile(r"-?\d+") -hex_number_gui = compile(r"(0x)?[0-9a-fA-F]*") # contains optional 0x prefix +hex_number_gui = compile(r"-?(0x)?[0-9a-fA-F]*") # contains optional 0x prefix # --------------------------------------------gdbextensions------------------------------------------------------ From 5d686bba2ecd2e80f35911f57e122ffaa03ff4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Mon, 22 Apr 2024 18:55:00 +0100 Subject: [PATCH 392/487] Change gdbinit's shell invocation to use python3 --- libpince/gdbinit_venv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libpince/gdbinit_venv b/libpince/gdbinit_venv index fb2701f7..c19bc2ad 100644 --- a/libpince/gdbinit_venv +++ b/libpince/gdbinit_venv @@ -7,7 +7,7 @@ python import os,subprocess,sys # Execute a Python using the user's shell and pull out the sys.path (for site-packages) -paths = subprocess.check_output('python -c "import os,sys;print(os.linesep.join(sys.path).strip())"',shell=True).decode("utf-8").split() +paths = subprocess.check_output('python3 -c "import os,sys;print(os.linesep.join(sys.path).strip())"',shell=True).decode("utf-8").split() # Extend GDB's Python's search path sys.path.extend(paths) From 2e05b5de1a82ef7acfb6f0992964e70af6774ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 23 Apr 2024 21:35:56 +0100 Subject: [PATCH 393/487] Prepare gdb init code for AppImage gdb bundling --- PINCE.py | 10 ++++++++-- libpince/debugcore.py | 6 +++--- libpince/typedefs.py | 2 +- libpince/utils.py | 7 +++++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/PINCE.py b/PINCE.py index ee5e92db..6b1cf154 100755 --- a/PINCE.py +++ b/PINCE.py @@ -397,7 +397,10 @@ def __init__(self): self.settings.clear() self.set_default_settings() try: - debugcore.init_gdb(settings.gdb_path) + gdb_path = settings.gdb_path + if os.environ.get("APPDIR"): + gdb_path = utils.get_default_gdb_path() + debugcore.init_gdb(gdb_path) except pexpect.EOF: InputDialogForm(self, [(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() else: @@ -1439,12 +1442,15 @@ def on_inferior_exit(self): self.lineEdit_Scan.setText("") self.reset_scan() self.on_status_running() - debugcore.init_gdb(settings.gdb_path) self.apply_after_init() self.flashAttachButton = True self.flashAttachButtonTimer.start(100) self.label_SelectedProcess.setText(tr.NO_PROCESS_SELECTED) self.memory_view_window.setWindowTitle(tr.NO_PROCESS_SELECTED) + gdb_path = settings.gdb_path + if os.environ.get("APPDIR"): + gdb_path = utils.get_default_gdb_path() + debugcore.init_gdb(gdb_path) def on_status_detached(self): self.label_SelectedProcess.setStyleSheet("color: blue") diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 24af8db1..cf9ee7ff 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -483,7 +483,7 @@ def handle_signals(signal_list): #:tag:GDBCommunication -def init_gdb(gdb_path=typedefs.PATHS.GDB): +def init_gdb(gdb_path=utils.get_default_gdb_path()): """Spawns gdb and initializes/resets some of the global variables Args: @@ -569,7 +569,7 @@ def init_referenced_dicts(pid): #:tag:Debug -def attach(pid, gdb_path=typedefs.PATHS.GDB): +def attach(pid, gdb_path=utils.get_default_gdb_path()): """Attaches gdb to the target and initializes some of the global variables Args: @@ -613,7 +613,7 @@ def attach(pid, gdb_path=typedefs.PATHS.GDB): #:tag:Debug -def create_process(process_path, args="", ld_preload_path="", gdb_path=typedefs.PATHS.GDB): +def create_process(process_path, args="", ld_preload_path="", gdb_path=utils.get_default_gdb_path()): """Creates a new process for debugging and initializes some of the global variables Current process will be detached even if the create_process call fails Make sure to save your data before calling this monstrosity diff --git a/libpince/typedefs.py b/libpince/typedefs.py index cc1ac057..e8087779 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -25,7 +25,7 @@ class CONST_TIME: class PATHS: - GDB = "/bin/gdb" + GDB = "/bin/gdb" # Use utils.get_default_gdb_path() TMP = "/tmp/PINCE/" # Use utils.get_tmp_path() IPC = "/dev/shm/PINCE_IPC/" # Use utils.get_ipc_path() FROM_PINCE = "/from_PINCE" # Use utils.get_from_pince_file() diff --git a/libpince/utils.py b/libpince/utils.py index 3ce9ad2f..fe7d5683 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -1102,6 +1102,13 @@ def get_user_path(user_path): return os.path.join(homedir, user_path) +def get_default_gdb_path(): + appdir = os.environ.get("APPDIR") + if appdir: + return appdir + "/usr/bin/gdb" + return typedefs.PATHS.GDB + + #:tag:Tools def execute_script(file_path): """Loads and executes the script in the given path From e472a760a8354dfb9f9bdb1a4c4a5912d92a722b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Tue, 23 Apr 2024 21:41:10 +0100 Subject: [PATCH 394/487] Fix missed apply_after_init in gdb init case --- PINCE.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PINCE.py b/PINCE.py index 6b1cf154..1b1aacbd 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1442,7 +1442,6 @@ def on_inferior_exit(self): self.lineEdit_Scan.setText("") self.reset_scan() self.on_status_running() - self.apply_after_init() self.flashAttachButton = True self.flashAttachButtonTimer.start(100) self.label_SelectedProcess.setText(tr.NO_PROCESS_SELECTED) @@ -1451,6 +1450,7 @@ def on_inferior_exit(self): if os.environ.get("APPDIR"): gdb_path = utils.get_default_gdb_path() debugcore.init_gdb(gdb_path) + self.apply_after_init() def on_status_detached(self): self.label_SelectedProcess.setStyleSheet("color: blue") From b6a68b3ff7a0c709814df7576b005a89ca51a850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Wed, 24 Apr 2024 00:14:49 +0100 Subject: [PATCH 395/487] Additional AppImage checks necessary to run --- libpince/debugcore.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index cf9ee7ff..89aeb97e 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -513,8 +513,12 @@ def init_gdb(gdb_path=utils.get_default_gdb_path()): last_gdb_command = "" libpince_dir = utils.get_libpince_directory() - child = pexpect.spawn(f'sudo -E --preserve-env=PATH LC_NUMERIC=C {gdb_path} --nx --interpreter=mi', - cwd=libpince_dir, encoding="utf-8") + is_appimage = os.environ.get('APPDIR') + python_home_env = f"PYTHONHOME={os.environ.get('PYTHONHOME')}" if is_appimage else "" + child = pexpect.spawn(f'sudo -E --preserve-env=PATH LC_NUMERIC=C {python_home_env} {gdb_path} --nx --interpreter=mi', + cwd=libpince_dir, + env=os.environ, + encoding="utf-8") child.setecho(False) child.delaybeforesend = 0 child.timeout = None @@ -524,7 +528,8 @@ def init_gdb(gdb_path=utils.get_default_gdb_path()): status_thread.start() gdb_initialized = True set_logging(False) - send_command("source ./gdbinit_venv") + if not is_appimage: + send_command("source ./gdbinit_venv") set_pince_paths() send_command("source " + utils.get_user_path(typedefs.USER_PATHS.GDBINIT)) utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT)) From 63c103cabe4e92074c632cb0d719c0a4e52fedf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berk=20=C3=96zler?= Date: Thu, 25 Apr 2024 01:28:04 +0100 Subject: [PATCH 396/487] Add AppImage builder --- .gitignore | 1 + ci/package.sh | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100755 ci/package.sh diff --git a/.gitignore b/.gitignore index 775ef761..f7f79cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ libpince/libscanmem/* gdb_pince/* *.gnbs.conf .venv/* +*.AppImage diff --git a/ci/package.sh b/ci/package.sh new file mode 100755 index 00000000..a0796f32 --- /dev/null +++ b/ci/package.sh @@ -0,0 +1,143 @@ +#!/bin/bash +: ' +Copyright (C) 2024 brkzlr + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +' + +# Check if the file is in the correct directory and cd there +# This script should be only in PINCE/ci folder +PACKAGEDIR="$(dirname "$(readlink -f "$0")")" +case $PACKAGEDIR in + *"PINCE/ci") ;; + *) echo "package.sh is not in PINCE/ci folder!"; exit 1;; +esac +cd $PACKAGEDIR + +# Download necessary tools +wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +DEPLOYTOOL=./linuxdeploy-x86_64.AppImage +chmod +x $DEPLOYTOOL + +wget https://raw.githubusercontent.com/TheAssassin/linuxdeploy-plugin-conda/master/linuxdeploy-plugin-conda.sh +CONDAPLUGIN=./linuxdeploy-plugin-conda.sh +chmod +x $CONDAPLUGIN + +# Create cleanup function to remove remaining deps/files +cleanup () { + rm AppRun.sh + rm -rf ./AppDir + rm -rf ./_temp_home + rm $DEPLOYTOOL* + rm $CONDAPLUGIN* +} +trap cleanup EXIT + +# Create AppImage's AppDir with a Conda environment pre-baked +# containing our required pip packages +export PIP_REQUIREMENTS="-r ../requirements.txt" +$DEPLOYTOOL --appdir AppDir -pconda + +# Create PINCE directory +mkdir -p AppDir/opt/PINCE + +# Install libscanmem +NUM_MAKE_JOBS="$(nproc --ignore=1)" +cd .. +git submodule update --init --recursive +if [ ! -d "libpince/libscanmem" ]; then + mkdir libpince/libscanmem +fi +cd libscanmem-PINCE +sh autogen.sh +./configure --prefix="$(pwd)" +make -j"$NUM_MAKE_JOBS" +cp --preserve .libs/libscanmem.so ../libpince/libscanmem +cp --preserve wrappers/scanmem.py ../libpince/libscanmem +cd .. + +# Copy necessary PINCE folders/files to inside AppDir +cp -r GUI i18n libpince media tr AUTHORS COPYING COPYING.CC-BY PINCE.py THANKS ci/AppDir/opt/PINCE/ +cd ci + +# Create a wrapper so GDB can correctly link against the +# included conda's python environment to ensure compatibility +# Taken from: https://github.com/pwndbg/pwndbg/pull/892 +cat > wrapper.sh <<\EOF +#!/bin/bash +if [[ -z "$CONDA_PREFIX" ]]; then + echo "Error: CONDA_PREFIX not set" + exit 2 +fi +echo "$(date +%F) -- $@" >> /tmp/args.txt +if [[ $1 != *"python-config.py"* ]]; then + exec "$CONDA_PREFIX"/bin/python3 +fi +# get rid of the first parameter, which is the path to the python-config.py script +shift +# python3-config --ldflags lacks the python library +# also gdb won't link on GitHub actions without libtinfow, which is not provided by the conda environment +if [[ "$1" == "--ldflags" ]]; then + echo -n "-lpython3.12 -ltinfow " +fi +exec "$CONDA_PREFIX"/bin/python3-config "$@" +EOF +chmod +x wrapper.sh + +# Prepare some env vars for GDB compilation +INSTALLDIR=$(pwd)/AppDir +export CONDA_PREFIX="$(readlink -f $INSTALLDIR/usr/conda)" + +# Grab latest GDB at time of writing and compile it with our conda Python +wget "https://ftp.gnu.org/gnu/gdb/gdb-14.2.tar.gz" +tar xvf gdb-14.2.tar.gz +rm gdb-14.2.tar.gz +cd gdb-14.2 +./configure --with-python="$(readlink -f ../wrapper.sh)" --prefix=/usr +make -j"$NUM_MAKE_JOBS" +make install DESTDIR=$INSTALLDIR +cd .. +rm -rf gdb-14.2 +rm wrapper.sh + +# Create a fake but needed desktop file for AppImage +cat > AppDir/usr/share/applications/PINCE.desktop <<\EOF +[Desktop Entry] +Name=PINCE +Exec=PINCE +Icon=PINCE +Type=Application +Terminal=true +Categories=Development; +EOF + +# Placeholder icon for above desktop file +touch AppDir/usr/share/icons/hicolor/scalable/apps/PINCE.svg + +# Create main running script +cat > AppRun.sh <<\EOF +#!/bin/bash +if [ "$(id -u)" != "0" ]; then + echo "Please run this AppImage using 'sudo -E'!" + exit 1 +fi +export APPDIR="$(dirname "$0")" +export PYTHONHOME=$APPDIR/usr/conda +$APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py +EOF +chmod +x AppRun.sh + +# Package AppDir into AppImage +export LD_LIBRARY_PATH="$(readlink -f ./AppDir/usr/conda/lib)" +$DEPLOYTOOL --appdir AppDir/ --output appimage --custom-apprun AppRun.sh From 371165ac11663c06b665a8a49d9eb0a59bb32aac Mon Sep 17 00:00:00 2001 From: brkzlr Date: Thu, 25 Apr 2024 22:52:33 +0100 Subject: [PATCH 397/487] Update libscanmem commit hash --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index 321fa6b1..fadbda39 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit 321fa6b18246ebcb2ac19c997a4e85ce7e54b82b +Subproject commit fadbda39cc9766ccaa80e1bc8aed4876e7107c53 From 3da0f807a7eb36d0716a45eb8f40932b138f581f Mon Sep 17 00:00:00 2001 From: brkzlr Date: Fri, 26 Apr 2024 10:49:48 +0100 Subject: [PATCH 398/487] Fix locales not working in AppImage --- PINCE.py | 3 ++- ci/package.sh | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/PINCE.py b/PINCE.py index 1b1aacbd..381ab94c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -113,7 +113,8 @@ locale = None if not locale: locale = get_locale() - translator.load(f'i18n/qm/{locale}.qm') + locale_file = utils.get_script_directory() + f'/i18n/qm/{locale}.qm' + translator.load(locale_file) app.installTranslator(translator) tr.translate() hotkeys = Hotkeys() # Create the instance after translations to ensure hotkeys are translated diff --git a/ci/package.sh b/ci/package.sh index a0796f32..f5704724 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -1,6 +1,6 @@ #!/bin/bash : ' -Copyright (C) 2024 brkzlr +Copyright (C) 2024 brkzlr This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,6 +25,33 @@ case $PACKAGEDIR in esac cd $PACKAGEDIR +# Check what distro we use for lrelease path +LSB_RELEASE="$(command -v lsb_release)" +if [ -n "$LSB_RELEASE" ]; then + OS_NAME="$(${LSB_RELEASE} -d -s)" +else + # shellcheck disable=SC1091 + . /etc/os-release + OS_NAME="$NAME" +fi +case $OS_NAME in +*SUSE*) + LRELEASE_CMD="lrelease6" + ;; +*Arch*) + LRELEASE_CMD="/usr/lib/qt6/bin/lrelease" + ;; +*Fedora*) + LRELEASE_CMD="lrelease-qt6" + ;; +*Debian*|*Ubuntu*) + LRELEASE_CMD="/usr/lib/qt6/bin/lrelease" + ;; +*) + LRELEASE_CMD="$(which lrelease6)" # Placeholder + ;; +esac + # Download necessary tools wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage DEPLOYTOOL=./linuxdeploy-x86_64.AppImage @@ -67,6 +94,11 @@ cp --preserve .libs/libscanmem.so ../libpince/libscanmem cp --preserve wrappers/scanmem.py ../libpince/libscanmem cd .. +# Compile translations +${LRELEASE_CMD} i18n/ts/* +mkdir -p i18n/qm +mv i18n/ts/*.qm i18n/qm/ + # Copy necessary PINCE folders/files to inside AppDir cp -r GUI i18n libpince media tr AUTHORS COPYING COPYING.CC-BY PINCE.py THANKS ci/AppDir/opt/PINCE/ cd ci From 17c97feb0093daba66c0328153b5bc3095b6a28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 2 May 2024 23:12:09 +0300 Subject: [PATCH 399/487] Apply black formatter --- .gitignore | 1 + .vscode/settings.json | 13 + CONTRIBUTING.md | 7 +- GUI/AbstractTableModels/AsciiModel.py | 1 + GUI/AbstractTableModels/HexModel.py | 13 +- GUI/AddAddressManuallyDialog.py | 4 +- GUI/AddAddressManuallyDialog.ui | 2 +- GUI/ItemDelegates/HexDelegate.py | 1 + GUI/Labels/FlagRegisterLabel.py | 8 +- GUI/Labels/RegisterLabel.py | 9 +- .../PointerChainOffset.py | 8 +- GUI/Settings/hotkeys.py | 2 +- GUI/Settings/settings.py | 69 +- GUI/Settings/themes.py | 23 +- GUI/TableViews/AsciiView.py | 1 + GUI/TableViews/HexView.py | 1 + GUI/TreeWidgets/AddressTree.py | 2 + GUI/Utils/guiutils.py | 14 +- GUI/Utils/keyboard_hack.py | 5 +- PINCE.py | 742 +++++++++++------- fix_ts.py | 22 +- libpince/debugcore.py | 213 +++-- libpince/gdb_python_scripts/gdbextensions.py | 40 +- libpince/gdb_python_scripts/gdbutils.py | 17 +- libpince/regexes.py | 23 +- libpince/typedefs.py | 253 +++--- libpince/utils.py | 43 +- pyproject.toml | 2 + run_tests.py | 28 +- tr/tr.py | 143 ++-- 30 files changed, 1092 insertions(+), 618 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore index f7f79cd5..1b1135a9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ __pycache__/ .idea/* .vscode/* !.vscode/launch.json +!.vscode/settings.json libscanmem.so* libpince/libscanmem/* *.directory diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..2fcd2bbd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "[python]": { + "diffEditor.ignoreTrimWhitespace": false, + "editor.formatOnType": true, + "editor.wordBasedSuggestions": "off", + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.formatOnSave": true, + "editor.formatOnSaveTimeout": 2000 + }, + "black-formatter.args": [ + "--line-length=120" + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 563904c0..97c346a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ - [tests](./libpince/gdb_python_scripts/tests) - An example for .so extension, read more [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) # Code Style -The rules are about the same with PEP-8, with some changes. While they are not strict, I'd like you to follow them for consistency +Formatting style is black defaults, except line length is 120. You can use black without parameters since we already use `pyproject.toml` for this setting - Max characters per line: 120 - Variable naming for libpince: - Classes: PascalCase @@ -54,10 +54,7 @@ The reason behind Qt class member naming convention is that when this project fi So, to have an idea about the type of the variable we are working with, I've come up with that naming idea. It's an old habit if anything. It could maybe replaced with something else after a refactorization -About the max characters per line, I used to use PyCharm when I first started this project years ago. 120 characters is a limit brought by PyCharm, -I've quit using PyCharm eventually but I think the limit makes the code look quite nice. PEP-8 suggests a limit of 79 characters, which is a bit too short to be frank. -So I think it's good to keep this old habit. This limit however, is not strict at all. A few characters passing the limit is ok, sometimes going for a newline -messes up the readability, trust your guts and decide for yourself +About the max characters per line, I used to use PyCharm when I first started this project years ago. 120 characters is a limit brought by PyCharm, I've quit using PyCharm eventually but I think the limit makes the code look quite nice. Black suggests a limit of 88 characters, which is a bit short to be frank. So I think it's good to keep this old habit, especially considering that docstrings have also followed this rule for a long time now. This limit for docstrings however, is not strict at all. A few characters passing the limit is ok, sometimes going for a newline messes up the readability, trust your guts and decide for yourself # UI Files You need to have [Qt6 Designer](https://pkgs.org/search/?q=designer&on=files) and [pyuic6](https://pkgs.org/search/?q=pyuic6&on=files) installed. If there are no available packages for your distro, install [pyqt6-tools](https://pypi.org/project/pyqt6-tools/) instead diff --git a/GUI/AbstractTableModels/AsciiModel.py b/GUI/AbstractTableModels/AsciiModel.py index 55f5889e..b1f71978 100644 --- a/GUI/AbstractTableModels/AsciiModel.py +++ b/GUI/AbstractTableModels/AsciiModel.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from GUI.AbstractTableModels.HexModel import QHexModel from libpince import utils diff --git a/GUI/AbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py index 42ee96cf..835dc6eb 100644 --- a/GUI/AbstractTableModels/HexModel.py +++ b/GUI/AbstractTableModels/HexModel.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt from PyQt6.QtGui import QColor, QColorConstants from libpince import utils, debugcore @@ -26,9 +27,9 @@ def __init__(self, row_count, column_count, parent=None): self.row_count = row_count self.column_count = column_count self.current_address = 0 - offset = row_count*column_count - self.data_array = ["??"]*offset - self.cell_animation = [0]*offset + offset = row_count * column_count + self.data_array = ["??"] * offset + self.cell_animation = [0] * offset self.cell_change_color = QColor(QColorConstants.Red) self.breakpoint_color = QColor(QColorConstants.Green) self.breakpoint_color.setAlpha(96) @@ -49,7 +50,7 @@ def data(self, model_index: QModelIndex, int_role=None): address = self.current_address + index if utils.modulo_address(address, debugcore.inferior_arch) in self.breakpoint_list: return self.breakpoint_color - self.cell_change_color.setAlpha(20*self.cell_animation[index]) + self.cell_change_color.setAlpha(20 * self.cell_animation[index]) return self.cell_change_color elif int_role == Qt.ItemDataRole.DisplayRole: return self.display_data(index) @@ -74,13 +75,13 @@ def refresh(self, int_address, offset, data_array=None, breakpoint_info=None): for i in range(bp.size): self.breakpoint_list.add(utils.modulo_address(breakpoint_address + i, debugcore.inferior_arch)) self.current_address = int_address - self.cell_animation = [0]*offset + self.cell_animation = [0] * offset self.layoutChanged.emit() def update_loop(self, updated_array): for index, item in enumerate(self.cell_animation): if item > 0: - self.cell_animation[index] = item-1 + self.cell_animation[index] = item - 1 for index, item in enumerate(updated_array): if item != self.data_array[index]: self.cell_animation[index] = 6 diff --git a/GUI/AddAddressManuallyDialog.py b/GUI/AddAddressManuallyDialog.py index 287ac2fe..a9c574af 100644 --- a/GUI/AddAddressManuallyDialog.py +++ b/GUI/AddAddressManuallyDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'AddAddressManuallyDialog.ui' # -# Created by: PyQt6 UI code generator 6.6.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -94,6 +94,7 @@ def setupUi(self, Dialog): self.lineEdit_PtrStartAddress.setObjectName("lineEdit_PtrStartAddress") self.horizontalLayout_4.addWidget(self.lineEdit_PtrStartAddress) self.label_BaseAddressDeref = QtWidgets.QLabel(parent=self.widget_Pointer) + self.label_BaseAddressDeref.setText("-> ??") self.label_BaseAddressDeref.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_BaseAddressDeref.setObjectName("label_BaseAddressDeref") self.horizontalLayout_4.addWidget(self.label_BaseAddressDeref) @@ -182,7 +183,6 @@ def retranslateUi(self, Dialog): self.label_Length.setText(_translate("Dialog", "Length:")) self.checkBox_ZeroTerminate.setText(_translate("Dialog", "Zero-Terminated")) self.label_BaseAddress.setText(_translate("Dialog", "Base Address:")) - self.label_BaseAddressDeref.setText(_translate("Dialog", "-> ??")) self.pushButton_AddOffset.setText(_translate("Dialog", "Add Offset")) self.pushButton_RemoveOffset.setText(_translate("Dialog", "Remove Offset")) self.label_4.setText(_translate("Dialog", "Description:")) diff --git a/GUI/AddAddressManuallyDialog.ui b/GUI/AddAddressManuallyDialog.ui index 3debe1cd..eb6109df 100644 --- a/GUI/AddAddressManuallyDialog.ui +++ b/GUI/AddAddressManuallyDialog.ui @@ -225,7 +225,7 @@ - -> <font color=red>??</font> + -> <font color=red>??</font> Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse diff --git a/GUI/ItemDelegates/HexDelegate.py b/GUI/ItemDelegates/HexDelegate.py index f00752b5..904da3b8 100644 --- a/GUI/ItemDelegates/HexDelegate.py +++ b/GUI/ItemDelegates/HexDelegate.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from PyQt6.QtWidgets import QStyledItemDelegate, QLineEdit, QWidget from PyQt6.QtGui import QRegularExpressionValidator from PyQt6.QtCore import QModelIndex, Qt, QRegularExpression diff --git a/GUI/Labels/FlagRegisterLabel.py b/GUI/Labels/FlagRegisterLabel.py index 5d4ca795..06ffd4da 100644 --- a/GUI/Labels/FlagRegisterLabel.py +++ b/GUI/Labels/FlagRegisterLabel.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from PyQt6.QtWidgets import QLabel from PyQt6.QtGui import QCursor, QMouseEvent, QEnterEvent from PyQt6.QtCore import Qt @@ -41,8 +42,11 @@ def enterEvent(self, event: QEnterEvent): super().enterEvent(event) def mouseDoubleClickEvent(self, event: QMouseEvent): - if event.button() != Qt.MouseButton.LeftButton or debugcore.currentpid == -1 or \ - debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + if ( + event.button() != Qt.MouseButton.LeftButton + or debugcore.currentpid == -1 + or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING + ): return registers = debugcore.read_registers() current_flag = self.objectName().lower() diff --git a/GUI/Labels/RegisterLabel.py b/GUI/Labels/RegisterLabel.py index 4e5923ab..010f1335 100644 --- a/GUI/Labels/RegisterLabel.py +++ b/GUI/Labels/RegisterLabel.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from PyQt6.QtWidgets import QLabel, QMenu, QApplication from PyQt6.QtGui import QCursor, QMouseEvent, QEnterEvent, QContextMenuEvent from PyQt6.QtCore import Qt @@ -22,6 +23,7 @@ from GUI.Utils import guiutils from tr.tr import TranslationConstants as tr + class QRegisterLabel(QLabel): def __init__(self, parent=None): super().__init__(parent) @@ -40,8 +42,11 @@ def enterEvent(self, event: QEnterEvent): super().enterEvent(event) def mouseDoubleClickEvent(self, event: QMouseEvent): - if event.button() != Qt.MouseButton.LeftButton or debugcore.currentpid == -1 or \ - debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + if ( + event.button() != Qt.MouseButton.LeftButton + or debugcore.currentpid == -1 + or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING + ): return registers = debugcore.read_registers() current_register = self.objectName().lower() diff --git a/GUI/ManualAddressDialogUtils/PointerChainOffset.py b/GUI/ManualAddressDialogUtils/PointerChainOffset.py index 92c54444..230b3ac4 100644 --- a/GUI/ManualAddressDialogUtils/PointerChainOffset.py +++ b/GUI/ManualAddressDialogUtils/PointerChainOffset.py @@ -3,13 +3,13 @@ from operator import add as opAdd, sub as opSub from GUI.Utils import guiutils - + # Only intended to be used by ManualAddressForm class PointerChainOffset(QFrame): offset_changed_signal = pyqtSignal(name="offsetChanged") - def __init__(self, offset_index: int, parent: QWidget|None = None): + def __init__(self, offset_index: int, parent: QWidget | None = None): super().__init__(parent) self.offset_index = offset_index self.initUI() @@ -41,7 +41,7 @@ def initUI(self): def get_offset_as_int(self): return int(self.offsetText.text(), 16) - + def on_offset_arrow_clicked(self, offsetTextWidget, operator_func): offsetText = offsetTextWidget.text() try: @@ -58,5 +58,3 @@ def offset_changed(self): def update_deref_label(self, text: str): self.derefLabel.setText(text) - - \ No newline at end of file diff --git a/GUI/Settings/hotkeys.py b/GUI/Settings/hotkeys.py index d66a56fb..bf9c6691 100644 --- a/GUI/Settings/hotkeys.py +++ b/GUI/Settings/hotkeys.py @@ -20,7 +20,7 @@ def change_key(self, custom: str) -> None: remove_hotkey(self.handle) self.handle = None self.custom = custom - if custom == '': + if custom == "": return self.handle = add_hotkey(custom.lower(), self.func) diff --git a/GUI/Settings/settings.py b/GUI/Settings/settings.py index df8cdef6..f48a1b74 100644 --- a/GUI/Settings/settings.py +++ b/GUI/Settings/settings.py @@ -13,20 +13,59 @@ handle_signals: list = [] # Due to community feedback, these signals are disabled by default: SIGUSR1, SIGUSR2, SIGPWR, SIGXCPU, SIGXFSZ, SIGSYS default_signals = [ - ["SIGHUP", True, True], ["SIGINT", True, False], ["SIGQUIT", True, True], ["SIGILL", True, True], - ["SIGTRAP", True, False], ["SIGABRT", True, True], ["SIGEMT", True, True], ["SIGFPE", True, True], - ["SIGKILL", True, True], ["SIGBUS", True, True], ["SIGSEGV", True, True], ["SIGSYS", False, True], - ["SIGPIPE", True, True], ["SIGALRM", False, True], ["SIGTERM", True, True], ["SIGURG", False, True], - ["SIGSTOP", True, True], ["SIGTSTP", True, True], ["SIGCONT", True, True], ["SIGCHLD", False, True], - ["SIGTTIN", True, True], ["SIGTTOU", True, True], ["SIGIO", False, True], ["SIGXCPU", False, True], - ["SIGXFSZ", False, True], ["SIGVTALRM", False, True], ["SIGPROF", False, True], ["SIGWINCH", False, True], - ["SIGLOST", True, True], ["SIGUSR1", False, True], ["SIGUSR2", False, True], ["SIGPWR", False, True], - ["SIGPOLL", False, True], ["SIGWIND", True, True], ["SIGPHONE", True, True], ["SIGWAITING", False, True], - ["SIGLWP", False, True], ["SIGDANGER", True, True], ["SIGGRANT", True, True], ["SIGRETRACT", True, True], - ["SIGMSG", True, True], ["SIGSOUND", True, True], ["SIGSAK", True, True], ["SIGPRIO", False, True], - ["SIGCANCEL", False, True], ["SIGINFO", True, True], ["EXC_BAD_ACCESS", True, True], - ["EXC_BAD_INSTRUCTION", True, True], ["EXC_ARITHMETIC", True, True], ["EXC_EMULATION", True, True], - ["EXC_SOFTWARE", True, True], ["EXC_BREAKPOINT", True, True], ["SIGLIBRT", False, True] + ["SIGHUP", True, True], + ["SIGINT", True, False], + ["SIGQUIT", True, True], + ["SIGILL", True, True], + ["SIGTRAP", True, False], + ["SIGABRT", True, True], + ["SIGEMT", True, True], + ["SIGFPE", True, True], + ["SIGKILL", True, True], + ["SIGBUS", True, True], + ["SIGSEGV", True, True], + ["SIGSYS", False, True], + ["SIGPIPE", True, True], + ["SIGALRM", False, True], + ["SIGTERM", True, True], + ["SIGURG", False, True], + ["SIGSTOP", True, True], + ["SIGTSTP", True, True], + ["SIGCONT", True, True], + ["SIGCHLD", False, True], + ["SIGTTIN", True, True], + ["SIGTTOU", True, True], + ["SIGIO", False, True], + ["SIGXCPU", False, True], + ["SIGXFSZ", False, True], + ["SIGVTALRM", False, True], + ["SIGPROF", False, True], + ["SIGWINCH", False, True], + ["SIGLOST", True, True], + ["SIGUSR1", False, True], + ["SIGUSR2", False, True], + ["SIGPWR", False, True], + ["SIGPOLL", False, True], + ["SIGWIND", True, True], + ["SIGPHONE", True, True], + ["SIGWAITING", False, True], + ["SIGLWP", False, True], + ["SIGDANGER", True, True], + ["SIGGRANT", True, True], + ["SIGRETRACT", True, True], + ["SIGMSG", True, True], + ["SIGSOUND", True, True], + ["SIGSAK", True, True], + ["SIGPRIO", False, True], + ["SIGCANCEL", False, True], + ["SIGINFO", True, True], + ["EXC_BAD_ACCESS", True, True], + ["EXC_BAD_INSTRUCTION", True, True], + ["EXC_ARITHMETIC", True, True], + ["EXC_EMULATION", True, True], + ["EXC_SOFTWARE", True, True], + ["EXC_BREAKPOINT", True, True], + ["SIGLIBRT", False, True], ] for x in range(32, 128): # Add signals SIG32-SIG127 - default_signals.append([f"SIG{x}", True, True]) \ No newline at end of file + default_signals.append([f"SIG{x}", True, True]) diff --git a/GUI/Settings/themes.py b/GUI/Settings/themes.py index db82b1c0..6702d9f9 100644 --- a/GUI/Settings/themes.py +++ b/GUI/Settings/themes.py @@ -1,16 +1,11 @@ from PyQt6.QtGui import QColor, QPalette -theme_list = [ - "Dark", - "Light", - "System Default", - "Wong (Colorblind Friendly)" -] +theme_list = ["Dark", "Light", "System Default", "Wong (Colorblind Friendly)"] grp_dict = { "ACTIVE": QPalette.ColorGroup.Active, "INACTIVE": QPalette.ColorGroup.Inactive, - "DISABLED": QPalette.ColorGroup.Disabled + "DISABLED": QPalette.ColorGroup.Disabled, } role_dict = { @@ -33,7 +28,7 @@ "ALTERNATE_BASE": QPalette.ColorRole.AlternateBase, "TOOLTIP_BASE": QPalette.ColorRole.ToolTipBase, "TOOLTIP_TEXT": QPalette.ColorRole.ToolTipText, - "PLACEHOLDER_TEXT": QPalette.ColorRole.PlaceholderText + "PLACEHOLDER_TEXT": QPalette.ColorRole.PlaceholderText, } @@ -68,7 +63,7 @@ def get_theme(theme_name): "ALTERNATE_BASE": "#120F18", "TOOLTIP_BASE": "#FFFFDC", "TOOLTIP_TEXT": "#000000", - "PLACEHOLDER_TEXT": "#80FFFFFF" + "PLACEHOLDER_TEXT": "#80FFFFFF", } dark_dict = { @@ -94,7 +89,7 @@ def get_theme(theme_name): "ALTERNATE_BASE": "#241F31", "TOOLTIP_BASE": "#FFFFDC", "TOOLTIP_TEXT": "#000000", - "PLACEHOLDER_TEXT": "#80FFFFFF" + "PLACEHOLDER_TEXT": "#80FFFFFF", }, } return apply_palette(dark_dict) @@ -119,7 +114,7 @@ def get_theme(theme_name): "ALTERNATE_BASE": "#F7F7F7", "TOOLTIP_BASE": "#FFFFDC", "TOOLTIP_TEXT": "#000000", - "PLACEHOLDER_TEXT": "#80000000" + "PLACEHOLDER_TEXT": "#80000000", } light_dict = { @@ -145,7 +140,7 @@ def get_theme(theme_name): "ALTERNATE_BASE": "#F7F7F7", "TOOLTIP_BASE": "#FFFFDC", "TOOLTIP_TEXT": "#000000", - "PLACEHOLDER_TEXT": "#80000000" + "PLACEHOLDER_TEXT": "#80000000", }, } return apply_palette(light_dict) @@ -172,7 +167,7 @@ def get_theme(theme_name): "ALTERNATE_BASE": "#E69F00", "TOOLTIP_BASE": "#FFFFDC", "TOOLTIP_TEXT": "#000000", - "PLACEHOLDER_TEXT": "#80000000" + "PLACEHOLDER_TEXT": "#80000000", } wong_dict = { @@ -198,7 +193,7 @@ def get_theme(theme_name): "ALTERNATE_BASE": "#919191", "TOOLTIP_BASE": "#000000", "TOOLTIP_TEXT": "#FFFFFF", - "PLACEHOLDER_TEXT": "#80000000" + "PLACEHOLDER_TEXT": "#80000000", }, } return apply_palette(wong_dict) diff --git a/GUI/TableViews/AsciiView.py b/GUI/TableViews/AsciiView.py index fc718644..d1f9fef5 100644 --- a/GUI/TableViews/AsciiView.py +++ b/GUI/TableViews/AsciiView.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from GUI.TableViews.HexView import QHexView from GUI.ItemDelegates.HexDelegate import QHexDelegate from libpince import typedefs diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index df759c1d..d9cb753b 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from PyQt6.QtGui import QKeyEvent, QWheelEvent from PyQt6.QtWidgets import QTableView, QAbstractItemView from PyQt6.QtCore import QItemSelectionModel, QModelIndex, Qt diff --git a/GUI/TreeWidgets/AddressTree.py b/GUI/TreeWidgets/AddressTree.py index b7717476..c355507d 100644 --- a/GUI/TreeWidgets/AddressTree.py +++ b/GUI/TreeWidgets/AddressTree.py @@ -14,8 +14,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ + from PyQt6.QtWidgets import QTreeWidget + class QAddressTree(QTreeWidget): def __init__(self, parent=None): super().__init__(parent) diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index f56cb12f..4a40ab58 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -27,9 +27,10 @@ "int_hex": QRegularExpressionValidator(QRegularExpression(regexes.hex_number_gui.pattern)), # hexadecimals "float": QRegularExpressionValidator(QRegularExpression(regexes.float_number.pattern)), # floats "bytearray": QRegularExpressionValidator(QRegularExpression(regexes.bytearray_input.pattern)), # array of bytes - "string": None + "string": None, } + #:tag:GUI def get_icons_directory(): """Gets the directory of the icons @@ -110,7 +111,7 @@ def fill_endianness_combobox(combobox: QComboBox, current_index: int = typedefs. endianness_text = [ (typedefs.ENDIANNESS.HOST, tr.HOST), (typedefs.ENDIANNESS.LITTLE, tr.LITTLE), - (typedefs.ENDIANNESS.BIG, tr.BIG) + (typedefs.ENDIANNESS.BIG, tr.BIG), ] for endian, text in endianness_text: combobox.addItem(text, endian) @@ -192,9 +193,12 @@ def clean_entries(menu: QMenu): if action.isSeparator(): actions = menu.actions() current_index = actions.index(action) - if len(actions) == 1 or (current_index == 0 and actions[1].isSeparator()) or \ - (current_index == -1 and actions[-2].isSeparator()) or \ - (actions[current_index - 1].isSeparator() and actions[current_index + 1].isSeparator()): + if ( + len(actions) == 1 + or (current_index == 0 and actions[1].isSeparator()) + or (current_index == -1 and actions[-2].isSeparator()) + or (actions[current_index - 1].isSeparator() and actions[current_index + 1].isSeparator()) + ): menu.removeAction(action) remove_entries(menu) diff --git a/GUI/Utils/keyboard_hack.py b/GUI/Utils/keyboard_hack.py index 2bd35335..0dbee1a4 100644 --- a/GUI/Utils/keyboard_hack.py +++ b/GUI/Utils/keyboard_hack.py @@ -6,6 +6,7 @@ _is_number = lambda x: isinstance(x, int) _is_list = lambda x: isinstance(x, (list, tuple)) + def parse_hotkey(hotkey): ## function to replace keyboard.parse_hotkey() with fix for literal '+' in hotkey strings """ @@ -36,7 +37,7 @@ def parse_hotkey(hotkey): steps = [] # since we dont have spaces in hotkey strings, we can ignore whitespace in the regex - for step in _re.split(r'(?"), - append_to_travel_history=True): + if self.memory_view_window.disassemble_expression( + row.text(ADDR_COL).strip("P->"), append_to_travel_history=True + ): self.memory_view_window.show() self.memory_view_window.activateWindow() @@ -832,7 +905,7 @@ def index_of(item): items = [] last_index = [-1] # any invalid list of indices are fine for index, item in index_items: - if index[:len(last_index)] == last_index: + if index[: len(last_index)] == last_index: continue # this item is a descendant of the last item items.append(item) last_index = index @@ -912,29 +985,51 @@ def delete_records(self): (item.parent() or root).removeChild(item) def treeWidget_AddressTable_key_press_event(self, event): - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_records), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), self.browse_region_for_selected_row), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.pushButton_RefreshAdressTable_clicked), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_records), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Space), - lambda: self.toggle_records(True)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_X), self.cut_records), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_records), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), self.paste_records), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), lambda: self.paste_records(True)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Return), - self.treeWidget_AddressTable_edit_value), - (QKeyCombination(Qt.KeyboardModifier.KeypadModifier, Qt.Key.Key_Enter), - self.treeWidget_AddressTable_edit_value), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), - self.treeWidget_AddressTable_edit_desc), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), - self.treeWidget_AddressTable_edit_address), - ( - QKeyCombination(Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_type) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [ + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_records), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), + self.browse_region_for_selected_row, + ), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), + ( + QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), + self.pushButton_RefreshAdressTable_clicked, + ), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_records), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Space), + lambda: self.toggle_records(True), + ), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_X), self.cut_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_records), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_V), self.paste_records), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_V), lambda: self.paste_records(True)), + ( + QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Return), + self.treeWidget_AddressTable_edit_value, + ), + ( + QKeyCombination(Qt.KeyboardModifier.KeypadModifier, Qt.Key.Key_Enter), + self.treeWidget_AddressTable_edit_value, + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), + self.treeWidget_AddressTable_edit_desc, + ), + ( + QKeyCombination( + Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return + ), + self.treeWidget_AddressTable_edit_address, + ), + ( + QKeyCombination(Qt.KeyboardModifier.AltModifier, Qt.Key.Key_Return), + self.treeWidget_AddressTable_edit_type, + ), + ] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -958,11 +1053,11 @@ def update_address_table(self): else: expression = address_data parent = row.parent() - if parent and expression.startswith(('+', '-')): - expression = parent.data(ADDR_COL, Qt.ItemDataRole.UserRole+1)+expression + if parent and expression.startswith(("+", "-")): + expression = parent.data(ADDR_COL, Qt.ItemDataRole.UserRole + 1) + expression if expression in exp_cache: address = exp_cache[expression] - elif expression.startswith(('+', '-')): # If parent has an empty address + elif expression.startswith(("+", "-")): # If parent has an empty address address = expression elif basic_math_exp.match(expression.replace(" ", "")): try: @@ -989,17 +1084,18 @@ def update_address_table(self): address = None address_data.base_address = old_base # then set it back if address: - row.setText(ADDR_COL, f'P->{address}') + row.setText(ADDR_COL, f"P->{address}") else: - row.setText(ADDR_COL, 'P->??') + row.setText(ADDR_COL, "P->??") else: - row.setText(ADDR_COL, 'P->??') + row.setText(ADDR_COL, "P->??") else: row.setText(ADDR_COL, address or address_data) address = "" if not address else address - row.setData(ADDR_COL, Qt.ItemDataRole.UserRole+1, address) - value = debugcore.read_memory(address, vt.value_index, vt.length, vt.zero_terminate, - vt.value_repr, vt.endian, mem_handle=mem_handle) + row.setData(ADDR_COL, Qt.ItemDataRole.UserRole + 1, address) + value = debugcore.read_memory( + address, vt.value_index, vt.length, vt.zero_terminate, vt.value_repr, vt.endian, mem_handle=mem_handle + ) value = "" if value is None else str(value) row.setText(VALUE_COL, value) @@ -1115,8 +1211,13 @@ def pushButton_UndoScan_clicked(self): self.pushButton_UndoScan.setEnabled(False) # we can undo once so set it to false and re-enable at next scan def comboBox_ScanType_current_index_changed(self): - hidden_types = [typedefs.SCAN_TYPE.INCREASED, typedefs.SCAN_TYPE.DECREASED, typedefs.SCAN_TYPE.CHANGED, - typedefs.SCAN_TYPE.UNCHANGED, typedefs.SCAN_TYPE.UNKNOWN] + hidden_types = [ + typedefs.SCAN_TYPE.INCREASED, + typedefs.SCAN_TYPE.DECREASED, + typedefs.SCAN_TYPE.CHANGED, + typedefs.SCAN_TYPE.UNCHANGED, + typedefs.SCAN_TYPE.UNKNOWN, + ] if self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) in hidden_types: self.widget_Scan.setEnabled(False) else: @@ -1140,7 +1241,7 @@ def comboBox_ScanType_init(self): typedefs.SCAN_TYPE.BETWEEN: tr.BETWEEN, typedefs.SCAN_TYPE.CHANGED: tr.CHANGED, typedefs.SCAN_TYPE.UNCHANGED: tr.UNCHANGED, - typedefs.SCAN_TYPE.UNKNOWN: tr.UNKNOWN_VALUE + typedefs.SCAN_TYPE.UNKNOWN: tr.UNKNOWN_VALUE, } current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() @@ -1157,7 +1258,7 @@ def comboBox_ScanScope_init(self): (typedefs.SCAN_SCOPE.BASIC, tr.BASIC), (typedefs.SCAN_SCOPE.NORMAL, tr.NORMAL), (typedefs.SCAN_SCOPE.FULL_RW, tr.RW), - (typedefs.SCAN_SCOPE.FULL, tr.FULL) + (typedefs.SCAN_SCOPE.FULL, tr.FULL), ] for scope, text in scan_scope_text: self.comboBox_ScanScope.addItem(text, scope) @@ -1180,7 +1281,7 @@ def validate_search(self, search_for: str, search_for2: str): typedefs.SCAN_TYPE.DECREASED: "-", typedefs.SCAN_TYPE.CHANGED: "!=", typedefs.SCAN_TYPE.UNCHANGED: "=", - typedefs.SCAN_TYPE.UNKNOWN: "snapshot" + typedefs.SCAN_TYPE.UNKNOWN: "snapshot", } if type_index in symbol_map: return symbol_map[type_index] @@ -1196,7 +1297,7 @@ def validate_search(self, search_for: str, search_for2: str): search_for = search_for.replace(".", ",") search_for2 = search_for2.replace(".", ",") elif scan_index == typedefs.SCAN_INDEX.STRING: - search_for = "\" " + search_for + search_for = '" ' + search_for elif self.checkBox_Hex.isChecked(): if not search_for.startswith(("0x", "-0x")): negative_str = "-" if search_for.startswith("-") else "" @@ -1204,14 +1305,14 @@ def validate_search(self, search_for: str, search_for2: str): if not search_for2.startswith(("0x", "-0x")): negative_str = "-" if search_for.startswith("-") else "" search_for2 = negative_str + "0x" + search_for2.lstrip("-") - + if type_index == typedefs.SCAN_TYPE.BETWEEN: return search_for + ".." + search_for2 cmp_symbols = { typedefs.SCAN_TYPE.INCREASED_BY: "+", typedefs.SCAN_TYPE.DECREASED_BY: "-", typedefs.SCAN_TYPE.LESS: "<", - typedefs.SCAN_TYPE.MORE: ">" + typedefs.SCAN_TYPE.MORE: ">", } if type_index in cmp_symbols: return cmp_symbols[type_index] + " " + search_for @@ -1262,7 +1363,7 @@ def _scan_to_length(self, type_index): if type_index == typedefs.SCAN_INDEX.STRING: return len(self.lineEdit_Scan.text()) return 0 - + def update_match_count(self): match_count = scanmem.get_match_count() if match_count > 1000: @@ -1298,7 +1399,7 @@ def tableWidget_valuesearchtable_key_press_event(self, event: QKeyEvent) -> None self.update_match_count() return - + self.tableWidget_valuesearchtable.keyPressEvent_original(event) def comboBox_ValueType_current_index_changed(self): @@ -1311,7 +1412,7 @@ def comboBox_ValueType_current_index_changed(self): validator_str = "int" self.checkBox_Hex.setEnabled(True) # keep hex validator if hex is checked - if (self.checkBox_Hex.isChecked()): + if self.checkBox_Hex.isChecked(): validator_str = "int_hex" else: self.checkBox_Hex.setChecked(False) @@ -1340,16 +1441,21 @@ def pushButton_Open_clicked(self): if content is None: QMessageBox.information(self, tr.ERROR, tr.FILE_LOAD_ERROR.format(file_path)) break - self.insert_records(content, self.treeWidget_AddressTable.invisibleRootItem(), - self.treeWidget_AddressTable.topLevelItemCount()) + self.insert_records( + content, + self.treeWidget_AddressTable.invisibleRootItem(), + self.treeWidget_AddressTable.topLevelItemCount(), + ) def pushButton_Save_clicked(self): pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES) file_path = QFileDialog.getSaveFileName(self, tr.SAVE_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] if not file_path: return - content = [self.read_address_table_recursively(self.treeWidget_AddressTable.topLevelItem(i)) - for i in range(self.treeWidget_AddressTable.topLevelItemCount())] + content = [ + self.read_address_table_recursively(self.treeWidget_AddressTable.topLevelItem(i)) + for i in range(self.treeWidget_AddressTable.topLevelItemCount()) + ] file_path = utils.append_file_extension(file_path, "pct") if not utils.save_file(content, file_path): QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) @@ -1373,7 +1479,7 @@ def attach_to_pid(self, pid: int): typedefs.ATTACH_RESULT.PROCESS_NOT_VALID: tr.PROCESS_NOT_VALID, typedefs.ATTACH_RESULT.ALREADY_DEBUGGING: tr.ALREADY_DEBUGGING, typedefs.ATTACH_RESULT.ALREADY_TRACED: tr.ALREADY_TRACED.format(utils.is_traced(pid)), - typedefs.ATTACH_RESULT.PERM_DENIED: tr.PERM_DENIED + typedefs.ATTACH_RESULT.PERM_DENIED: tr.PERM_DENIED, } QMessageBox.information(app.focusWidget(), tr.ERROR, messages[attach_result]) return False @@ -1491,7 +1597,7 @@ def treeWidget_AddressTable_item_double_clicked(self, row, column): VALUE_COL: self.treeWidget_AddressTable_edit_value, DESC_COL: self.treeWidget_AddressTable_edit_desc, ADDR_COL: self.treeWidget_AddressTable_edit_address, - TYPE_COL: self.treeWidget_AddressTable_edit_type + TYPE_COL: self.treeWidget_AddressTable_edit_type, } action_for_column = collections.defaultdict(lambda *args: lambda: None, action_for_column) action_for_column[column]() @@ -1542,8 +1648,11 @@ def update_search_table(self): previous_text = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_PREVIOUS_COL).text() value_index, value_repr, endian = address_item.data(Qt.ItemDataRole.UserRole) address = address_item.text() - new_value = str(debugcore.read_memory(address, value_index, length, value_repr=value_repr, - endian=endian, mem_handle=mem_handle)) + new_value = str( + debugcore.read_memory( + address, value_index, length, value_repr=value_repr, endian=endian, mem_handle=mem_handle + ) + ) value_item = QTableWidgetItem(new_value) if new_value != previous_text: value_item.setForeground(QBrush(QColor(255, 0, 0))) @@ -1563,8 +1672,12 @@ def freeze(self): freeze_type = frozen.freeze_type if typedefs.VALUE_INDEX.is_number(vt.value_index): new_value = debugcore.read_memory(address, vt.value_index, endian=vt.endian) - if freeze_type == typedefs.FREEZE_TYPE.INCREMENT and new_value > value or \ - freeze_type == typedefs.FREEZE_TYPE.DECREMENT and new_value < value: + if ( + freeze_type == typedefs.FREEZE_TYPE.INCREMENT + and new_value > value + or freeze_type == typedefs.FREEZE_TYPE.DECREMENT + and new_value < value + ): frozen.value = new_value debugcore.write_memory(address, vt.value_index, new_value, endian=vt.endian) continue @@ -1598,10 +1711,9 @@ def treeWidget_AddressTable_item_clicked(self, row: QTreeWidgetItem, column: int vt: typedefs.ValueType = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) frozen.value = utils.parse_string(row.text(VALUE_COL), vt.value_index) else: - frozen.enabled = False # it has just been toggled off + frozen.enabled = False # it has just been toggled off self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT) - def treeWidget_AddressTable_change_repr(self, new_repr): value_type = guiutils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) value_type.value_repr = new_repr @@ -1694,8 +1806,9 @@ def read_address_table_entries(self, row, serialize=False): # All values except the last are the same as read_address_table_entries output. # Last value is an iterable of information about its direct children. def read_address_table_recursively(self, row): - return self.read_address_table_entries(row, True) + \ - ([self.read_address_table_recursively(row.child(i)) for i in range(row.childCount())],) + return self.read_address_table_entries(row, True) + ( + [self.read_address_table_recursively(row.child(i)) for i in range(row.childCount())], + ) # Flashing Attach Button when the process is not attached def flash_attach_button(self): @@ -1859,9 +1972,7 @@ def label_Value_context_menu_event(self, event): font_size = self.label_Value.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) - actions = { - refresh: self.update_value - } + actions = {refresh: self.update_value} try: actions[action]() except KeyError: @@ -1886,7 +1997,7 @@ def removeOffsetLayout(self): def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult): if pointer_chain_result != None: - base_deref = hex(pointer_chain_result.pointer_chain[0]).upper().replace("X","x") + base_deref = hex(pointer_chain_result.pointer_chain[0]).upper().replace("X", "x") self.label_BaseAddressDeref.setText(f" → {base_deref}") for index, offsetFrame in enumerate(self.offsetsList): previousDerefText = self.caps_hex_or_error_indicator(pointer_chain_result.pointer_chain[index]) @@ -1909,11 +2020,13 @@ def caps_hex_or_error_indicator(self, address: int): return self.caps_hex(hex(address)) def caps_hex(self, hex_str: str): - return hex_str.upper().replace("X","x") + return hex_str.upper().replace("X", "x") def update_value(self): if self.checkBox_IsPointer.isChecked(): - pointer_chain_req = typedefs.PointerChainRequest(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) + pointer_chain_req = typedefs.PointerChainRequest( + self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list() + ) pointer_chain_result = debugcore.read_pointer_chain(pointer_chain_req) address = None if pointer_chain_result != None: @@ -2217,8 +2330,14 @@ class InputDialogForm(QDialog, InputDialog): # that points the current index of the QComboBox, for instance: ["0", "1", 1] will create a QCombobox with the items # "0" and "1" then will set current index to 1 (which is the item "1") # label_alignment is optional - def __init__(self, parent, item_list=None, parsed_index=-1, value_index=typedefs.VALUE_INDEX.INT32, - buttons=(QDialogButtonBox.StandardButton.Ok, QDialogButtonBox.StandardButton.Cancel)): + def __init__( + self, + parent, + item_list=None, + parsed_index=-1, + value_index=typedefs.VALUE_INDEX.INT32, + buttons=(QDialogButtonBox.StandardButton.Ok, QDialogButtonBox.StandardButton.Cancel), + ): super().__init__(parent) self.setupUi(self) for button in buttons: @@ -2233,7 +2352,8 @@ def __init__(self, parent, item_list=None, parsed_index=-1, value_index=typedefs label.setAlignment(Qt.AlignmentFlag.AlignCenter) label.setText(item[0]) label.setTextInteractionFlags( - Qt.TextInteractionFlag.LinksAccessibleByMouse | Qt.TextInteractionFlag.TextSelectableByMouse) + Qt.TextInteractionFlag.LinksAccessibleByMouse | Qt.TextInteractionFlag.TextSelectableByMouse + ) self.verticalLayout.addWidget(label) try: item_data = item[1] @@ -2273,8 +2393,11 @@ def get_text(self, item): return string def get_values(self): - return self.get_text(self.object_list[0]) if len(self.object_list) == 1 else [self.get_text(item) for item in - self.object_list] + return ( + self.get_text(self.object_list[0]) + if len(self.object_list) == 1 + else [self.get_text(item) for item in self.object_list] + ) def accept(self): if self.parsed_index != -1: @@ -2322,7 +2445,7 @@ def __init__(self, parent, set_default_settings_func): locale_model.appendRow(item) self.comboBox_Language.setModel(locale_model) self.comboBox_InterruptSignal.addItem("SIGINT") - self.comboBox_InterruptSignal.addItems([f"SIG{x}" for x in range(signal.SIGRTMIN, signal.SIGRTMAX+1)]) + self.comboBox_InterruptSignal.addItems([f"SIG{x}" for x in range(signal.SIGRTMIN, signal.SIGRTMAX + 1)]) self.comboBox_InterruptSignal.setStyleSheet("combobox-popup: 0;") # maxVisibleItems doesn't work otherwise self.comboBox_Theme.addItems(theme_list) logo_directory = utils.get_logo_directory() @@ -2381,8 +2504,11 @@ def accept(self): if self.checkBox_AutoUpdateAddressTable.isChecked(): self.settings.setValue("General/address_table_update_interval", current_table_update_interval) self.settings.setValue("General/freeze_interval", current_freeze_interval) - output_mode = [self.checkBox_OutputModeAsync.isChecked(), self.checkBox_OutputModeCommand.isChecked(), - self.checkBox_OutputModeCommandInfo.isChecked()] + output_mode = [ + self.checkBox_OutputModeAsync.isChecked(), + self.checkBox_OutputModeCommand.isChecked(), + self.checkBox_OutputModeCommandInfo.isChecked(), + ] self.settings.setValue("General/gdb_output_mode", json.dumps(output_mode)) if self.checkBox_AutoAttachRegex.isChecked(): try: @@ -2405,8 +2531,9 @@ def accept(self): elif self.radioButton_AdvancedInjection.isChecked(): injection_method = typedefs.INJECTION_METHOD.ADVANCED self.settings.setValue("CodeInjection/code_injection_method", injection_method) - self.settings.setValue("Disassemble/bring_disassemble_to_front", - self.checkBox_BringDisassembleToFront.isChecked()) + self.settings.setValue( + "Disassemble/bring_disassemble_to_front", self.checkBox_BringDisassembleToFront.isChecked() + ) self.settings.setValue("Disassemble/instructions_per_scroll", current_instructions_shown) selected_gdb_path = self.lineEdit_GDBPath.text() current_gdb_path = self.settings.value("Debug/gdb_path", type=str) @@ -2430,9 +2557,11 @@ def reject(self): def config_gui(self): self.checkBox_AutoUpdateAddressTable.setChecked( - self.settings.value("General/auto_update_address_table", type=bool)) + self.settings.value("General/auto_update_address_table", type=bool) + ) self.lineEdit_UpdateInterval.setText( - str(self.settings.value("General/address_table_update_interval", type=int))) + str(self.settings.value("General/address_table_update_interval", type=int)) + ) self.lineEdit_FreezeInterval.setText(str(self.settings.value("General/freeze_interval", type=int))) output_mode = json.loads(self.settings.value("General/gdb_output_mode", type=str)) output_mode = typedefs.gdb_output_mode(*output_mode) @@ -2458,9 +2587,11 @@ def config_gui(self): self.radioButton_AdvancedInjection.setChecked(True) self.checkBox_BringDisassembleToFront.setChecked( - self.settings.value("Disassemble/bring_disassemble_to_front", type=bool)) + self.settings.value("Disassemble/bring_disassemble_to_front", type=bool) + ) self.lineEdit_InstructionsPerScroll.setText( - str(self.settings.value("Disassemble/instructions_per_scroll", type=int))) + str(self.settings.value("Disassemble/instructions_per_scroll", type=int)) + ) self.lineEdit_GDBPath.setText(str(self.settings.value("Debug/gdb_path", type=str))) self.checkBox_GDBLogging.setChecked(self.settings.value("Debug/gdb_logging", type=bool)) self.comboBox_InterruptSignal.setCurrentText(self.settings.value("Debug/interrupt_signal", type=str)) @@ -2473,7 +2604,7 @@ def listWidget_Functions_current_row_changed(self, index): if index == -1: self.lineEdit_Hotkey.clear() else: - self.lineEdit_Hotkey.setText(self.hotkey_to_value[hotkeys.get_hotkeys()[index].name]) + self.lineEdit_Hotkey.setText(self.hotkey_to_value[hotkeys.get_hotkeys()[index].name]) def pushButton_ClearHotkey_clicked(self): self.lineEdit_Hotkey.clear() @@ -2527,7 +2658,7 @@ def lineEdit_Hotkey_key_pressed_event(self, event: QKeyEvent): One final caveat exists: system hotkeys or system wide defined hotkeys (xserver) take precedence over the keyboard lib and are not caught completely. """ - pressed_events:list[KeyboardEvent] = list(_pressed_events.values()) + pressed_events: list[KeyboardEvent] = list(_pressed_events.values()) if len(pressed_events) == 0: # the keypress time was so short its not recognized by keyboard lib. return @@ -2539,7 +2670,7 @@ def lineEdit_Hotkey_key_pressed_event(self, event: QKeyEvent): if ev.scan_code == 125 or ev.scan_code == 126: ev.name = "windows" hotkey_string += ev.name + "+" - + # remove the last plus hotkey_string = hotkey_string[:-1] @@ -2549,8 +2680,8 @@ def lineEdit_Hotkey_key_pressed_event(self, event: QKeyEvent): if index == -1: self.lineEdit_Hotkey.clear() else: - self.hotkey_to_value[ - hotkeys.get_hotkeys()[index].name] = self.lineEdit_Hotkey.text() + self.hotkey_to_value[hotkeys.get_hotkeys()[index].name] = self.lineEdit_Hotkey.text() + class HandleSignalsDialogForm(QDialog, HandleSignalsDialog): def __init__(self, parent, signal_data): @@ -2575,7 +2706,6 @@ def __init__(self, parent, signal_data): self.tableWidget_Signals.resizeColumnsToContents() guiutils.center_to_parent(self) - def create_checkbox_widget(self): widget = QWidget() checkbox = QCheckBox() @@ -2697,10 +2827,12 @@ def scroll_forwards_history(self): self.lineEdit.setText(self.input_history[self.current_history_index]) def lineEdit_key_press_event(self, event): - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), self.scroll_backwards_history), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), self.scroll_forwards_history) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [ + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), self.scroll_backwards_history), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), self.scroll_forwards_history), + ] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -2732,8 +2864,9 @@ def __init__(self, parent): thanks_text = open("THANKS").read() self.textBrowser_License.setPlainText(license_text) self.textBrowser_Contributors.append( - "This is only a placeholder, this section may look different when the project finishes" + - "\nIn fact, something like a demo-scene for here would look absolutely fabulous <:") + "This is only a placeholder, this section may look different when the project finishes" + + "\nIn fact, something like a demo-scene for here would look absolutely fabulous <:" + ) self.textBrowser_Contributors.append("\n########") self.textBrowser_Contributors.append("#AUTHORS#") self.textBrowser_Contributors.append("########\n") @@ -2919,7 +3052,8 @@ def initialize_hex_view(self): self.tableWidget_HexView_Address.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_HexView_Address.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_HexView_Address.verticalHeader().setDefaultSectionSize( - self.tableView_HexView_Hex.verticalHeader().defaultSectionSize()) + self.tableView_HexView_Hex.verticalHeader().defaultSectionSize() + ) self.hex_update_timer = QTimer(timeout=self.hex_update_loop) self.hex_update_timer.start(200) @@ -2928,20 +3062,29 @@ def show_trace_window(self): TraceInstructionsWindowForm(self, prompt_dialog=False) def step_instruction(self): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or \ - self.updating_memoryview: + if ( + debugcore.currentpid == -1 + or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING + or self.updating_memoryview + ): return debugcore.step_instruction() def step_over_instruction(self): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or \ - self.updating_memoryview: + if ( + debugcore.currentpid == -1 + or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING + or self.updating_memoryview + ): return debugcore.step_over_instruction() def execute_till_return(self): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or \ - self.updating_memoryview: + if ( + debugcore.currentpid == -1 + or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING + or self.updating_memoryview + ): return debugcore.execute_till_return() @@ -3010,9 +3153,7 @@ def copy_to_clipboard(): font_size = self.label_HexView_Information.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) - actions = { - copy_label: copy_to_clipboard - } + actions = {copy_label: copy_to_clipboard} try: actions[action]() except KeyError: @@ -3058,7 +3199,7 @@ def widget_HexView_context_menu_event(self, event): watchpoint_read: lambda: self.toggle_watchpoint(addr, length, typedefs.WATCHPOINT_TYPE.READ_ONLY), watchpoint_both: lambda: self.toggle_watchpoint(addr, length, typedefs.WATCHPOINT_TYPE.BOTH), add_condition: lambda: self.add_breakpoint_condition(addr, length), - delete_breakpoint: lambda: self.toggle_watchpoint(addr, length) + delete_breakpoint: lambda: self.toggle_watchpoint(addr, length), } try: actions[action]() @@ -3207,14 +3348,14 @@ def handle_hex_selection(self): else: # First line start = hex_selection_model.model().index(*start_point) - end = hex_selection_model.model().index(start_point[0], HEX_VIEW_COL_COUNT-1) + end = hex_selection_model.model().index(start_point[0], HEX_VIEW_COL_COUNT - 1) selection = QItemSelection(start, end) hex_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) ascii_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) # Middle - if end_point[0]-start_point[0] > 1: - start = hex_selection_model.model().index(start_point[0]+1, 0) - end = hex_selection_model.model().index(end_point[0]-1, HEX_VIEW_COL_COUNT-1) + if end_point[0] - start_point[0] > 1: + start = hex_selection_model.model().index(start_point[0] + 1, 0) + end = hex_selection_model.model().index(end_point[0] - 1, HEX_VIEW_COL_COUNT - 1) selection = QItemSelection(start, end) hex_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) ascii_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) @@ -3225,7 +3366,7 @@ def handle_hex_selection(self): hex_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) ascii_selection_model.select(selection, QItemSelectionModel.SelectionFlag.Select) self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) - for row in range(start_point[0], end_point[0]+1): + for row in range(start_point[0], end_point[0] + 1): self.tableWidget_HexView_Address.selectRow(row) self.tableWidget_HexView_Address.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) self.tableView_HexView_Hex.update() @@ -3233,28 +3374,28 @@ def handle_hex_selection(self): self.tableWidget_HexView_Address.update() def hex_point_to_address(self, point): - address = self.hex_model.current_address+point[0]*HEX_VIEW_COL_COUNT+point[1] + address = self.hex_model.current_address + point[0] * HEX_VIEW_COL_COUNT + point[1] return utils.modulo_address(address, debugcore.inferior_arch) def address_to_hex_point(self, address): - diff = address-self.hex_model.current_address - if 0 <= diff < HEX_VIEW_ROW_COUNT*HEX_VIEW_COL_COUNT: - return diff//HEX_VIEW_COL_COUNT, diff % HEX_VIEW_COL_COUNT + diff = address - self.hex_model.current_address + if 0 <= diff < HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT: + return diff // HEX_VIEW_COL_COUNT, diff % HEX_VIEW_COL_COUNT def get_hex_selection_length(self): - return self.hex_selection_address_end-self.hex_selection_address_begin+1 + return self.hex_selection_address_end - self.hex_selection_address_begin + 1 def fix_selection_at_borders(self, start_point, end_point): if not start_point: start_point = (0, 0) if not end_point: - end_point = (HEX_VIEW_ROW_COUNT-1, HEX_VIEW_COL_COUNT-1) + end_point = (HEX_VIEW_ROW_COUNT - 1, HEX_VIEW_COL_COUNT - 1) return start_point, end_point def hex_update_loop(self): - offset = HEX_VIEW_ROW_COUNT*HEX_VIEW_COL_COUNT + offset = HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT if debugcore.currentpid == -1 or exiting: - updated_array = ["??"]*offset + updated_array = ["??"] * offset else: updated_array = debugcore.hex_dump(self.hex_model.current_address, offset) self.hex_model.update_loop(updated_array) @@ -3271,8 +3412,9 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL info = utils.get_region_info(debugcore.currentpid, int_address) if info: self.hex_view_current_region = info - self.label_HexView_Information.setText(tr.REGION_INFO.format( - info.perms, hex(info.start), hex(info.end), info.file_name)) + self.label_HexView_Information.setText( + tr.REGION_INFO.format(info.perms, hex(info.start), hex(info.end), info.file_name) + ) else: self.hex_view_current_region = typedefs.tuple_region_info(0, 0, None, None) self.label_HexView_Information.setText(tr.INVALID_REGION) @@ -3322,8 +3464,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his # TODO: Change this nonsense when the huge refactorization happens current_first_address = utils.extract_address(disas_data[0][0]) # address of first list entry try: - previous_first_address = utils.extract_address( - self.tableWidget_Disassemble.item(0, DISAS_ADDR_COL).text()) + previous_first_address = utils.extract_address(self.tableWidget_Disassemble.item(0, DISAS_ADDR_COL).text()) except AttributeError: previous_first_address = current_first_address @@ -3619,7 +3760,7 @@ def copy_to_clipboard(row, column): switch_to_stack: lambda: self.set_stack_widget(self.Stack), copy_return: lambda: copy_to_clipboard(selected_row, STACKTRACE_RETURN_ADDRESS_COL), copy_frame: lambda: copy_to_clipboard(selected_row, STACKTRACE_FRAME_ADDRESS_COL), - refresh: self.update_stacktrace + refresh: self.update_stacktrace, } try: actions[action]() @@ -3644,20 +3785,26 @@ def tableWidget_Stack_key_press_event(self, event): return selected_row = guiutils.get_current_row(self.tableWidget_Stack) if selected_row == -1: - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [(QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack)] + ) else: current_address_text = self.tableWidget_Stack.item(selected_row, STACK_VALUE_COL).text() current_address = utils.extract_address(current_address_text) - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), - lambda: self.disassemble_expression(current_address, append_to_travel_history=True)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), - lambda: self.hex_dump_address(int(current_address, 16))) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [ + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), + lambda: self.disassemble_expression(current_address, append_to_travel_history=True), + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), + lambda: self.hex_dump_address(int(current_address, 16)), + ), + ] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -3700,7 +3847,7 @@ def copy_to_clipboard(row, column): copy_points_to: lambda: copy_to_clipboard(selected_row, STACK_POINTS_TO_COL), refresh: self.update_stack, show_in_disas: lambda: self.disassemble_expression(current_address, append_to_travel_history=True), - show_in_hex: lambda: self.hex_dump_address(int(current_address, 16)) + show_in_hex: lambda: self.hex_dump_address(int(current_address, 16)), } try: actions[action]() @@ -3740,9 +3887,9 @@ def tableWidget_StackTrace_double_click(self, index): def tableWidget_StackTrace_key_press_event(self, event): if debugcore.currentpid == -1: return - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stacktrace) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [(QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stacktrace)] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -3774,7 +3921,8 @@ def disassemble_check_viewport(self, where, instruction_count): break last_visible_row += 1 current_address = utils.extract_address( - self.tableWidget_Disassemble.item(current_row, DISAS_ADDR_COL).text()) + self.tableWidget_Disassemble.item(current_row, DISAS_ADDR_COL).text() + ) new_address = debugcore.find_closest_instruction_address(current_address, "previous", last_visible_row) self.disassemble_expression(new_address) elif (where == "previous" and current_row == 0) or (where == "next" and current_row_height > height): @@ -3801,16 +3949,25 @@ def widget_HexView_wheel_event(self, event): def widget_HexView_key_press_event(self, event): if debugcore.currentpid == -1: return - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_hex_view_go_to_dialog), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), - lambda: self.disassemble_expression(hex(self.hex_selection_address_begin), append_to_travel_history=True)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_A), self.exec_hex_view_add_address_dialog), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_hex_view_selection), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_hex_view), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.hex_view_scroll_up), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.hex_view_scroll_down), - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [ + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_hex_view_go_to_dialog), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), + lambda: self.disassemble_expression( + hex(self.hex_selection_address_begin), append_to_travel_history=True + ), + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_A), + self.exec_hex_view_add_address_dialog, + ), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), self.copy_hex_view_selection), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_hex_view), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.hex_view_scroll_up), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.hex_view_scroll_down), + ] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -3827,26 +3984,46 @@ def tableWidget_Disassemble_key_press_event(self, event): current_address = utils.extract_address(current_address_text) current_address_int = int(current_address, 16) - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), - lambda: self.follow_instruction(selected_row)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_E), - lambda: self.exec_examine_referrers_widget(current_address_text)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_disassemble_go_to_dialog), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), - lambda: self.hex_dump_address(current_address_int)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), - lambda: self.bookmark_address(current_address_int)), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.dissect_current_region), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_T), self.exec_trace_instructions_dialog), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_disassemble_view), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), - lambda: self.disassemble_check_viewport("next", 1)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), - lambda: self.disassemble_check_viewport("previous", 1)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.disassemble_scroll_up), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.disassemble_scroll_down) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [ + ( + QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), + lambda: self.follow_instruction(selected_row), + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_E), + lambda: self.exec_examine_referrers_widget(current_address_text), + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), + self.exec_disassemble_go_to_dialog, + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), + lambda: self.hex_dump_address(current_address_int), + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), + lambda: self.bookmark_address(current_address_int), + ), + (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.dissect_current_region), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_T), + self.exec_trace_instructions_dialog, + ), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh_disassemble_view), + ( + QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Down), + lambda: self.disassemble_check_viewport("next", 1), + ), + ( + QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Up), + lambda: self.disassemble_check_viewport("previous", 1), + ), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageUp), self.disassemble_scroll_up), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_PageDown), self.disassemble_scroll_down), + ] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -3881,7 +4058,8 @@ def follow_instruction(self, selected_row): if debugcore.currentpid == -1: return address = utils.instruction_follow_address( - self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text()) + self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() + ) if address: self.disassemble_expression(address, append_to_travel_history=True) @@ -3914,7 +4092,8 @@ def copy_all_columns(row): show_in_hex_view = menu.addAction(f"{tr.HEXVIEW_ADDRESS}[Ctrl+H]") menu.addSeparator() followable = utils.instruction_follow_address( - self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text()) + self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() + ) follow = menu.addAction(f"{tr.FOLLOW}[Space]") if not followable: guiutils.delete_menu_entries(menu, [follow]) @@ -3940,7 +4119,7 @@ def copy_all_columns(row): menu.addSeparator() edit_instruction = menu.addAction(tr.EDIT_INSTRUCTION) nop_instruction = menu.addAction(tr.REPLACE_WITH_NOPS) - if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() == '90': + if self.tableWidget_Disassemble.item(selected_row, DISAS_BYTES_COL).text() == "90": guiutils.delete_menu_entries(menu, [nop_instruction]) menu.addSeparator() track_breakpoint = menu.addAction(tr.WHAT_ACCESSES_INSTRUCTION) @@ -3981,7 +4160,7 @@ def copy_all_columns(row): copy_bytes: lambda: copy_to_clipboard(selected_row, DISAS_BYTES_COL), copy_opcode: lambda: copy_to_clipboard(selected_row, DISAS_OPCODES_COL), copy_comment: lambda: copy_to_clipboard(selected_row, DISAS_COMMENT_COL), - copy_all: lambda: copy_all_columns(selected_row) + copy_all: lambda: copy_all_columns(selected_row), } try: actions[action]() @@ -4260,7 +4439,7 @@ def listWidget_context_menu_event(self, event): add_entry: self.exec_add_entry_dialog, change_comment: lambda: self.exec_change_comment_dialog(current_address), delete_record: self.delete_record, - refresh: self.refresh_table + refresh: self.refresh_table, } try: actions[action]() @@ -4371,10 +4550,7 @@ def tableWidget_Instructions_context_menu_event(self, event): font_size = self.tableWidget_Instructions.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) - actions = { - restore_instruction: lambda: self.restore_instruction(selected_address_int), - refresh: self.refresh - } + actions = {restore_instruction: lambda: self.restore_instruction(selected_address_int), refresh: self.refresh} try: actions[action]() except KeyError: @@ -4402,9 +4578,9 @@ def refresh_all(self): self.refresh() def tableWidget_Instructions_key_press_event(self, event): - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [(QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh)] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -4462,11 +4638,15 @@ def tableWidget_BreakpointInfo_key_press_event(self, event): else: current_address = None - actions = typedefs.KeyboardModifiersTupleDict([ - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), - lambda: self.delete_breakpoint(current_address)), - (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh) - ]) + actions = typedefs.KeyboardModifiersTupleDict( + [ + ( + QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), + lambda: self.delete_breakpoint(current_address), + ), + (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.refresh), + ] + ) try: actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() except KeyError: @@ -4485,8 +4665,7 @@ def exec_enable_count_dialog(self, current_address): if count < 1: QMessageBox.information(self, tr.ERROR, tr.HIT_COUNT_ASSERT_LT.format(1)) else: - debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.ENABLE_COUNT, - count=count) + debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.ENABLE_COUNT, count=count) def tableWidget_BreakpointInfo_context_menu_event(self, event): selected_row = guiutils.get_current_row(self.tableWidget_BreakpointInfo) @@ -4509,8 +4688,15 @@ def tableWidget_BreakpointInfo_context_menu_event(self, event): delete_breakpoint = menu.addAction(f"{tr.DELETE}[Del]") menu.addSeparator() if current_address is None: - deletion_list = [change_condition, enable, disable, enable_once, enable_count, enable_delete, - delete_breakpoint] + deletion_list = [ + change_condition, + enable, + disable, + enable_once, + enable_count, + enable_delete, + delete_breakpoint, + ] guiutils.delete_menu_entries(menu, deletion_list) refresh = menu.addAction(f"{tr.REFRESH}[R]") font_size = self.tableWidget_BreakpointInfo.font().pointSize() @@ -4522,10 +4708,11 @@ def tableWidget_BreakpointInfo_context_menu_event(self, event): disable: lambda: debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.DISABLE), enable_once: lambda: debugcore.modify_breakpoint(current_address, typedefs.BREAKPOINT_MODIFY.ENABLE_ONCE), enable_count: lambda: self.exec_enable_count_dialog(current_address), - enable_delete: lambda: debugcore.modify_breakpoint(current_address, - typedefs.BREAKPOINT_MODIFY.ENABLE_DELETE), + enable_delete: lambda: debugcore.modify_breakpoint( + current_address, typedefs.BREAKPOINT_MODIFY.ENABLE_DELETE + ), delete_breakpoint: lambda: debugcore.delete_breakpoint(current_address), - refresh: self.refresh + refresh: self.refresh, } try: actions[action]() @@ -4619,8 +4806,8 @@ def tableWidget_Opcodes_current_changed(self, QModelIndex_current): def tableWidget_Opcodes_item_double_clicked(self, index): self.parent().memory_view_window.disassemble_expression( - self.tableWidget_Opcodes.item(index.row(), TRACK_WATCHPOINT_ADDR_COL).text(), - append_to_travel_history=True) + self.tableWidget_Opcodes.item(index.row(), TRACK_WATCHPOINT_ADDR_COL).text(), append_to_travel_history=True + ) self.parent().memory_view_window.show() self.parent().memory_view_window.activateWindow() @@ -4684,11 +4871,13 @@ def update_list(self): for register_expression in info: for row, address in enumerate(info[register_expression]): self.tableWidget_TrackInfo.setRowCount(self.tableWidget_TrackInfo.rowCount() + 1) - self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_COUNT_COL, - QTableWidgetItem(str(info[register_expression][address]))) + self.tableWidget_TrackInfo.setItem( + row, TRACK_BREAKPOINT_COUNT_COL, QTableWidgetItem(str(info[register_expression][address])) + ) self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_ADDR_COL, QTableWidgetItem(address)) - self.tableWidget_TrackInfo.setItem(row, TRACK_BREAKPOINT_SOURCE_COL, - QTableWidgetItem("[" + register_expression + "]")) + self.tableWidget_TrackInfo.setItem( + row, TRACK_BREAKPOINT_SOURCE_COL, QTableWidgetItem("[" + register_expression + "]") + ) self.update_values() def update_values(self): @@ -4756,8 +4945,17 @@ def get_values(self): collect_flag_registers = self.checkBox_FlagRegisters.isChecked() collect_segment_registers = self.checkBox_SegmentRegisters.isChecked() collect_float_registers = self.checkBox_FloatRegisters.isChecked() - return (max_trace_count, trigger_condition, stop_condition, step_mode, stop_after_trace, - collect_general_registers, collect_flag_registers, collect_segment_registers, collect_float_registers) + return ( + max_trace_count, + trigger_condition, + stop_condition, + step_mode, + stop_after_trace, + collect_general_registers, + collect_flag_registers, + collect_segment_registers, + collect_float_registers, + ) def accept(self): if int(self.lineEdit_MaxTraceCount.text()) >= 1: @@ -4776,7 +4974,7 @@ def __init__(self, parent, address, breakpoint): typedefs.TRACE_STATUS.IDLE: tr.WAITING_FOR_BREAKPOINT, typedefs.TRACE_STATUS.CANCELED: tr.TRACING_CANCELED, typedefs.TRACE_STATUS.PROCESSING: tr.PROCESSING_DATA, - typedefs.TRACE_STATUS.FINISHED: tr.TRACING_COMPLETED + typedefs.TRACE_STATUS.FINISHED: tr.TRACING_COMPLETED, } self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) self.address = address @@ -4863,7 +5061,8 @@ def display_collected_data(self, QTreeWidgetItem_current): for key in current_dict: self.textBrowser_RegisterInfo.append(str(key) + " = " + str(current_dict[key])) self.textBrowser_RegisterInfo.verticalScrollBar().setValue( - self.textBrowser_RegisterInfo.verticalScrollBar().minimum()) + self.textBrowser_RegisterInfo.verticalScrollBar().minimum() + ) def show_trace_info(self, trace_data=None): self.treeWidget_InstructionInfo.setStyleSheet("QTreeWidget::item{ height: 16px; }") @@ -4923,7 +5122,7 @@ def treeWidget_InstructionInfo_context_menu_event(self, event): action = menu.exec(event.globalPos()) actions = { expand_all: self.treeWidget_InstructionInfo.expandAll, - collapse_all: self.treeWidget_InstructionInfo.collapseAll + collapse_all: self.treeWidget_InstructionInfo.collapseAll, } try: actions[action]() @@ -5016,7 +5215,7 @@ def copy_to_clipboard(row, column): action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row, FUNCTIONS_INFO_ADDR_COL), - copy_symbol: lambda: copy_to_clipboard(selected_row, FUNCTIONS_INFO_SYMBOL_COL) + copy_symbol: lambda: copy_to_clipboard(selected_row, FUNCTIONS_INFO_SYMBOL_COL), } try: actions[action]() @@ -5030,8 +5229,11 @@ def tableWidget_SymbolInfo_item_double_clicked(self, index): self.parent().disassemble_expression(address, append_to_travel_history=True) def pushButton_Help_clicked(self): - InputDialogForm(self, [(tr.FUNCTIONS_INFO_HELPER, None, Qt.AlignmentFlag.AlignLeft)], - buttons=[QDialogButtonBox.StandardButton.Ok]).exec() + InputDialogForm( + self, + [(tr.FUNCTIONS_INFO_HELPER, None, Qt.AlignmentFlag.AlignLeft)], + buttons=[QDialogButtonBox.StandardButton.Ok], + ).exec() class EditInstructionDialogForm(QDialog, EditInstructionDialog): @@ -5073,7 +5275,7 @@ def lineEdit_Instruction_text_edited(self): if result: byte_list = result[0] self.set_valid(True) - bytes_str = " ".join([format(num, '02x') for num in byte_list]) + bytes_str = " ".join([format(num, "02x") for num in byte_list]) self.lineEdit_Bytes.setText(bytes_str) else: self.set_valid(False) @@ -5090,7 +5292,7 @@ def accept(self): new_length = len(bytes_aob.split()) old_length = len(self.orig_bytes.split()) if new_length < old_length: - bytes_aob += " 90"*(old_length-new_length) # Append NOPs if we are short on bytes + bytes_aob += " 90" * (old_length - new_length) # Append NOPs if we are short on bytes elif new_length > old_length: if not InputDialogForm(self, [(tr.NEW_OPCODE.format(new_length, old_length),)]).exec(): return @@ -5237,7 +5439,7 @@ def copy_to_clipboard(row, column): actions = { refresh: self.fill_resource_table, copy_item: lambda: copy_to_clipboard(selected_row, LIBPINCE_REFERENCE_ITEM_COL), - copy_value: lambda: copy_to_clipboard(selected_row, LIBPINCE_REFERENCE_VALUE_COL) + copy_value: lambda: copy_to_clipboard(selected_row, LIBPINCE_REFERENCE_VALUE_COL), } try: actions[action]() @@ -5278,7 +5480,7 @@ def collapse_all(): copy_item: lambda: copy_to_clipboard(LIBPINCE_REFERENCE_ITEM_COL), copy_value: lambda: copy_to_clipboard(LIBPINCE_REFERENCE_VALUE_COL), expand_all_items: expand_all, - collapse_all_items: collapse_all + collapse_all_items: collapse_all, } # Thanks QT, for this unexplainable, mind blowing bug of yours @@ -5503,8 +5705,9 @@ def refresh_table(self): enable_regex = self.checkBox_Regex.isChecked() self.loading_dialog = LoadingDialogForm(self) self.background_thread = self.loading_dialog.background_thread - self.background_thread.overrided_func = lambda: self.process_data(regex, start_address, end_address, - case_sensitive, enable_regex) + self.background_thread.overrided_func = lambda: self.process_data( + regex, start_address, end_address, case_sensitive, enable_regex + ) self.background_thread.output_ready.connect(self.apply_data) self.loading_dialog.exec() @@ -5524,8 +5727,11 @@ def apply_data(self, disas_data): self.tableWidget_Opcodes.setSortingEnabled(True) def pushButton_Help_clicked(self): - InputDialogForm(self, [(tr.SEARCH_OPCODE_HELPER, None, Qt.AlignmentFlag.AlignLeft)], - buttons=[QDialogButtonBox.StandardButton.Ok]).exec() + InputDialogForm( + self, + [(tr.SEARCH_OPCODE_HELPER, None, Qt.AlignmentFlag.AlignLeft)], + buttons=[QDialogButtonBox.StandardButton.Ok], + ).exec() def tableWidget_Opcodes_item_double_clicked(self, index): row = index.row() @@ -5548,7 +5754,7 @@ def copy_to_clipboard(row, column): action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row, SEARCH_OPCODE_ADDR_COL), - copy_opcode: lambda: copy_to_clipboard(selected_row, SEARCH_OPCODE_OPCODES_COL) + copy_opcode: lambda: copy_to_clipboard(selected_row, SEARCH_OPCODE_OPCODES_COL), } try: actions[action]() @@ -5573,7 +5779,7 @@ def refresh_table(self): self.tableWidget_MemoryRegions.setRowCount(0) self.tableWidget_MemoryRegions.setRowCount(len(memory_regions)) for row, (start, end, perms, offset, _, _, path) in enumerate(memory_regions): - address = start+"-"+end + address = start + "-" + end self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_ADDR_COL, QTableWidgetItem(address)) self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_PERM_COL, QTableWidgetItem(perms)) self.tableWidget_MemoryRegions.setItem(row, MEMORY_REGIONS_OFFSET_COL, QTableWidgetItem(offset)) @@ -5601,7 +5807,7 @@ def copy_to_clipboard(row, column): refresh: self.refresh_table, copy_addresses: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_ADDR_COL), copy_offset: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_OFFSET_COL), - copy_path: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_PATH_COL) + copy_path: lambda: copy_to_clipboard(selected_row, MEMORY_REGIONS_PATH_COL), } try: actions[action]() @@ -5695,7 +5901,7 @@ def show_memory_regions(self): self.tableWidget_ExecutableMemoryRegions.setRowCount(0) self.tableWidget_ExecutableMemoryRegions.setRowCount(len(executable_regions)) for row, (start, end, _, _, _, _, path) in enumerate(executable_regions): - address = start+"-"+end + address = start + "-" + end self.region_list.append((start, end)) self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_ADDR_COL, QTableWidgetItem(address)) self.tableWidget_ExecutableMemoryRegions.setItem(row, DISSECT_CODE_PATH_COL, QTableWidgetItem(path)) @@ -5727,8 +5933,9 @@ def pushButton_StartCancel_clicked(self): return selected_indexes = [selected_row.row() for selected_row in selected_rows] selected_regions = [self.region_list[selected_index] for selected_index in selected_indexes] - self.background_thread = self.BackgroundThread(selected_regions, - self.checkBox_DiscardInvalidStrings.isChecked()) + self.background_thread = self.BackgroundThread( + selected_regions, self.checkBox_DiscardInvalidStrings.isChecked() + ) self.background_thread.output_ready.connect(self.scan_finished) self.init_after_scan_gui() self.refresh_timer.start() @@ -5781,13 +5988,15 @@ def pad_hex(self, hex_str): self_len = 0 else: self_len = len(hex_str) - index - return '0x' + hex_str[2:].zfill(self.hex_len + self_len) + return "0x" + hex_str[2:].zfill(self.hex_len + self_len) def refresh_table(self): - item_list = debugcore.search_referenced_strings(self.lineEdit_Regex.text(), - self.comboBox_ValueType.currentIndex(), - self.checkBox_CaseSensitive.isChecked(), - self.checkBox_Regex.isChecked()) + item_list = debugcore.search_referenced_strings( + self.lineEdit_Regex.text(), + self.comboBox_ValueType.currentIndex(), + self.checkBox_CaseSensitive.isChecked(), + self.checkBox_Regex.isChecked(), + ) if item_list is None: QMessageBox.information(self, tr.ERROR, tr.INVALID_REGEX) return @@ -5840,7 +6049,7 @@ def copy_to_clipboard(row, column): action = menu.exec(event.globalPos()) actions = { copy_address: lambda: copy_to_clipboard(selected_row, REF_STR_ADDR_COL), - copy_value: lambda: copy_to_clipboard(selected_row, REF_STR_VAL_COL) + copy_value: lambda: copy_to_clipboard(selected_row, REF_STR_VAL_COL), } try: actions[action]() @@ -5860,9 +6069,7 @@ def copy_to_clipboard(row): font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) - actions = { - copy_address: lambda: copy_to_clipboard(selected_row) - } + actions = {copy_address: lambda: copy_to_clipboard(selected_row)} try: actions[action]() except KeyError: @@ -5907,12 +6114,12 @@ def pad_hex(self, hex_str): self_len = 0 else: self_len = len(hex_str) - index - return '0x' + hex_str[2:].zfill(self.hex_len + self_len) + return "0x" + hex_str[2:].zfill(self.hex_len + self_len) def refresh_table(self): - item_list = debugcore.search_referenced_calls(self.lineEdit_Regex.text(), - self.checkBox_CaseSensitive.isChecked(), - self.checkBox_Regex.isChecked()) + item_list = debugcore.search_referenced_calls( + self.lineEdit_Regex.text(), self.checkBox_CaseSensitive.isChecked(), self.checkBox_Regex.isChecked() + ) if item_list is None: QMessageBox.information(self, tr.ERROR, tr.INVALID_REGEX) return @@ -5959,9 +6166,7 @@ def copy_to_clipboard(row, column): font_size = self.tableWidget_References.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) - actions = { - copy_address: lambda: copy_to_clipboard(selected_row, REF_CALL_ADDR_COL) - } + actions = {copy_address: lambda: copy_to_clipboard(selected_row, REF_CALL_ADDR_COL)} try: actions[action]() except KeyError: @@ -5980,9 +6185,7 @@ def copy_to_clipboard(row): font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) - actions = { - copy_address: lambda: copy_to_clipboard(selected_row) - } + actions = {copy_address: lambda: copy_to_clipboard(selected_row)} try: actions[action]() except KeyError: @@ -6015,7 +6218,7 @@ def pad_hex(self, hex_str): self_len = 0 else: self_len = len(hex_str) - index - return '0x' + hex_str[2:].zfill(self.hex_len + self_len) + return "0x" + hex_str[2:].zfill(self.hex_len + self_len) def collect_referrer_data(self): jmp_dict, call_dict = debugcore.get_dissect_code_data(False, True, True) @@ -6072,7 +6275,8 @@ def listWidget_Referrers_current_changed(self, QModelIndex_current): return self.textBrowser_DisasInfo.clear() disas_data = debugcore.disassemble( - utils.extract_address(self.listWidget_Referrers.item(QModelIndex_current.row()).text()), "+200") + utils.extract_address(self.listWidget_Referrers.item(QModelIndex_current.row()).text()), "+200" + ) for address_info, _, opcode in disas_data: self.textBrowser_DisasInfo.append(address_info + opcode) cursor = self.textBrowser_DisasInfo.textCursor() @@ -6096,9 +6300,7 @@ def copy_to_clipboard(row): font_size = self.listWidget_Referrers.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) - actions = { - copy_address: lambda: copy_to_clipboard(selected_row) - } + actions = {copy_address: lambda: copy_to_clipboard(selected_row)} try: actions[action]() except KeyError: diff --git a/fix_ts.py b/fix_ts.py index f91325cb..8c619bf9 100644 --- a/fix_ts.py +++ b/fix_ts.py @@ -8,21 +8,21 @@ # pylupdate6 doesn't set locale on creation, make sure it's there locale = os.path.splitext(os.path.basename(file))[0] -root.set('language', locale) +root.set("language", locale) # Removing line info so updating tr.py affects git history much less -for location in root.findall('.//location'): - location.set('line', '0') +for location in root.findall(".//location"): + location.set("line", "0") -modified_xml = ET.tostring(root, encoding='utf-8', xml_declaration=False).decode() -with open(file, 'r', encoding='utf-8') as f: +modified_xml = ET.tostring(root, encoding="utf-8", xml_declaration=False).decode() +with open(file, "r", encoding="utf-8") as f: original_xml = f.read() # These declarations are hardcoded in pylupdate6, make sure everything is correct -declarations = original_xml.split('\n', 2)[:2] -assert declarations[0] == '', 'xml format has changed' -assert declarations[1] == '', 'doctype format has changed' -final_xml = '\n'.join(declarations) + '\n' + modified_xml + '\n' +declarations = original_xml.split("\n", 2)[:2] +assert declarations[0] == '', "xml format has changed" +assert declarations[1] == "", "doctype format has changed" +final_xml = "\n".join(declarations) + "\n" + modified_xml + "\n" -with open(file, 'w', encoding='utf-8') as f: - f.write(final_xml) \ No newline at end of file +with open(file, "w", encoding="utf-8") as f: + f.write(final_xml) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 89aeb97e..68758f89 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -22,7 +22,7 @@ from . import utils, typedefs, regexes self_pid = os.getpid() -libc = ctypes.CDLL('libc.so.6') +libc = ctypes.CDLL("libc.so.6") system_endianness = typedefs.ENDIANNESS.LITTLE if sys.byteorder == "little" else typedefs.ENDIANNESS.BIG #:tag:GDBInformation @@ -134,21 +134,21 @@ # A string. Determines which signal to use to interrupt the process interrupt_signal = "SIGINT" -''' +""" When PINCE was first launched, it used gdb 7.7.1, which is a very outdated version of gdb interpreter-exec mi command of gdb showed some buggy behaviour at that time Because of that, PINCE couldn't support gdb/mi commands for a while But PINCE is now updated with the new versions of gdb as much as possible and the interpreter-exec works much better So, old parts of codebase still get their required information by parsing gdb console output New parts can try to rely on gdb/mi output -''' +""" -''' +""" Functions that require breakpoint commands, such as track_watchpoint and track_breakpoint, requires process to be stopped beforehand. If the process is running before we give the breakpoint its commands, there's a chance that the breakpoint will be triggered before we give it commands. The process must be stopped to avoid this race condition It's also necessary to stop the process to run commands like "watch" -''' +""" #:tag:GDBCommunication @@ -172,8 +172,9 @@ def cancel_last_command(): #:tag:GDBCommunication -def send_command(command, control=False, cli_output=False, send_with_file=False, file_contents_send=None, - recv_with_file=False): +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 Args: @@ -286,7 +287,7 @@ def check_inferior_status(): print(f"Process terminated (PID:{currentpid})") process_exited_condition.notify_all() return - + # For multiline outputs, only the last async event is important # Get the last match only to optimize parsing stop_info = matches[-1][0] @@ -513,12 +514,14 @@ def init_gdb(gdb_path=utils.get_default_gdb_path()): last_gdb_command = "" libpince_dir = utils.get_libpince_directory() - is_appimage = os.environ.get('APPDIR') + is_appimage = os.environ.get("APPDIR") python_home_env = f"PYTHONHOME={os.environ.get('PYTHONHOME')}" if is_appimage else "" - child = pexpect.spawn(f'sudo -E --preserve-env=PATH LC_NUMERIC=C {python_home_env} {gdb_path} --nx --interpreter=mi', - cwd=libpince_dir, - env=os.environ, - encoding="utf-8") + child = pexpect.spawn( + f"sudo -E --preserve-env=PATH LC_NUMERIC=C {python_home_env} {gdb_path} --nx --interpreter=mi", + cwd=libpince_dir, + env=os.environ, + encoding="utf-8", + ) child.setecho(False) child.delaybeforesend = 0 child.timeout = None @@ -557,8 +560,8 @@ def set_pince_paths(): libpince_dir = utils.get_libpince_directory() pince_dir = os.path.dirname(libpince_dir) gdbinit_aa_dir = utils.get_user_path(typedefs.USER_PATHS.GDBINIT_AA) - send_command('set $GDBINIT_AA_PATH=' + '"' + gdbinit_aa_dir + '"') - send_command('set $PINCE_PATH=' + '"' + pince_dir + '"') + send_command("set $GDBINIT_AA_PATH=" + '"' + gdbinit_aa_dir + '"') + send_command("set $PINCE_PATH=" + '"' + pince_dir + '"') send_command("source gdb_python_scripts/gdbextensions.py") @@ -596,7 +599,7 @@ def attach(pid, gdb_path=utils.get_default_gdb_path()): (lambda: not utils.is_process_valid(pid), typedefs.ATTACH_RESULT.PROCESS_NOT_VALID), (lambda: pid == currentpid, typedefs.ATTACH_RESULT.ALREADY_DEBUGGING), (lambda: traced_by is not None, typedefs.ATTACH_RESULT.ALREADY_TRACED), - (lambda: not can_attach(pid), typedefs.ATTACH_RESULT.PERM_DENIED) + (lambda: not can_attach(pid), typedefs.ATTACH_RESULT.PERM_DENIED), ] for control_func, attach_result in pid_control_list: if control_func(): @@ -826,8 +829,15 @@ def memory_handle(): #:tag:MemoryRW -def read_memory(address, value_index, length=None, zero_terminate=True, value_repr=typedefs.VALUE_REPR.UNSIGNED, - endian=typedefs.ENDIANNESS.HOST, mem_handle=None): +def read_memory( + address, + value_index, + length=None, + zero_terminate=True, + value_repr=typedefs.VALUE_REPR.UNSIGNED, + endian=typedefs.ENDIANNESS.HOST, + mem_handle=None, +): """Reads value from the given address Args: @@ -901,13 +911,13 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re encoding, option = typedefs.string_index_to_encoding_dict[value_index] returned_string = data_read.decode(encoding, option) if zero_terminate: - if returned_string.startswith('\x00'): - returned_string = '\x00' + if returned_string.startswith("\x00"): + returned_string = "\x00" else: - returned_string = returned_string.split('\x00')[0] + returned_string = returned_string.split("\x00")[0] return returned_string[0:length] elif value_index is typedefs.VALUE_INDEX.AOB: - return " ".join(format(n, '02x') for n in data_read) + return " ".join(format(n, "02x") for n in data_read) else: is_integer = typedefs.VALUE_INDEX.is_integer(value_index) if is_integer and value_repr == typedefs.VALUE_REPR.SIGNED: @@ -919,8 +929,13 @@ def read_memory(address, value_index, length=None, zero_terminate=True, value_re #:tag:MemoryRW -def write_memory(address: str | int, value_index: int, value: str | int | float | list[int], zero_terminate=True, - endian=typedefs.ENDIANNESS.HOST): +def write_memory( + address: str | int, + value_index: int, + value: str | int | float | list[int], + zero_terminate=True, + endian=typedefs.ENDIANNESS.HOST, +): """Sets the given value to the given address If any errors occurs while setting value to the according address, it'll be ignored but the information about @@ -1010,8 +1025,9 @@ def examine_expression(expression): """ if currentpid == -1: return typedefs.tuple_examine_expression(None, None, None) - return send_command("pince-examine-expressions", send_with_file=True, file_contents_send=[expression], - recv_with_file=True)[0] + return send_command( + "pince-examine-expressions", send_with_file=True, file_contents_send=[expression], recv_with_file=True + )[0] def examine_expressions(expression_list): @@ -1027,8 +1043,9 @@ def examine_expressions(expression_list): return [] if currentpid == -1: return [typedefs.tuple_examine_expression(None, None, None) for _ in range(len(expression_list))] - return send_command("pince-examine-expressions", send_with_file=True, file_contents_send=expression_list, - recv_with_file=True) + return send_command( + "pince-examine-expressions", send_with_file=True, file_contents_send=expression_list, recv_with_file=True + ) #:tag:GDBExpressions @@ -1049,8 +1066,9 @@ def parse_and_eval(expression, cast=str): cast: Self-explanatory None: If casting fails """ - return send_command("pince-parse-and-eval", send_with_file=True, file_contents_send=(expression, cast), - recv_with_file=True) + return send_command( + "pince-parse-and-eval", send_with_file=True, file_contents_send=(expression, cast), recv_with_file=True + ) #:tag:Threads @@ -1158,8 +1176,12 @@ def search_functions(expression, case_sensitive=False): Please don't try to write a symbol parser for every single language out there, it's an overkill https://sourceware.org/bugzilla/show_bug.cgi?id=23899 """ - return send_command("pince-search-functions", send_with_file=True, file_contents_send=(expression, case_sensitive), - recv_with_file=True) + return send_command( + "pince-search-functions", + send_with_file=True, + file_contents_send=(expression, case_sensitive), + recv_with_file=True, + ) #:tag:InferiorInformation @@ -1236,9 +1258,26 @@ def set_register_flag(flag, value): raise Exception(value + " isn't valid value. It can be only 0 or 1") if flag not in typedefs.REGISTERS.FLAG: raise Exception(flag + " isn't a valid flag, must be a member of typedefs.REGISTERS.FLAG") - eflags_hex_value = hex(int( - registers["of"] + registers["df"] + registers["if"] + registers["tf"] + registers["sf"] + registers[ - "zf"] + "0" + registers["af"] + "0" + registers["pf"] + "0" + registers["cf"], 2)) + eflags_hex_value = hex( + int( + registers["of"] + + registers["df"] + + registers["if"] + + registers["tf"] + + registers["sf"] + + registers["zf"] + + "0" + + registers["af"] + + "0" + + registers["pf"] + + "0" + + registers["cf"], + 2, + ) + ) + a = 5 + b = 3 + set_convenience_variable("eflags", eflags_hex_value) @@ -1329,7 +1368,7 @@ def hex_dump(address, offset): pass for item in range(offset): try: - current_item = " ".join(format(n, '02x') for n in FILE.read(1)) + current_item = " ".join(format(n, "02x") for n in FILE.read(1)) except OSError: current_item = "??" try: @@ -1368,7 +1407,7 @@ def nop_instruction(start_address, length_of_instr): if start_address not in modified_instructions_dict: modified_instructions_dict[start_address] = old_aob - nop_aob = '90 ' * length_of_instr + nop_aob = "90 " * length_of_instr write_memory(start_address, typedefs.VALUE_INDEX.AOB, nop_aob) @@ -1436,11 +1475,19 @@ def get_breakpoint_info() -> list[typedefs.tuple_breakpoint_info]: # Temporary fix for https://sourceware.org/bugzilla/show_bug.cgi?id=9659 # TODO:Delete this line when gdb or pygdbmi fixes the problem raw_info = re.sub(r"script={(.*?)}", r"script=[\g<1>]", raw_info) # Please refer to issue #53 - for item in utils.parse_response(raw_info)['payload']['BreakpointTable']['body']: + for item in utils.parse_response(raw_info)["payload"]["BreakpointTable"]["body"]: item = defaultdict(lambda: "", item) - number, breakpoint_type, disp, enabled, address, what, condition, hit_count, enable_count = \ - item['number'], item['type'], item['disp'], item['enabled'], item['addr'], item['what'], item['cond'], \ - item['times'], item['enable'] + number, breakpoint_type, disp, enabled, address, what, condition, hit_count, enable_count = ( + item["number"], + item["type"], + item["disp"], + item["enabled"], + item["addr"], + item["what"], + item["cond"], + item["times"], + item["enable"], + ) if address == "": multiple_break_data[number] = (breakpoint_type, disp, condition, hit_count) continue @@ -1462,8 +1509,10 @@ def get_breakpoint_info() -> list[typedefs.tuple_breakpoint_info]: else: size = 1 returned_list.append( - typedefs.tuple_breakpoint_info(number, breakpoint_type, disp, enabled, address, size, on_hit, hit_count, - enable_count, condition)) + typedefs.tuple_breakpoint_info( + number, breakpoint_type, disp, enabled, address, size, on_hit, hit_count, enable_count, condition + ) + ) return returned_list @@ -1482,12 +1531,12 @@ def get_breakpoints_in_range(address: str | int, length: int = 1) -> list[typede breakpoint_list = [] if type(address) != int: address = int(address, 0) - max_address = max(address, address+length-1) - min_address = min(address, address+length-1) + max_address = max(address, address + length - 1) + min_address = min(address, address + length - 1) breakpoint_info = get_breakpoint_info() for item in breakpoint_info: breakpoint_address = int(item.address, 16) - if not (max_address < breakpoint_address or min_address > breakpoint_address+item.size-1): + if not (max_address < breakpoint_address or min_address > breakpoint_address + item.size - 1): breakpoint_list.append(item) return breakpoint_list @@ -1514,8 +1563,9 @@ def hardware_breakpoint_available() -> bool: #:tag:BreakWatchpoints -def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE, - on_hit=typedefs.BREAKPOINT_ON_HIT.BREAK): +def add_breakpoint( + expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE, on_hit=typedefs.BREAKPOINT_ON_HIT.BREAK +): """Adds a breakpoint at the address evaluated by the given expression. Uses a software breakpoint if all hardware breakpoint slots are being used @@ -1552,10 +1602,15 @@ def add_breakpoint(expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE else: return + @execute_with_temporary_interruption #:tag:BreakWatchpoints -def add_watchpoint(expression: str, length: int = 4, watchpoint_type: int = typedefs.WATCHPOINT_TYPE.BOTH, - on_hit: int = typedefs.BREAKPOINT_ON_HIT.BREAK) -> list[str]: +def add_watchpoint( + expression: str, + length: int = 4, + watchpoint_type: int = typedefs.WATCHPOINT_TYPE.BOTH, + on_hit: int = typedefs.BREAKPOINT_ON_HIT.BREAK, +) -> list[str]: """Adds a watchpoint at the address evaluated by the given expression Args: @@ -1743,10 +1798,9 @@ def track_watchpoint(expression, length, watchpoint_type): if not breakpoints: return for breakpoint in breakpoints: - send_command("commands " + breakpoint - + "\npince-get-track-watchpoint-info " + str(breakpoints) - + "\nc&" - + "\nend") + send_command( + "commands " + breakpoint + "\npince-get-track-watchpoint-info " + str(breakpoints) + "\nc&" + "\nend" + ) return breakpoints @@ -1795,10 +1849,16 @@ def track_breakpoint(expression, register_expressions): breakpoint = add_breakpoint(expression, on_hit=typedefs.BREAKPOINT_ON_HIT.FIND_ADDR) if not breakpoint: return - send_command("commands " + breakpoint - + "\npince-get-track-breakpoint-info " + register_expressions.replace(" ", "") + "," + breakpoint - + "\nc&" - + "\nend") + send_command( + "commands " + + breakpoint + + "\npince-get-track-breakpoint-info " + + register_expressions.replace(" ", "") + + "," + + breakpoint + + "\nc&" + + "\nend" + ) return breakpoint @@ -1827,10 +1887,18 @@ def get_track_breakpoint_info(breakpoint): @execute_with_temporary_interruption #:tag:Tools -def trace_instructions(expression, max_trace_count=1000, trigger_condition="", stop_condition="", - step_mode=typedefs.STEP_MODE.SINGLE_STEP, - stop_after_trace=False, collect_general_registers=True, collect_flag_registers=True, - collect_segment_registers=True, collect_float_registers=True): +def trace_instructions( + expression, + max_trace_count=1000, + trigger_condition="", + stop_condition="", + step_mode=typedefs.STEP_MODE.SINGLE_STEP, + stop_after_trace=False, + collect_general_registers=True, + collect_flag_registers=True, + collect_segment_registers=True, + collect_float_registers=True, +): """Starts tracing instructions at the address evaluated by the given expression There can be only one tracing process at a time, calling this function without waiting the first tracing process meet an end may cause bizarre behaviour @@ -1866,11 +1934,17 @@ def trace_instructions(expression, max_trace_count=1000, trigger_condition="", s trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) pickle.dump(contents_send, open(trace_status_file, "wb")) param_str = ( - breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_general_registers, - collect_flag_registers, collect_segment_registers, collect_float_registers) - send_command("commands " + breakpoint - + "\npince-trace-instructions " + str(param_str) - + "\nend") + breakpoint, + max_trace_count, + stop_condition, + step_mode, + stop_after_trace, + collect_general_registers, + collect_flag_registers, + collect_segment_registers, + collect_float_registers, + ) + send_command("commands " + breakpoint + "\npince-trace-instructions " + str(param_str) + "\nend") return breakpoint @@ -2100,8 +2174,9 @@ def get_dissect_code_data(referenced_strings=True, referenced_jumps=True, refere #:tag:Tools -def search_referenced_strings(searched_str, value_index=typedefs.VALUE_INDEX.STRING_UTF8, case_sensitive=False, - enable_regex=False): +def search_referenced_strings( + searched_str, value_index=typedefs.VALUE_INDEX.STRING_UTF8, case_sensitive=False, enable_regex=False +): """Searches for given str in the referenced strings Args: diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 063f8b26..4196a96e 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -285,8 +285,13 @@ def invoke(self, arg, from_tty): register_info.update(gdbutils.get_segment_registers()) float_info = gdbutils.get_float_registers() disas_info = gdb.execute("disas " + previous_pc_address + ",+40", to_string=True).replace("=>", " ") - track_watchpoint_dict[breakpoints][current_pc_int] = [count, previous_pc_address, register_info, float_info, - disas_info] + track_watchpoint_dict[breakpoints][current_pc_int] = [ + count, + previous_pc_address, + register_info, + float_info, + disas_info, + ] track_watchpoint_file = utils.get_track_watchpoint_file(pid, breakpoints) pickle.dump(track_watchpoint_dict[breakpoints], open(track_watchpoint_file, "wb")) @@ -343,8 +348,17 @@ def __init__(self): super(TraceInstructions, self).__init__("pince-trace-instructions", gdb.COMMAND_USER) def invoke(self, arg, from_tty): - (breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_general_registers, - collect_flag_registers, collect_segment_registers, collect_float_registers) = eval(arg) + ( + breakpoint, + max_trace_count, + stop_condition, + step_mode, + stop_after_trace, + collect_general_registers, + collect_flag_registers, + collect_segment_registers, + collect_float_registers, + ) = eval(arg) gdb.execute("delete " + breakpoint) trace_status_file = utils.get_trace_instructions_status_file(pid, breakpoint) @@ -378,8 +392,10 @@ def invoke(self, arg, from_tty): current_index += 1 tree.append([(line_info, collect_dict), current_root_index, []]) tree[current_root_index][2].append(current_index) # Add a child - status_info = (typedefs.TRACE_STATUS.TRACING, - line_info + "\n(" + str(x + 1) + "/" + str(max_trace_count) + ")") + status_info = ( + typedefs.TRACE_STATUS.TRACING, + line_info + "\n(" + str(x + 1) + "/" + str(max_trace_count) + ")", + ) pickle.dump(status_info, open(trace_status_file, "wb")) if regexes.trace_instructions_ret.search(line_info): if tree[current_root_index][1] is None: # If no parents exist @@ -488,7 +504,7 @@ def invoke(self, arg, from_tty): ref_jmp_count = len(referenced_jumps_dict) ref_call_count = len(referenced_calls_dict) for region_index, (start_addr, end_addr) in enumerate(region_list): - region_info = start_addr+"-"+end_addr, str(region_index + 1) + " / " + str(region_count) + region_info = start_addr + "-" + end_addr, str(region_index + 1) + " / " + str(region_count) start_addr = int(start_addr, 16) # Becomes address of the last disassembled instruction later on end_addr = int(end_addr, 16) region_finished = False @@ -499,8 +515,12 @@ def invoke(self, arg, from_tty): region_finished = True else: offset = buffer - status_info = region_info + (hex(start_addr)[2:] + "-" + hex(start_addr + offset)[2:], - ref_str_count, ref_jmp_count, ref_call_count) + status_info = region_info + ( + hex(start_addr)[2:] + "-" + hex(start_addr + offset)[2:], + ref_str_count, + ref_jmp_count, + ref_call_count, + ) pickle.dump(status_info, open(dissect_code_status_file, "wb")) try: self.memory.seek(start_addr) @@ -514,7 +534,7 @@ def invoke(self, arg, from_tty): del disas_data[-1] # Get rid of last 4 instructions to ensure correct bytecode translation else: last_disas_addr = 0 - for (instruction_offset, size, instruction, hexdump) in disas_data: + for instruction_offset, size, instruction, hexdump in disas_data: if isinstance(instruction, bytes): instruction = instruction.decode() if instruction.startswith("J") or instruction.startswith("LOOP"): diff --git a/libpince/gdb_python_scripts/gdbutils.py b/libpince/gdb_python_scripts/gdbutils.py index 2261aad7..9d65fa21 100644 --- a/libpince/gdb_python_scripts/gdbutils.py +++ b/libpince/gdb_python_scripts/gdbutils.py @@ -78,8 +78,17 @@ def get_flag_registers(): contents_send = OrderedDict() bitwise_flags = bin(int(gdb.parse_and_eval("$eflags")))[2:] reversed_bitwise_flags = "".join(reversed(bitwise_flags)) - (contents_send["cf"], contents_send["pf"], contents_send["af"], contents_send["zf"], contents_send["sf"], - contents_send["tf"], contents_send["if"], contents_send["df"], contents_send["of"]) = ["0"] * 9 + ( + contents_send["cf"], + contents_send["pf"], + contents_send["af"], + contents_send["zf"], + contents_send["sf"], + contents_send["tf"], + contents_send["if"], + contents_send["df"], + contents_send["of"], + ) = ["0"] * 9 try: contents_send["cf"] = reversed_bitwise_flags[0] contents_send["pf"] = reversed_bitwise_flags[2] @@ -126,7 +135,7 @@ def examine_expression(expression: str, regions=None): offset = "+0" index = regexes.index.search(expression) if index: - expression = expression[:index.start()] + expression = expression[: index.start()] index = int(index.group(1)) else: index = 0 @@ -135,7 +144,7 @@ def examine_expression(expression: str, regions=None): if len(start_address_list) > index: address = start_address_list[index] try: - address = hex(eval(address+offset)) + address = hex(eval(address + offset)) except Exception as e: print(e) return typedefs.tuple_examine_expression(None, None, None) diff --git a/libpince/regexes.py b/libpince/regexes.py index c1758e10..673835b2 100644 --- a/libpince/regexes.py +++ b/libpince/regexes.py @@ -38,11 +38,14 @@ # The command will always start with the word "source", check debugcore.send_command function for the cause gdb_command_source = lambda command_file: compile(r"&\".*source\s" + command_file + r"\\n\"") # &"command\n" # 0x00007fd81d4c7400 <__printf+0>:\t48 81 ec d8 00 00 00\tsub rsp,0xd8\n -disassemble_output = compile(r""" +disassemble_output = compile( + r""" ([0-9a-fA-F]+.*)\\t # Address with symbol (.*?[0-9a-fA-F]{2})\s*\\t # Bytes, ignore padding (.+)\\n # Opcode -""", VERBOSE) +""", + VERBOSE, +) info_functions_non_debugging = compile(hex_number_grouped.pattern + r"\s+(.*)") max_completions_reached = compile(r"\*\*\*\s+List\s+may\s+be\s+truncated,\s+max-completions\s+reached\.\s+\*\*\*") @@ -52,19 +55,25 @@ docstring_variable = compile(r"(\w+)\s*=") docstring_function_or_variable = compile(r"def\s+(\w+)|" + docstring_variable.pattern) whitespaces = compile(r"\s+") -ps = compile(r""" +ps = compile( + r""" \s+(\d+)\s+ # PID (\S+)\s+ # Username (.*)$ # Process name -""", VERBOSE) -maps = compile(r""" +""", + VERBOSE, +) +maps = compile( + r""" ([0-9a-f]+)-([0-9a-f]+)\s+ # Address (start-end) (\S+)\s+ # Permissions ([0-9a-f]+)\s+ # Map offset (\S+)\s+ # Device node (\d+)\s+ # Inode (.*)$ # Pathname -""", VERBOSE) +""", + VERBOSE, +) # --------------------------------------------guiutils------------------------------------------------------------------ @@ -72,7 +81,7 @@ float_number = compile(r"-?[0-9]+[.,]?[0-9]*") bytearray_input = compile(r"^(([A-Fa-f0-9?]{2} +)+)$") decimal_number = compile(r"-?\d+") -hex_number_gui = compile(r"-?(0x)?[0-9a-fA-F]*") # contains optional 0x prefix +hex_number_gui = compile(r"-?(0x)?[0-9a-fA-F]*") # contains optional 0x prefix # --------------------------------------------gdbextensions------------------------------------------------------ diff --git a/libpince/typedefs.py b/libpince/typedefs.py index e8087779..ecc3f2ab 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -20,12 +20,13 @@ import collections.abc, queue, sys + class CONST_TIME: GDB_INPUT_SLEEP = sys.float_info.min class PATHS: - GDB = "/bin/gdb" # Use utils.get_default_gdb_path() + GDB = "/bin/gdb" # Use utils.get_default_gdb_path() TMP = "/tmp/PINCE/" # Use utils.get_tmp_path() IPC = "/dev/shm/PINCE_IPC/" # Use utils.get_ipc_path() FROM_PINCE = "/from_PINCE" # Use utils.get_from_pince_file() @@ -49,7 +50,12 @@ def get_init_directories(): @staticmethod def get_init_files(): - return USER_PATHS.GDBINIT, USER_PATHS.GDBINIT_AA, USER_PATHS.PINCEINIT, USER_PATHS.PINCEINIT_AA + return ( + USER_PATHS.GDBINIT, + USER_PATHS.GDBINIT_AA, + USER_PATHS.PINCEINIT, + USER_PATHS.PINCEINIT_AA, + ) class INFERIOR_STATUS: @@ -128,8 +134,25 @@ class TOGGLE_ATTACH: class REGISTERS: GENERAL_32 = ["eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp", "eip"] - GENERAL_64 = ["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp", "rip", "r8", "r9", "r10", "r11", "r12", - "r13", "r14", "r15"] + GENERAL_64 = [ + "rax", + "rbx", + "rcx", + "rdx", + "rsi", + "rdi", + "rbp", + "rsp", + "rip", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + ] SEGMENT = ["cs", "ss", "ds", "es", "fs", "gs"] FLAG = ["cf", "pf", "af", "zf", "sf", "tf", "if", "df", "of"] @@ -210,78 +233,86 @@ class SCAN_INDEX: BREAKPOINT_ON_HIT.BREAK: "Break", BREAKPOINT_ON_HIT.FIND_CODE: "Find Code", BREAKPOINT_ON_HIT.FIND_ADDR: "Find Address", - BREAKPOINT_ON_HIT.TRACE: "Trace" + BREAKPOINT_ON_HIT.TRACE: "Trace", } # Represents the texts at indexes in the address table # TODO: This class is mostly an UI helper, maybe integrate it into the the UI completely in the future? -index_to_text_dict = collections.OrderedDict([ - (VALUE_INDEX.INT8, "Int8"), - (VALUE_INDEX.INT16, "Int16"), - (VALUE_INDEX.INT32, "Int32"), - (VALUE_INDEX.INT64, "Int64"), - (VALUE_INDEX.FLOAT32, "Float32"), - (VALUE_INDEX.FLOAT64, "Float64"), - (VALUE_INDEX.STRING_ASCII, "String_ASCII"), - (VALUE_INDEX.STRING_UTF8, "String_UTF8"), - (VALUE_INDEX.STRING_UTF16, "String_UTF16"), - (VALUE_INDEX.STRING_UTF32, "String_UTF32"), - (VALUE_INDEX.AOB, "ByteArray") -]) +index_to_text_dict = collections.OrderedDict( + [ + (VALUE_INDEX.INT8, "Int8"), + (VALUE_INDEX.INT16, "Int16"), + (VALUE_INDEX.INT32, "Int32"), + (VALUE_INDEX.INT64, "Int64"), + (VALUE_INDEX.FLOAT32, "Float32"), + (VALUE_INDEX.FLOAT64, "Float64"), + (VALUE_INDEX.STRING_ASCII, "String_ASCII"), + (VALUE_INDEX.STRING_UTF8, "String_UTF8"), + (VALUE_INDEX.STRING_UTF16, "String_UTF16"), + (VALUE_INDEX.STRING_UTF32, "String_UTF32"), + (VALUE_INDEX.AOB, "ByteArray"), + ] +) text_to_index_dict = collections.OrderedDict() for key in index_to_text_dict: text_to_index_dict[index_to_text_dict[key]] = key -scanmem_result_to_index_dict = collections.OrderedDict([ - ("I8", VALUE_INDEX.INT8), - ("I8u", VALUE_INDEX.INT8), - ("I8s", VALUE_INDEX.INT8), - ("I16", VALUE_INDEX.INT16), - ("I16u", VALUE_INDEX.INT16), - ("I16s", VALUE_INDEX.INT16), - ("I32", VALUE_INDEX.INT32), - ("I32u", VALUE_INDEX.INT32), - ("I32s", VALUE_INDEX.INT32), - ("I64", VALUE_INDEX.INT64), - ("I64u", VALUE_INDEX.INT64), - ("I64s", VALUE_INDEX.INT64), - ("F32", VALUE_INDEX.FLOAT32), - ("F64", VALUE_INDEX.FLOAT64), - ("string", VALUE_INDEX.STRING_UTF8), - ("bytearray", VALUE_INDEX.AOB) -]) +scanmem_result_to_index_dict = collections.OrderedDict( + [ + ("I8", VALUE_INDEX.INT8), + ("I8u", VALUE_INDEX.INT8), + ("I8s", VALUE_INDEX.INT8), + ("I16", VALUE_INDEX.INT16), + ("I16u", VALUE_INDEX.INT16), + ("I16s", VALUE_INDEX.INT16), + ("I32", VALUE_INDEX.INT32), + ("I32u", VALUE_INDEX.INT32), + ("I32s", VALUE_INDEX.INT32), + ("I64", VALUE_INDEX.INT64), + ("I64u", VALUE_INDEX.INT64), + ("I64s", VALUE_INDEX.INT64), + ("F32", VALUE_INDEX.FLOAT32), + ("F64", VALUE_INDEX.FLOAT64), + ("string", VALUE_INDEX.STRING_UTF8), + ("bytearray", VALUE_INDEX.AOB), + ] +) # Represents the texts at indexes in scan combobox # TODO: Same as index_to_text_dict, consider integrating into UI completely -scan_index_to_text_dict = collections.OrderedDict([ - (SCAN_INDEX.INT_ANY, "Int(any)"), - (SCAN_INDEX.INT8, "Int8"), - (SCAN_INDEX.INT16, "Int16"), - (SCAN_INDEX.INT32, "Int32"), - (SCAN_INDEX.INT64, "Int64"), - (SCAN_INDEX.FLOAT_ANY, "Float(any)"), - (SCAN_INDEX.FLOAT32, "Float32"), - (SCAN_INDEX.FLOAT64, "Float64"), - (SCAN_INDEX.ANY, "Any(int, float)"), - (SCAN_INDEX.STRING, "String"), - (VALUE_INDEX.AOB, "ByteArray") -]) +scan_index_to_text_dict = collections.OrderedDict( + [ + (SCAN_INDEX.INT_ANY, "Int(any)"), + (SCAN_INDEX.INT8, "Int8"), + (SCAN_INDEX.INT16, "Int16"), + (SCAN_INDEX.INT32, "Int32"), + (SCAN_INDEX.INT64, "Int64"), + (SCAN_INDEX.FLOAT_ANY, "Float(any)"), + (SCAN_INDEX.FLOAT32, "Float32"), + (SCAN_INDEX.FLOAT64, "Float64"), + (SCAN_INDEX.ANY, "Any(int, float)"), + (SCAN_INDEX.STRING, "String"), + (VALUE_INDEX.AOB, "ByteArray"), + ] +) # Used in scan_data_type option of scanmem -scan_index_to_scanmem_dict = collections.OrderedDict([ - (SCAN_INDEX.INT_ANY, "int"), - (SCAN_INDEX.INT8, "int8"), - (SCAN_INDEX.INT16, "int16"), - (SCAN_INDEX.INT32, "int32"), - (SCAN_INDEX.INT64, "int64"), - (SCAN_INDEX.FLOAT_ANY, "float"), - (SCAN_INDEX.FLOAT32, "float32"), - (SCAN_INDEX.FLOAT64, "float64"), - (SCAN_INDEX.ANY, "number"), - (SCAN_INDEX.STRING, "string"), - (VALUE_INDEX.AOB, "bytearray") -]) +scan_index_to_scanmem_dict = collections.OrderedDict( + [ + (SCAN_INDEX.INT_ANY, "int"), + (SCAN_INDEX.INT8, "int8"), + (SCAN_INDEX.INT16, "int16"), + (SCAN_INDEX.INT32, "int32"), + (SCAN_INDEX.INT64, "int64"), + (SCAN_INDEX.FLOAT_ANY, "float"), + (SCAN_INDEX.FLOAT32, "float32"), + (SCAN_INDEX.FLOAT64, "float64"), + (SCAN_INDEX.ANY, "number"), + (SCAN_INDEX.STRING, "string"), + (VALUE_INDEX.AOB, "bytearray"), + ] +) # TODO: Same as index_to_text_dict, consider integrating into UI completely @@ -301,11 +332,26 @@ class SCAN_TYPE: @staticmethod def get_list(scan_mode): if scan_mode == SCAN_MODE.NEW: - return [SCAN_TYPE.EXACT, SCAN_TYPE.LESS, SCAN_TYPE.MORE, SCAN_TYPE.BETWEEN, SCAN_TYPE.UNKNOWN] + return [ + SCAN_TYPE.EXACT, + SCAN_TYPE.LESS, + SCAN_TYPE.MORE, + SCAN_TYPE.BETWEEN, + SCAN_TYPE.UNKNOWN, + ] else: - return [SCAN_TYPE.EXACT, SCAN_TYPE.INCREASED, SCAN_TYPE.INCREASED_BY, SCAN_TYPE.DECREASED, - SCAN_TYPE.DECREASED_BY, SCAN_TYPE.LESS, SCAN_TYPE.MORE, SCAN_TYPE.BETWEEN, - SCAN_TYPE.CHANGED, SCAN_TYPE.UNCHANGED] + return [ + SCAN_TYPE.EXACT, + SCAN_TYPE.INCREASED, + SCAN_TYPE.INCREASED_BY, + SCAN_TYPE.DECREASED, + SCAN_TYPE.DECREASED_BY, + SCAN_TYPE.LESS, + SCAN_TYPE.MORE, + SCAN_TYPE.BETWEEN, + SCAN_TYPE.CHANGED, + SCAN_TYPE.UNCHANGED, + ] class SCAN_MODE: @@ -319,11 +365,13 @@ class SCAN_SCOPE: FULL_RW = 3 FULL = 4 + class ENDIANNESS: HOST = 0 LITTLE = 1 BIG = 2 + string_index_to_encoding_dict = { VALUE_INDEX.STRING_UTF8: ["utf-8", "surrogateescape"], VALUE_INDEX.STRING_UTF16: ["utf-16", "replace"], @@ -350,7 +398,7 @@ class ENDIANNESS: VALUE_INDEX.STRING_UTF8: [None, None], VALUE_INDEX.STRING_UTF16: [None, None], VALUE_INDEX.STRING_UTF32: [None, None], - VALUE_INDEX.AOB: [None, None] + VALUE_INDEX.AOB: [None, None], } # Check gdbutils for an exemplary usage @@ -360,34 +408,38 @@ class ENDIANNESS: VALUE_INDEX.INT32: "I", VALUE_INDEX.INT64: "Q", VALUE_INDEX.FLOAT32: "f", - VALUE_INDEX.FLOAT64: "d" + VALUE_INDEX.FLOAT64: "d", } # Format: {tag:tag_description} -tag_to_string = collections.OrderedDict([ - ("MemoryRW", "Memory Read/Write"), - ("ValueType", "Value Type"), - ("Injection", "Injection"), - ("Debug", "Debugging"), - ("BreakWatchpoints", "Breakpoints&Watchpoints"), - ("Threads", "Threads"), - ("Registers", "Registers"), - ("Stack", "Stack&StackTrace"), - ("Assembly", "Disassemble&Assemble"), - ("GDBExpressions", "GDB Expressions"), - ("GDBCommunication", "GDB Communication"), - ("Tools", "Tools"), - ("Utilities", "Utilities"), - ("Processes", "Processes"), - ("GUI", "GUI"), - ("ConditionsLocks", "Conditions&Locks"), - ("GDBInformation", "GDB Information"), - ("InferiorInformation", "Inferior Information"), -]) +tag_to_string = collections.OrderedDict( + [ + ("MemoryRW", "Memory Read/Write"), + ("ValueType", "Value Type"), + ("Injection", "Injection"), + ("Debug", "Debugging"), + ("BreakWatchpoints", "Breakpoints&Watchpoints"), + ("Threads", "Threads"), + ("Registers", "Registers"), + ("Stack", "Stack&StackTrace"), + ("Assembly", "Disassemble&Assemble"), + ("GDBExpressions", "GDB Expressions"), + ("GDBCommunication", "GDB Communication"), + ("Tools", "Tools"), + ("Utilities", "Utilities"), + ("Processes", "Processes"), + ("GUI", "GUI"), + ("ConditionsLocks", "Conditions&Locks"), + ("GDBInformation", "GDB Information"), + ("InferiorInformation", "Inferior Information"), + ] +) # size-->int, any other field-->str -tuple_breakpoint_info = collections.namedtuple("tuple_breakpoint_info", "number breakpoint_type \ - disp enabled address size on_hit hit_count enable_count condition") +tuple_breakpoint_info = collections.namedtuple( + "tuple_breakpoint_info", + "number breakpoint_type disp enabled address size on_hit hit_count enable_count condition", +) # start, end-->int, perms-->str, file_name-->str tuple_region_info = collections.namedtuple("tuple_region_info", "start end perms file_name") @@ -412,8 +464,14 @@ def __init__(self, value, freeze_type=FREEZE_TYPE.DEFAULT): class ValueType: - def __init__(self, value_index=VALUE_INDEX.INT32, length=10, zero_terminate=True, - value_repr=VALUE_REPR.UNSIGNED, endian=ENDIANNESS.HOST): + def __init__( + self, + value_index=VALUE_INDEX.INT32, + length=10, + zero_terminate=True, + value_repr=VALUE_REPR.UNSIGNED, + endian=ENDIANNESS.HOST, + ): """ Args: value_index (int): Determines the type of data. Can be a member of VALUE_INDEX @@ -430,7 +488,13 @@ def __init__(self, value_index=VALUE_INDEX.INT32, length=10, zero_terminate=True self.endian = endian def serialize(self): - return self.value_index, self.length, self.zero_terminate, self.value_repr, self.endian + return ( + self.value_index, + self.length, + self.zero_terminate, + self.value_repr, + self.endian, + ) def text(self): """Returns the text representation according to its members @@ -467,7 +531,7 @@ def __init__(self): self.pointer_chain: list[int] = [] def get_pointer_by_index(self, index) -> int | None: - if index >= size(self.pointer_chain): + if index >= len(self.pointer_chain): return None return self.pointer_chain[index] @@ -537,4 +601,3 @@ def __iter__(self): def __len__(self): return len(self._storage) - diff --git a/libpince/utils.py b/libpince/utils.py index fe7d5683..cb96ddf2 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -83,7 +83,7 @@ def get_regions(pid): Returns: list: List of (start_address, end_address, permissions, map_offset, device_node, inode, path) -> all str """ - with open("/proc/"+str(pid)+"/maps") as f: + with open("/proc/" + str(pid) + "/maps") as f: regions = [] for line in f.read().splitlines(): regions.append(regexes.maps.match(line).groups()) @@ -108,7 +108,7 @@ def get_region_dict(pid: int) -> dict[str, list[str]]: if not path: continue _, tail = os.path.split(path) - start_addr = "0x"+start_addr + start_addr = "0x" + start_addr short_name = regexes.file_with_extension.search(tail) if short_name: short_name = short_name.group(0) @@ -165,8 +165,9 @@ def filter_regions(pid, attribute, regex, case_sensitive=False): Returns: list: List of (start_address, end_address, permissions, map_offset, device_node, inode, path) -> all str """ - index = ["start_address", "end_address", "permissions", - "map_offset", "device_node", "inode", "path"].index(attribute) + index = ["start_address", "end_address", "permissions", "map_offset", "device_node", "inode", "path"].index( + attribute + ) if index == -1: raise Exception("Invalid attribute") if case_sensitive: @@ -753,19 +754,19 @@ def aob_to_str(list_of_bytes, encoding="ascii"): ### make an actual list of bytes hexString = "" byteList = list_of_bytes - if (isinstance(list_of_bytes, list)): + if isinstance(list_of_bytes, list): byteList = list_of_bytes else: byteList = [] byteList.append(list_of_bytes) for sByte in byteList: - if (sByte == "??"): - hexString += f'{63:02x}' # replace ?? with a single ? + if sByte == "??": + hexString += f"{63:02x}" # replace ?? with a single ? else: - if (isinstance(sByte, int)): - byte=sByte + if isinstance(sByte, int): + byte = sByte else: - byte=int(sByte,16) + byte = int(sByte, 16) """NOTE: replacing non-printable chars with a period will have an adverse effect on the ability to edit hex/ASCII data since the editor dialog will replace the hex bytes with 2e rather @@ -774,11 +775,11 @@ def aob_to_str(list_of_bytes, encoding="ascii"): So for now, don't replace them -- but be aware that this clutters the ascii text in the memory view and does not look 'neat' """ - #if ( (byte < 32) or (byte > 126) ): + # if ( (byte < 32) or (byte > 126) ): # hexString += f'{46:02x}' # replace non-printable chars with a period (.) - #else: - hexString += f'{byte:02x}' - hexBytes=bytes.fromhex(hexString) + # else: + hexString += f"{byte:02x}" + hexBytes = bytes.fromhex(hexString) return hexBytes.decode(encoding, "surrogateescape") @@ -794,7 +795,7 @@ def str_to_aob(string, encoding="ascii"): str: AoB equivalent of the given string """ s = str(binascii.hexlify(string.encode(encoding, "surrogateescape")), encoding) - return " ".join(s[i:i + 2] for i in range(0, len(s), 2)) + return " ".join(s[i : i + 2] for i in range(0, len(s), 2)) #:tag:GDBExpressions @@ -838,10 +839,12 @@ def split_symbol(symbol_string): elif letter == "(": p_count -= 1 if p_count == 0: - returned_list.append((symbol_string[:-(index + 1)])) + returned_list.append((symbol_string[: -(index + 1)])) break - assert p_count >= 0, symbol_string + " contains unhealthy amount of left parentheses\nGotta give him some" \ - ' right parentheses. Like Bob always says "everyone needs a friend"' + assert p_count >= 0, ( + symbol_string + " contains unhealthy amount of left parentheses\nGotta give him some" + ' right parentheses. Like Bob always says "everyone needs a friend"' + ) assert p_count == 0, symbol_string + " contains unbalanced parentheses" if "@plt" in symbol_string: returned_list.append(symbol_string.rsplit("@plt", maxsplit=1)[0]) @@ -1181,8 +1184,8 @@ def wrapper(*args, **kwargs): try: func(*args, **kwargs) except: - #print(f' Args: {args}' ) - #print(f' Kwargs: {kwargs}' ) + # print(f' Args: {args}' ) + # print(f' Kwargs: {kwargs}' ) traceback.print_exc() return wrapper diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..55ec8d78 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.black] +line-length = 120 diff --git a/run_tests.py b/run_tests.py index 4efea2e7..0062a80f 100644 --- a/run_tests.py +++ b/run_tests.py @@ -19,18 +19,30 @@ import unittest, argparse from libpince import debugcore, utils -desc = 'Runs all unit tests by creating or attaching to a process' -ex = 'Example of Usage:' \ - + '\n\tsudo python3 run_tests.py -a kmines' \ - + '\n\tsudo python3 run_tests.py -c /usr/games/kmines -o="-v"' +desc = "Runs all unit tests by creating or attaching to a process" +ex = ( + "Example of Usage:" + + "\n\tsudo python3 run_tests.py -a kmines" + + '\n\tsudo python3 run_tests.py -c /usr/games/kmines -o="-v"' +) parser = argparse.ArgumentParser(description=desc, epilog=ex, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("-a", metavar="process_name", type=str, help="Attaches to the process with given name") parser.add_argument("-c", metavar="file_path", type=str, help="Creates a new process with given path") -parser.add_argument("-o", metavar="options", type=str, default="", - help="Arguments that'll be passed to the inferior, only can be used with -c, optional") -parser.add_argument("-l", metavar="ld_preload_path", type=str, default="", - help="Path of the preloaded .so file, only can be used with -c, optional") +parser.add_argument( + "-o", + metavar="options", + type=str, + default="", + help="Arguments that'll be passed to the inferior, only can be used with -c, optional", +) +parser.add_argument( + "-l", + metavar="ld_preload_path", + type=str, + default="", + help="Path of the preloaded .so file, only can be used with -c, optional", +) args = parser.parse_args() if args.a: diff --git a/tr/tr.py b/tr/tr.py index 87058f32..db6c2c80 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -1,16 +1,14 @@ from PyQt6.QtCore import QObject, QLocale, QT_TR_NOOP, QT_TRANSLATE_NOOP from collections import OrderedDict -language_list = OrderedDict([ - ("en_US", "English"), - ("it_IT", "Italiano"), - ("zh_CN", "简体中文") -]) +language_list = OrderedDict([("en_US", "English"), ("it_IT", "Italiano"), ("zh_CN", "简体中文")]) + def get_locale(): system_locale = QLocale.system().name() return system_locale if system_locale in language_list else "en_US" + # This handles the default translations for QDialogButtonBox.StandardButton # Some of the standard button labels have an ampersand (&). It's used to denote an access key or keyboard shortcut # Translate the text as you wish, then put the ampersand (&) where the shortcut should be @@ -54,9 +52,11 @@ def translate(): SUCCESS = QT_TR_NOOP("Success") INFO = QT_TR_NOOP("Information") GDB_INIT = QT_TR_NOOP("GDB isn't initialized yet") - GDB_INIT_ERROR = QT_TR_NOOP("Unable to initialize GDB\n" - "You might want to reinstall GDB or use the system GDB\n" - "To change the current GDB path, check Settings->Debug") + GDB_INIT_ERROR = QT_TR_NOOP( + "Unable to initialize GDB\n" + "You might want to reinstall GDB or use the system GDB\n" + "To change the current GDB path, check Settings->Debug" + ) EDIT = QT_TR_NOOP("Edit") SHOW_HEX = QT_TR_NOOP("Show as hexadecimal") SHOW_DEC = QT_TR_NOOP("Show as decimal") @@ -125,19 +125,22 @@ def translate(): INSTRUCTION_ASSERT_LT = QT_TR_NOOP("Instruction count cannot be lower than {}") INTERVAL_ASSERT_NEGATIVE = QT_TR_NOOP("Interval cannot be a negative number") ASKING_FOR_TROUBLE = QT_TR_NOOP("You are asking for it, aren't you?") - UPDATE_ASSERT_GT = QT_TR_NOOP("Update interval should be bigger than {} ms\n" - "Setting update interval less than {} ms may cause slowdown\n" - "Proceed?") + UPDATE_ASSERT_GT = QT_TR_NOOP( + "Update interval should be bigger than {} ms\n" + "Setting update interval less than {} ms may cause slowdown\n" + "Proceed?" + ) IS_INVALID_REGEX = QT_TR_NOOP("{} isn't a valid regex") LANG_RESET = QT_TR_NOOP("Language settings will take effect upon the next restart") GDB_RESET = QT_TR_NOOP("You have changed the GDB path, reset GDB now?") - RESET_DEFAULT_SETTINGS = QT_TR_NOOP("This will reset to the default settings\n" - "Proceed?") + RESET_DEFAULT_SETTINGS = QT_TR_NOOP("This will reset to the default settings\n" "Proceed?") MOUSE_OVER_EXAMPLES = QT_TR_NOOP("Mouse over on this text for examples") - AUTO_ATTACH_TOOLTIP = QT_TR_NOOP("asdf|qwer --> search for asdf or qwer\n" - "[as]df --> search for both adf and sdf\n" - "Use the char \\ to escape special chars such as [\n" - r"\[asdf\] --> search for opcodes that contain [asdf]") + AUTO_ATTACH_TOOLTIP = QT_TR_NOOP( + "asdf|qwer --> search for asdf or qwer\n" + "[as]df --> search for both adf and sdf\n" + "Use the char \\ to escape special chars such as [\n" + r"\[asdf\] --> search for opcodes that contain [asdf]" + ) SEPARATE_PROCESSES_WITH = QT_TR_NOOP("Separate processes with {}") SELECT_GDB_BINARY = QT_TR_NOOP("Select the gdb binary") QUIT_SESSION_CRASH = QT_TR_NOOP("Quitting current session will crash PINCE") @@ -167,7 +170,8 @@ def translate(): "---------------------------------------------------------------------------------------------------\n" "You can change the output mode from bottom right\n" "Changing output mode only affects commands sent. Any other output coming from external sources" - "(e.g async output) will be shown in MI format") + "(e.g async output) will be shown in MI format" + ) BREAK = QT_TR_NOOP("Break[{}]") RUN = QT_TR_NOOP("Run[{}]") TOGGLE_ATTACH = QT_TR_NOOP("Toggle Attach[{}]") @@ -192,12 +196,13 @@ def translate(): MV_PAUSED = QT_TR_NOOP("Memory Viewer - Paused") MV_DEBUGGING = QT_TR_NOOP("Memory Viewer - Currently debugging {}") MV_RUNNING = QT_TR_NOOP("Memory Viewer - Running") - ENTER_BP_CONDITION = QT_TR_NOOP("Enter the expression for condition, for instance:\n\n" - "$eax==0x523\n" - "$rax>0 && ($rbp<0 || $rsp==0)\n" - "printf($r10)==3") - BP_CONDITION_FAILED = QT_TR_NOOP("Failed to set condition for address {}\n" - "Check terminal for details") + ENTER_BP_CONDITION = QT_TR_NOOP( + "Enter the expression for condition, for instance:\n\n" + "$eax==0x523\n" + "$rax>0 && ($rbp<0 || $rsp==0)\n" + "printf($r10)==3" + ) + BP_CONDITION_FAILED = QT_TR_NOOP("Failed to set condition for address {}\n" "Check terminal for details") FULL_STACK = QT_TR_NOOP("Full Stack") COPY_RETURN_ADDRESS = QT_TR_NOOP("Copy Return Address") COPY_FRAME_ADDRESS = QT_TR_NOOP("Copy Frame Address") @@ -225,16 +230,18 @@ def translate(): COPY_OPCODE = QT_TR_NOOP("Copy Opcode") COPY_COMMENT = QT_TR_NOOP("Copy Comment") COPY_ALL = QT_TR_NOOP("Copy All") - ENTER_TRACK_BP_EXPRESSION = QT_TR_NOOP("Enter the register expression(s) you want to track\n" - "Register names must start with $\n" - "Each expression must be separated with a comma\n\n" - "For instance:\n" - "Let's say the instruction is mov [rax+rbx],30\n" - "Then you should enter $rax+$rbx\n" - "So PINCE can track address [rax+rbx]\n\n" - "Another example:\n" - "If you enter $rax,$rbx*$rcx+4,$rbp\n" - "PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]") + ENTER_TRACK_BP_EXPRESSION = QT_TR_NOOP( + "Enter the register expression(s) you want to track\n" + "Register names must start with $\n" + "Each expression must be separated with a comma\n\n" + "For instance:\n" + "Let's say the instruction is mov [rax+rbx],30\n" + "Then you should enter $rax+$rbx\n" + "So PINCE can track address [rax+rbx]\n\n" + "Another example:\n" + "If you enter $rax,$rbx*$rcx+4,$rbp\n" + "PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp]" + ) ALREADY_BOOKMARKED = QT_TR_NOOP("This address has already been bookmarked") ENTER_BOOKMARK_COMMENT = QT_TR_NOOP("Enter the comment for bookmarked address") SELECT_SO_FILE = QT_TR_NOOP("Select the .so file") @@ -243,15 +250,17 @@ def translate(): SHARED_OBJECT_TYPE = QT_TR_NOOP("Shared object library (*.so)") FILE_INJECTED = QT_TR_NOOP("The file has been injected") FILE_INJECT_FAILED = QT_TR_NOOP("Failed to inject the .so file") - ENTER_CALL_EXPRESSION = QT_TR_NOOP("Enter the expression for the function that'll be called from the inferior\n" - "You can view functions list from View->Functions\n\n" - "For instance:\n" - 'Calling printf("1234") will yield something like this\n' - '↓\n' - '$28 = 4\n\n' - '$28 is the assigned convenience variable\n' - '4 is the result\n' - 'You can use the assigned variable from the GDB Console') + ENTER_CALL_EXPRESSION = QT_TR_NOOP( + "Enter the expression for the function that'll be called from the inferior\n" + "You can view functions list from View->Functions\n\n" + "For instance:\n" + 'Calling printf("1234") will yield something like this\n' + "↓\n" + "$28 = 4\n\n" + "$28 is the assigned convenience variable\n" + "4 is the result\n" + "You can use the assigned variable from the GDB Console" + ) CALL_EXPRESSION_FAILED = QT_TR_NOOP("Failed to call the expression {}") INVALID_EXPRESSION = QT_TR_NOOP("Invalid expression or address") INVALID_ENTRY = QT_TR_NOOP("Invalid entries detected, refreshing the page") @@ -288,21 +297,26 @@ def translate(): EXPAND_ALL = QT_TR_NOOP("Expand All") COLLAPSE_ALL = QT_TR_NOOP("Collapse All") DEFINED = QT_TR_NOOP("DEFINED") - DEFINED_SYMBOL = QT_TR_NOOP("This symbol is defined. You can use its body as a gdb expression. For instance:\n\n" - "void func(param) can be used as 'func' as a gdb expression") + DEFINED_SYMBOL = QT_TR_NOOP( + "This symbol is defined. You can use its body as a gdb expression. For instance:\n\n" + "void func(param) can be used as 'func' as a gdb expression" + ) COPY_SYMBOL = QT_TR_NOOP("Copy Symbol") - FUNCTIONS_INFO_HELPER = QT_TR_NOOP("\tHere's some useful regex tips:\n" - "^quaso --> search for everything that starts with quaso\n" - "[ab]cd --> search for both acd and bcd\n\n" - "\tHow to interpret symbols:\n" - "A symbol that looks like 'func(param)@plt' consists of 3 pieces\n" - "func, func(param), func(param)@plt\n" - "These 3 functions will have different addresses\n" - "@plt means this function is a subroutine for the original one\n" - "There can be more than one of the same function\n" - "It means that the function is overloaded") - NEW_OPCODE = QT_TR_NOOP("New opcode is {} bytes long but old opcode is only {} bytes long\n" - "This will cause an overflow, proceed?") + FUNCTIONS_INFO_HELPER = QT_TR_NOOP( + "\tHere's some useful regex tips:\n" + "^quaso --> search for everything that starts with quaso\n" + "[ab]cd --> search for both acd and bcd\n\n" + "\tHow to interpret symbols:\n" + "A symbol that looks like 'func(param)@plt' consists of 3 pieces\n" + "func, func(param), func(param)@plt\n" + "These 3 functions will have different addresses\n" + "@plt means this function is a subroutine for the original one\n" + "There can be more than one of the same function\n" + "It means that the function is overloaded" + ) + NEW_OPCODE = QT_TR_NOOP( + "New opcode is {} bytes long but old opcode is only {} bytes long\n" "This will cause an overflow, proceed?" + ) IS_INVALID_EXPRESSION = QT_TR_NOOP("{} isn't a valid expression") LOG_FILE = QT_TR_NOOP("Log File of PID {}") LOG_CONTENTS = QT_TR_NOOP("Contents of {} (only last {} bytes are shown)") @@ -312,11 +326,13 @@ def translate(): LOG_READ_ERROR = QT_TR_NOOP("Unable to read log file at {}") SETTINGS_ENABLE_LOG = QT_TR_NOOP("Go to Settings->Debug to enable logging") INVALID_REGEX = QT_TR_NOOP("Invalid Regex") - SEARCH_OPCODE_HELPER = QT_TR_NOOP("\tHere's some useful regex examples:\n" - "call|rax --> search for opcodes that contain call or rax\n" - "[re]cx --> search for both rcx and ecx\n" - "Use the char \\ to escape special chars such as [\n" - r"\[rsp\] --> search for opcodes that contain [rsp]") + SEARCH_OPCODE_HELPER = QT_TR_NOOP( + "\tHere's some useful regex examples:\n" + "call|rax --> search for opcodes that contain call or rax\n" + "[re]cx --> search for both rcx and ecx\n" + "Use the char \\ to escape special chars such as [\n" + r"\[rsp\] --> search for opcodes that contain [rsp]" + ) COPY_ADDRESSES = QT_TR_NOOP("Copy Addresses") COPY_OFFSET = QT_TR_NOOP("Copy Offset") COPY_PATH = QT_TR_NOOP("Copy Path") @@ -326,8 +342,7 @@ def translate(): SCAN_FINISHED = QT_TR_NOOP("Scan finished") SCAN_CANCELED = QT_TR_NOOP("Scan was canceled") SELECT_ONE_REGION = QT_TR_NOOP("Select at least one region") - DISSECT_CODE = QT_TR_NOOP("You need to dissect code first\n" - "Proceed?") + DISSECT_CODE = QT_TR_NOOP("You need to dissect code first\n" "Proceed?") WAITING_FOR_BREAKPOINT = QT_TR_NOOP("Waiting for breakpoint to trigger") TRACING_CANCELED = QT_TR_NOOP("Tracing has been canceled") TRACING_COMPLETED = QT_TR_NOOP("Tracing has been completed") From b24a583e3f2910704ec964fcce8fa372bdc7c420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 2 May 2024 23:26:30 +0300 Subject: [PATCH 400/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 97c346a4..9cef4b3d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ - [tests](./libpince/gdb_python_scripts/tests) - An example for .so extension, read more [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) # Code Style -Formatting style is black defaults, except line length is 120. You can use black without parameters since we already use `pyproject.toml` for this setting +Formatting style is black defaults, except line length is 120. You can use black without parameters since we already use `pyproject.toml` for this setting. Please do not format automatically generated files under GUI folder. Your changes will be overwritten by Qt Designer. More info at [UI Files](#ui-files) - Max characters per line: 120 - Variable naming for libpince: - Classes: PascalCase From 56988e8c52736c4d9612c09a6e0a9909f9e61c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 4 May 2024 17:27:51 +0300 Subject: [PATCH 401/487] Add setting for byte scroll count --- GUI/Settings/settings.py | 2 +- GUI/SettingsDialog.py | 67 +++++++++++++++++++++++---------------- GUI/SettingsDialog.ui | 68 ++++++++++++++++++++++++++++++---------- PINCE.py | 49 +++++++++++++---------------- i18n/ts/it_IT.ts | 26 +++++++-------- i18n/ts/zh_CN.ts | 32 +++++++++---------- tr/tr.py | 2 -- 7 files changed, 143 insertions(+), 103 deletions(-) diff --git a/GUI/Settings/settings.py b/GUI/Settings/settings.py index f48a1b74..901cc076 100644 --- a/GUI/Settings/settings.py +++ b/GUI/Settings/settings.py @@ -1,6 +1,6 @@ import libpince.typedefs as typedefs -current_settings_version = "34" # Increase version by one if you change settings +current_settings_version = "35" # Increase version by one if you change settings # Unused, will be re-added in the future code_injection_method: int = 0 diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 34b6a5a9..124ecc1b 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SettingsDialog.ui' # -# Created by: PyQt6 UI code generator 6.6.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -255,25 +255,36 @@ def setupUi(self, Dialog): self.gridLayout_5.setObjectName("gridLayout_5") self.verticalLayout_10 = QtWidgets.QVBoxLayout() self.verticalLayout_10.setObjectName("verticalLayout_10") - self.checkBox_BringDisassembleToFront = QtWidgets.QCheckBox(parent=self.page_4) - self.checkBox_BringDisassembleToFront.setObjectName("checkBox_BringDisassembleToFront") - self.verticalLayout_10.addWidget(self.checkBox_BringDisassembleToFront) + self.checkBox_ShowMemoryViewOnStop = QtWidgets.QCheckBox(parent=self.page_4) + self.checkBox_ShowMemoryViewOnStop.setObjectName("checkBox_ShowMemoryViewOnStop") + self.verticalLayout_10.addWidget(self.checkBox_ShowMemoryViewOnStop) self.horizontalLayout_10 = QtWidgets.QHBoxLayout() self.horizontalLayout_10.setObjectName("horizontalLayout_10") - self.horizontalLayout_9 = QtWidgets.QHBoxLayout() - self.horizontalLayout_9.setObjectName("horizontalLayout_9") self.label_6 = QtWidgets.QLabel(parent=self.page_4) self.label_6.setObjectName("label_6") - self.horizontalLayout_9.addWidget(self.label_6) - self.lineEdit_InstructionsPerScroll = QtWidgets.QLineEdit(parent=self.page_4) - self.lineEdit_InstructionsPerScroll.setObjectName("lineEdit_InstructionsPerScroll") - self.horizontalLayout_9.addWidget(self.lineEdit_InstructionsPerScroll) - self.horizontalLayout_10.addLayout(self.horizontalLayout_9) + self.horizontalLayout_10.addWidget(self.label_6) + self.spinBox_InstructionsPerScroll = QtWidgets.QSpinBox(parent=self.page_4) + self.spinBox_InstructionsPerScroll.setObjectName("spinBox_InstructionsPerScroll") + self.horizontalLayout_10.addWidget(self.spinBox_InstructionsPerScroll) spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_10.addItem(spacerItem10) self.verticalLayout_10.addLayout(self.horizontalLayout_10) - spacerItem11 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_10.addItem(spacerItem11) + self.horizontalLayout_19 = QtWidgets.QHBoxLayout() + self.horizontalLayout_19.setObjectName("horizontalLayout_19") + self.label_16 = QtWidgets.QLabel(parent=self.page_4) + self.label_16.setObjectName("label_16") + self.horizontalLayout_19.addWidget(self.label_16) + self.spinBox_BytesPerScroll = QtWidgets.QSpinBox(parent=self.page_4) + self.spinBox_BytesPerScroll.setMaximum(4096) + self.spinBox_BytesPerScroll.setSingleStep(16) + self.spinBox_BytesPerScroll.setDisplayIntegerBase(16) + self.spinBox_BytesPerScroll.setObjectName("spinBox_BytesPerScroll") + self.horizontalLayout_19.addWidget(self.spinBox_BytesPerScroll) + spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_19.addItem(spacerItem11) + self.verticalLayout_10.addLayout(self.horizontalLayout_19) + spacerItem12 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_10.addItem(spacerItem12) self.gridLayout_5.addLayout(self.verticalLayout_10, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_4) self.page_5 = QtWidgets.QWidget() @@ -308,19 +319,19 @@ def setupUi(self, Dialog): self.comboBox_InterruptSignal = QtWidgets.QComboBox(parent=self.page_5) self.comboBox_InterruptSignal.setObjectName("comboBox_InterruptSignal") self.horizontalLayout_18.addWidget(self.comboBox_InterruptSignal) - spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_18.addItem(spacerItem12) + spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_18.addItem(spacerItem13) self.verticalLayout_11.addLayout(self.horizontalLayout_18) self.horizontalLayout_16 = QtWidgets.QHBoxLayout() self.horizontalLayout_16.setObjectName("horizontalLayout_16") self.pushButton_HandleSignals = QtWidgets.QPushButton(parent=self.page_5) self.pushButton_HandleSignals.setObjectName("pushButton_HandleSignals") self.horizontalLayout_16.addWidget(self.pushButton_HandleSignals) - spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_16.addItem(spacerItem13) + spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_16.addItem(spacerItem14) self.verticalLayout_11.addLayout(self.horizontalLayout_16) - spacerItem14 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_11.addItem(spacerItem14) + spacerItem15 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_11.addItem(spacerItem15) self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) self.stackedWidget.addWidget(self.page_5) self.page_6 = QtWidgets.QWidget() @@ -330,8 +341,8 @@ def setupUi(self, Dialog): self.checkBox_JavaSegfault = QtWidgets.QCheckBox(parent=self.page_6) self.checkBox_JavaSegfault.setObjectName("checkBox_JavaSegfault") self.gridLayout_7.addWidget(self.checkBox_JavaSegfault, 0, 0, 1, 1) - spacerItem15 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.gridLayout_7.addItem(spacerItem15, 1, 0, 1, 1) + spacerItem16 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.gridLayout_7.addItem(spacerItem16, 1, 0, 1, 1) self.stackedWidget.addWidget(self.page_6) self.horizontalLayout_2.addWidget(self.stackedWidget) self.verticalLayout.addLayout(self.horizontalLayout_2) @@ -340,8 +351,8 @@ def setupUi(self, Dialog): self.pushButton_ResetSettings = QtWidgets.QPushButton(parent=Dialog) self.pushButton_ResetSettings.setObjectName("pushButton_ResetSettings") self.horizontalLayout.addWidget(self.pushButton_ResetSettings) - spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem16) + spacerItem17 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem17) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -351,7 +362,7 @@ def setupUi(self, Dialog): self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) self.retranslateUi(Dialog) - self.stackedWidget.setCurrentIndex(0) + self.stackedWidget.setCurrentIndex(3) self.listWidget_Functions.setCurrentRow(-1) self.buttonBox.accepted.connect(Dialog.accept) # type: ignore self.buttonBox.rejected.connect(Dialog.reject) # type: ignore @@ -369,7 +380,7 @@ def retranslateUi(self, Dialog): item = self.listWidget_Options.item(2) item.setText(_translate("Dialog", "Code Injection")) item = self.listWidget_Options.item(3) - item.setText(_translate("Dialog", "Disassemble")) + item.setText(_translate("Dialog", "Memory View")) item = self.listWidget_Options.item(4) item.setText(_translate("Dialog", "Debug")) item = self.listWidget_Options.item(5) @@ -396,8 +407,10 @@ def retranslateUi(self, Dialog): self.label_5.setText(_translate("Dialog", "Code injection method:")) self.radioButton_SimpleDLopenCall.setText(_translate("Dialog", "Simp&le dlopen call")) self.radioButton_AdvancedInjection.setText(_translate("Dialog", "Advanced In&jection")) - self.checkBox_BringDisassembleToFront.setText(_translate("Dialog", "Bring disassemble screen to front when the inferior is stopped")) - self.label_6.setText(_translate("Dialog", "Instructions shown per scroll")) + self.checkBox_ShowMemoryViewOnStop.setText(_translate("Dialog", "Bring Memory View to front when the inferior is stopped")) + self.label_6.setText(_translate("Dialog", "Instructions shown per scroll in Disassembly View")) + self.label_16.setText(_translate("Dialog", "Bytes shown per scroll in Hex View")) + self.spinBox_BytesPerScroll.setPrefix(_translate("Dialog", "0x")) self.label_7.setText(_translate("Dialog", "GDB Path")) self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) self.label_15.setText(_translate("Dialog", "Interruption signal")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index 758f2082..f66c98bf 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -49,7 +49,7 @@ - Disassemble + Memory View @@ -73,7 +73,7 @@ - 0 + 3 @@ -535,27 +535,23 @@ Patterns at former positions have higher priority if regex is off - + - Bring disassemble screen to front when the inferior is stopped + Bring Memory View to front when the inferior is stopped - - - - - Instructions shown per scroll - - - - - - - + + + Instructions shown per scroll in Disassembly View + + + + + @@ -572,6 +568,46 @@ Patterns at former positions have higher priority if regex is off + + + + + + Bytes shown per scroll in Hex View + + + + + + + 0x + + + 4096 + + + 16 + + + 16 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/PINCE.py b/PINCE.py index 953da411..56c923bf 100755 --- a/PINCE.py +++ b/PINCE.py @@ -560,9 +560,10 @@ def set_default_settings(self): self.settings.beginGroup("CodeInjection") self.settings.setValue("code_injection_method", typedefs.INJECTION_METHOD.DLOPEN) self.settings.endGroup() - self.settings.beginGroup("Disassemble") - self.settings.setValue("bring_disassemble_to_front", False) + self.settings.beginGroup("MemoryView") + self.settings.setValue("show_memory_view_on_stop", False) self.settings.setValue("instructions_per_scroll", MemoryViewWindowForm.instructions_per_scroll) + self.settings.setValue("bytes_per_scroll", MemoryViewWindowForm.bytes_per_scroll) self.settings.endGroup() self.settings.beginGroup("Debug") self.settings.setValue("gdb_path", typedefs.PATHS.GDB) @@ -628,12 +629,13 @@ def apply_settings(self): except AttributeError: pass settings.code_injection_method = self.settings.value("CodeInjection/code_injection_method", type=int) - self.memory_view_window.bring_disassemble_to_front = self.settings.value( - "Disassemble/bring_disassemble_to_front", type=bool + self.memory_view_window.show_memory_view_on_stop = self.settings.value( + "MemoryView/show_memory_view_on_stop", type=bool ) self.memory_view_window.instructions_per_scroll = self.settings.value( - "Disassemble/instructions_per_scroll", type=int + "MemoryView/instructions_per_scroll", type=int ) + self.memory_view_window.bytes_per_scroll = self.settings.value("MemoryView/bytes_per_scroll", type=int) settings.gdb_path = self.settings.value("Debug/gdb_path", type=str) if debugcore.gdb_initialized: self.apply_after_init() @@ -2480,14 +2482,6 @@ def accept(self): except: QMessageBox.information(self, tr.ERROR, tr.FREEZE_ASSERT_INT) return - try: - current_instructions_shown = int(self.lineEdit_InstructionsPerScroll.text()) - except: - QMessageBox.information(self, tr.ERROR, tr.INSTRUCTION_ASSERT_INT) - return - if current_instructions_shown < 1: - QMessageBox.information(self, tr.ERROR, tr.INSTRUCTION_ASSERT_LT.format(1)) - return if not self.checkBox_AutoUpdateAddressTable.isChecked(): pass elif current_table_update_interval < 0 or current_freeze_interval < 0: @@ -2531,10 +2525,9 @@ def accept(self): elif self.radioButton_AdvancedInjection.isChecked(): injection_method = typedefs.INJECTION_METHOD.ADVANCED self.settings.setValue("CodeInjection/code_injection_method", injection_method) - self.settings.setValue( - "Disassemble/bring_disassemble_to_front", self.checkBox_BringDisassembleToFront.isChecked() - ) - self.settings.setValue("Disassemble/instructions_per_scroll", current_instructions_shown) + self.settings.setValue("MemoryView/show_memory_view_on_stop", self.checkBox_ShowMemoryViewOnStop.isChecked()) + self.settings.setValue("MemoryView/instructions_per_scroll", self.spinBox_InstructionsPerScroll.value()) + self.settings.setValue("MemoryView/bytes_per_scroll", self.spinBox_BytesPerScroll.value()) selected_gdb_path = self.lineEdit_GDBPath.text() current_gdb_path = self.settings.value("Debug/gdb_path", type=str) if selected_gdb_path != current_gdb_path: @@ -2586,12 +2579,11 @@ def config_gui(self): elif code_injection_method == typedefs.INJECTION_METHOD.ADVANCED: self.radioButton_AdvancedInjection.setChecked(True) - self.checkBox_BringDisassembleToFront.setChecked( - self.settings.value("Disassemble/bring_disassemble_to_front", type=bool) - ) - self.lineEdit_InstructionsPerScroll.setText( - str(self.settings.value("Disassemble/instructions_per_scroll", type=int)) + self.checkBox_ShowMemoryViewOnStop.setChecked( + self.settings.value("MemoryView/show_memory_view_on_stop", type=bool) ) + self.spinBox_InstructionsPerScroll.setValue(self.settings.value("MemoryView/instructions_per_scroll", type=int)) + self.spinBox_BytesPerScroll.setValue(self.settings.value("MemoryView/bytes_per_scroll", type=int)) self.lineEdit_GDBPath.setText(str(self.settings.value("Debug/gdb_path", type=str))) self.checkBox_GDBLogging.setChecked(self.settings.value("Debug/gdb_logging", type=bool)) self.comboBox_InterruptSignal.setCurrentText(self.settings.value("Debug/interrupt_signal", type=str)) @@ -2881,8 +2873,9 @@ def __init__(self, parent): class MemoryViewWindowForm(QMainWindow, MemoryViewWindow): process_stopped = pyqtSignal() process_running = pyqtSignal() - bring_disassemble_to_front: bool = False + show_memory_view_on_stop: bool = False instructions_per_scroll: int = 3 + bytes_per_scroll: int = 0x40 def set_dynamic_debug_hotkeys(self): self.actionBreak.setText(tr.BREAK.format(hotkeys.break_hotkey.get_active_key())) @@ -3261,9 +3254,9 @@ def hex_view_scrollbar_sliderchanged(self, event): # return current_address = self.hex_model.current_address if current_value < midst: - next_address = current_address - 0x40 + next_address = current_address - self.bytes_per_scroll else: - next_address = current_address + 0x40 + next_address = current_address + self.bytes_per_scroll self.hex_dump_address(next_address) guiutils.center_scroll_bar(self.verticalScrollBar_HexView) self.bHexViewScrolling = False @@ -3635,7 +3628,7 @@ def on_process_stop(self): if self.tableWidget_Stack.rowCount() == 0: self.update_stack() self.refresh_hex_view() - if self.bring_disassemble_to_front: + if self.show_memory_view_on_stop: self.showMaximized() self.activateWindow() if self.stacktrace_info_widget.isVisible(): @@ -3941,9 +3934,9 @@ def widget_HexView_wheel_event(self, event): steps = event.angleDelta() current_address = self.hex_model.current_address if steps.y() > 0: - next_address = current_address - 0x40 + next_address = current_address - self.bytes_per_scroll else: - next_address = current_address + 0x40 + next_address = current_address + self.bytes_per_scroll self.hex_dump_address(next_address) def widget_HexView_key_press_event(self, event): diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 87a927e4..388d6bcd 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -220,7 +220,7 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin - Disassemble + Memory View @@ -336,12 +336,22 @@ Patterns at former positions have higher priority if regex is off - Bring disassemble screen to front when the inferior is stopped + Bring Memory View to front when the inferior is stopped + + + + + Instructions shown per scroll in Disassembly View + + + + + Bytes shown per scroll in Hex View - Instructions shown per scroll + 0x @@ -1757,16 +1767,6 @@ To change the current GDB path, check Settings->Debug Freeze interval must be an int - - - Instruction count must be an int - - - - - Instruction count cannot be lower than {} - - Interval cannot be a negative number diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 34cbbcab..6ce20fab 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -221,8 +221,8 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin - Disassemble - 反汇编 + Memory View + 内存查看器 @@ -338,13 +338,23 @@ Patterns at former positions have higher priority if regex is off - Bring disassemble screen to front when the inferior is stopped - 在程序(inferior)停止运行时,将反汇编(disassemble)屏幕置于前台显示 + Bring Memory View to front when the inferior is stopped + + + + + Instructions shown per scroll in Disassembly View + + + + + Bytes shown per scroll in Hex View + - Instructions shown per scroll - 每次滚动时显示的指令数量 + 0x + @@ -1761,16 +1771,6 @@ To change the current GDB path, check Settings->Debug Freeze interval must be an int 冻结间隔必须是 int - - - Instruction count must be an int - 指令计数必须是 int - - - - Instruction count cannot be lower than {} - 指令计数不能低于 {} - Interval cannot be a negative number diff --git a/tr/tr.py b/tr/tr.py index db6c2c80..618a0ad9 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -121,8 +121,6 @@ def translate(): PARSE_ERROR = QT_TR_NOOP("Can't parse the input") UPDATE_ASSERT_INT = QT_TR_NOOP("Update interval must be an int") FREEZE_ASSERT_INT = QT_TR_NOOP("Freeze interval must be an int") - INSTRUCTION_ASSERT_INT = QT_TR_NOOP("Instruction count must be an int") - INSTRUCTION_ASSERT_LT = QT_TR_NOOP("Instruction count cannot be lower than {}") INTERVAL_ASSERT_NEGATIVE = QT_TR_NOOP("Interval cannot be a negative number") ASKING_FOR_TROUBLE = QT_TR_NOOP("You are asking for it, aren't you?") UPDATE_ASSERT_GT = QT_TR_NOOP( From 8df63e0ee70c0ac49128d1d197bc88eaabd63ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 4 May 2024 18:09:37 +0300 Subject: [PATCH 402/487] Convert table setting lineEdits to spinBoxes --- GUI/SettingsDialog.py | 28 ++++++++++++++-------------- GUI/SettingsDialog.ui | 35 +++++++++++++++++++++-------------- PINCE.py | 32 ++++---------------------------- i18n/ts/it_IT.ts | 32 -------------------------------- i18n/ts/zh_CN.ts | 34 ---------------------------------- tr/tr.py | 9 --------- 6 files changed, 39 insertions(+), 131 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 124ecc1b..180a41ad 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -68,9 +68,12 @@ def setupUi(self, Dialog): self.label.setMinimumSize(QtCore.QSize(102, 0)) self.label.setObjectName("label") self.horizontalLayout_UpdateInterval.addWidget(self.label) - self.lineEdit_UpdateInterval = QtWidgets.QLineEdit(parent=self.QWidget_UpdateInterval) - self.lineEdit_UpdateInterval.setObjectName("lineEdit_UpdateInterval") - self.horizontalLayout_UpdateInterval.addWidget(self.lineEdit_UpdateInterval) + self.spinBox_UpdateInterval = QtWidgets.QSpinBox(parent=self.QWidget_UpdateInterval) + self.spinBox_UpdateInterval.setMinimum(100) + self.spinBox_UpdateInterval.setMaximum(10000) + self.spinBox_UpdateInterval.setSingleStep(100) + self.spinBox_UpdateInterval.setObjectName("spinBox_UpdateInterval") + self.horizontalLayout_UpdateInterval.addWidget(self.spinBox_UpdateInterval) self.label_2 = QtWidgets.QLabel(parent=self.QWidget_UpdateInterval) self.label_2.setText("ms") self.label_2.setObjectName("label_2") @@ -91,15 +94,12 @@ def setupUi(self, Dialog): self.label_12.setBaseSize(QtCore.QSize(0, 0)) self.label_12.setObjectName("label_12") self.horizontalLayout_14.addWidget(self.label_12) - self.lineEdit_FreezeInterval = QtWidgets.QLineEdit(parent=self.LockInterval) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEdit_FreezeInterval.sizePolicy().hasHeightForWidth()) - self.lineEdit_FreezeInterval.setSizePolicy(sizePolicy) - self.lineEdit_FreezeInterval.setBaseSize(QtCore.QSize(20, 0)) - self.lineEdit_FreezeInterval.setObjectName("lineEdit_FreezeInterval") - self.horizontalLayout_14.addWidget(self.lineEdit_FreezeInterval) + self.spinBox_FreezeInterval = QtWidgets.QSpinBox(parent=self.LockInterval) + self.spinBox_FreezeInterval.setMinimum(100) + self.spinBox_FreezeInterval.setMaximum(10000) + self.spinBox_FreezeInterval.setSingleStep(100) + self.spinBox_FreezeInterval.setObjectName("spinBox_FreezeInterval") + self.horizontalLayout_14.addWidget(self.spinBox_FreezeInterval) self.label_10 = QtWidgets.QLabel(parent=self.LockInterval) self.label_10.setText("ms") self.label_10.setObjectName("label_10") @@ -275,6 +275,7 @@ def setupUi(self, Dialog): self.label_16.setObjectName("label_16") self.horizontalLayout_19.addWidget(self.label_16) self.spinBox_BytesPerScroll = QtWidgets.QSpinBox(parent=self.page_4) + self.spinBox_BytesPerScroll.setPrefix("0x") self.spinBox_BytesPerScroll.setMaximum(4096) self.spinBox_BytesPerScroll.setSingleStep(16) self.spinBox_BytesPerScroll.setDisplayIntegerBase(16) @@ -362,7 +363,7 @@ def setupUi(self, Dialog): self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) self.retranslateUi(Dialog) - self.stackedWidget.setCurrentIndex(3) + self.stackedWidget.setCurrentIndex(0) self.listWidget_Functions.setCurrentRow(-1) self.buttonBox.accepted.connect(Dialog.accept) # type: ignore self.buttonBox.rejected.connect(Dialog.reject) # type: ignore @@ -410,7 +411,6 @@ def retranslateUi(self, Dialog): self.checkBox_ShowMemoryViewOnStop.setText(_translate("Dialog", "Bring Memory View to front when the inferior is stopped")) self.label_6.setText(_translate("Dialog", "Instructions shown per scroll in Disassembly View")) self.label_16.setText(_translate("Dialog", "Bytes shown per scroll in Hex View")) - self.spinBox_BytesPerScroll.setPrefix(_translate("Dialog", "0x")) self.label_7.setText(_translate("Dialog", "GDB Path")) self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) self.label_15.setText(_translate("Dialog", "Interruption signal")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index f66c98bf..ab0c5bc5 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -73,7 +73,7 @@ - 3 + 0 @@ -114,7 +114,17 @@ - + + + 100 + + + 10000 + + + 100 + + @@ -158,18 +168,15 @@ - - - - 0 - 0 - + + + 100 - - - 20 - 0 - + + 10000 + + + 100 @@ -580,7 +587,7 @@ Patterns at former positions have higher priority if regex is off - 0x + 0x 4096 diff --git a/PINCE.py b/PINCE.py index 56c923bf..0f110c54 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2472,32 +2472,10 @@ def __init__(self, parent, set_default_settings_func): guiutils.center_to_parent(self) def accept(self): - try: - current_table_update_interval = int(self.lineEdit_UpdateInterval.text()) - except: - QMessageBox.information(self, tr.ERROR, tr.UPDATE_ASSERT_INT) - return - try: - current_freeze_interval = int(self.lineEdit_FreezeInterval.text()) - except: - QMessageBox.information(self, tr.ERROR, tr.FREEZE_ASSERT_INT) - return - if not self.checkBox_AutoUpdateAddressTable.isChecked(): - pass - elif current_table_update_interval < 0 or current_freeze_interval < 0: - QMessageBox.information(self, tr.ERROR, tr.INTERVAL_ASSERT_NEGATIVE) - return - elif current_table_update_interval == 0 or current_freeze_interval == 0: - if not InputDialogForm(self, [(tr.ASKING_FOR_TROUBLE,)]).exec(): # Easter egg - return - elif current_table_update_interval < 100: - if not InputDialogForm(self, [(tr.UPDATE_ASSERT_GT.format(100),)]).exec(): - return - self.settings.setValue("General/auto_update_address_table", self.checkBox_AutoUpdateAddressTable.isChecked()) if self.checkBox_AutoUpdateAddressTable.isChecked(): - self.settings.setValue("General/address_table_update_interval", current_table_update_interval) - self.settings.setValue("General/freeze_interval", current_freeze_interval) + self.settings.setValue("General/address_table_update_interval", self.spinBox_UpdateInterval.value()) + self.settings.setValue("General/freeze_interval", self.spinBox_FreezeInterval.value()) output_mode = [ self.checkBox_OutputModeAsync.isChecked(), self.checkBox_OutputModeCommand.isChecked(), @@ -2552,10 +2530,8 @@ def config_gui(self): self.checkBox_AutoUpdateAddressTable.setChecked( self.settings.value("General/auto_update_address_table", type=bool) ) - self.lineEdit_UpdateInterval.setText( - str(self.settings.value("General/address_table_update_interval", type=int)) - ) - self.lineEdit_FreezeInterval.setText(str(self.settings.value("General/freeze_interval", type=int))) + self.spinBox_UpdateInterval.setValue(self.settings.value("General/address_table_update_interval", type=int)) + self.spinBox_FreezeInterval.setValue(self.settings.value("General/freeze_interval", type=int)) output_mode = json.loads(self.settings.value("General/gdb_output_mode", type=str)) output_mode = typedefs.gdb_output_mode(*output_mode) self.checkBox_OutputModeAsync.setChecked(output_mode.async_output) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 388d6bcd..fe2219a7 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -349,11 +349,6 @@ Patterns at former positions have higher priority if regex is off Bytes shown per scroll in Hex View - - - 0x - - GDB Path @@ -1757,33 +1752,6 @@ To change the current GDB path, check Settings->Debug Can't parse the input - - - Update interval must be an int - - - - - Freeze interval must be an int - - - - - Interval cannot be a negative number - - - - - You are asking for it, aren't you? - - - - - Update interval should be bigger than {} ms -Setting update interval less than {} ms may cause slowdown -Proceed? - - {} isn't a valid regex diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 6ce20fab..130e8b47 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -351,11 +351,6 @@ Patterns at former positions have higher priority if regex is off Bytes shown per scroll in Hex View - - - 0x - - GDB Path @@ -1761,35 +1756,6 @@ To change the current GDB path, check Settings->Debug Can't parse the input 无法解析输入 - - - Update interval must be an int - 更新间隔必须是 int - - - - Freeze interval must be an int - 冻结间隔必须是 int - - - - Interval cannot be a negative number - 间隔不能为负数 - - - - You are asking for it, aren't you? - 这是你自找的,不是吗? - - - - Update interval should be bigger than {} ms -Setting update interval less than {} ms may cause slowdown -Proceed? - 更新间隔应大于 {} 毫秒 -将更新间隔设置为小于 {} 毫秒可能会导致速度变慢 -继续? - {} isn't a valid regex diff --git a/tr/tr.py b/tr/tr.py index 618a0ad9..4deda6b1 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -119,15 +119,6 @@ def translate(): LENGTH_NOT_VALID = QT_TR_NOOP("Length is not valid") LENGTH_GT = QT_TR_NOOP("Length must be greater than 0") PARSE_ERROR = QT_TR_NOOP("Can't parse the input") - UPDATE_ASSERT_INT = QT_TR_NOOP("Update interval must be an int") - FREEZE_ASSERT_INT = QT_TR_NOOP("Freeze interval must be an int") - INTERVAL_ASSERT_NEGATIVE = QT_TR_NOOP("Interval cannot be a negative number") - ASKING_FOR_TROUBLE = QT_TR_NOOP("You are asking for it, aren't you?") - UPDATE_ASSERT_GT = QT_TR_NOOP( - "Update interval should be bigger than {} ms\n" - "Setting update interval less than {} ms may cause slowdown\n" - "Proceed?" - ) IS_INVALID_REGEX = QT_TR_NOOP("{} isn't a valid regex") LANG_RESET = QT_TR_NOOP("Language settings will take effect upon the next restart") GDB_RESET = QT_TR_NOOP("You have changed the GDB path, reset GDB now?") From 094645ffc3b12131d527826cc0ebc493d620f1a0 Mon Sep 17 00:00:00 2001 From: Bastian Ebiko Jesuiter Date: Fri, 10 May 2024 16:56:39 +0200 Subject: [PATCH 403/487] Multiple Changes (#254) Add Monospace Font and other QoL changes - potentially fix oversized address column in hex view ( Bug via Discord ) - Improve HexView: - Monospace Font - caps hex (0xASDF) - ascii view more compact - ascii view now turning non-printable chars into . - improve other parts by - adding monospace font (registers, dissassembler) --- .vscode/settings.json | 3 +- GUI/AbstractTableModels/HexModel.py | 4 +- GUI/MemoryViewerWindow.py | 73 ++++++++++++++++- GUI/MemoryViewerWindow.ui | 83 +++++++++++++++++++- GUI/TableViews/AsciiView.py | 6 +- GUI/TableViews/HexView.py | 6 +- PINCE.py | 18 ++--- libpince/debugcore.py | 2 +- libpince/gdb_python_scripts/gdbextensions.py | 2 + libpince/utils.py | 25 +++--- 10 files changed, 186 insertions(+), 36 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2fcd2bbd..945f0dd4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,6 @@ }, "black-formatter.args": [ "--line-length=120" - ] + ], + "editor.tabSize": 4 } diff --git a/GUI/AbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py index 835dc6eb..83ee0917 100644 --- a/GUI/AbstractTableModels/HexModel.py +++ b/GUI/AbstractTableModels/HexModel.py @@ -88,9 +88,9 @@ def update_loop(self, updated_array): self.data_array = updated_array self.layoutChanged.emit() - def update_index(self, index, data): + def update_index(self, index: int, data: str): data = self.translate_data(data) if self.data_array[index] != data: self.cell_animation[index] = 6 - self.data_array[index] = data + self.data_array[index] = utils.upper_hex(data) self.layoutChanged.emit() diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index ed106722..389fecf0 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MemoryViewerWindow.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.6.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -38,6 +38,7 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_2.setObjectName("gridLayout_2") self.tableWidget_Disassemble = QtWidgets.QTableWidget(parent=self.widget_Disassemble) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.tableWidget_Disassemble.setFont(font) self.tableWidget_Disassemble.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) @@ -72,6 +73,9 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_2.addWidget(self.verticalScrollBar_Disassemble, 0, 1, 1, 1) self.widget_Registers = QtWidgets.QWidget(parent=self.splitter_Disassemble_Registers) self.widget_Registers.setMinimumSize(QtCore.QSize(0, 0)) + font = QtGui.QFont() + font.setFamily("Monospace") + self.widget_Registers.setFont(font) self.widget_Registers.setObjectName("widget_Registers") self.gridLayout_4 = QtWidgets.QGridLayout(self.widget_Registers) self.gridLayout_4.setContentsMargins(0, 0, 0, 0) @@ -81,7 +85,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Registers.setWidgetResizable(True) self.scrollArea_Registers.setObjectName("scrollArea_Registers") self.scrollAreaWidgetContents_Registers = QtWidgets.QWidget() - self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 336, 342)) + self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 335, 330)) self.scrollAreaWidgetContents_Registers.setObjectName("scrollAreaWidgetContents_Registers") self.gridLayout_8 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_Registers) self.gridLayout_8.setContentsMargins(0, 0, 0, 0) @@ -95,6 +99,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_19.setObjectName("verticalLayout_19") self.label_3 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_3.setFont(font) self.label_3.setObjectName("label_3") @@ -130,6 +135,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.setObjectName("verticalLayout_16") self.RAX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RAX.setFont(font) self.RAX.setText("RAX=") @@ -137,6 +143,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.addWidget(self.RAX) self.RBX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RBX.setFont(font) self.RBX.setText("RBX=") @@ -144,6 +151,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.addWidget(self.RBX) self.RCX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RCX.setFont(font) self.RCX.setText("RCX=") @@ -151,6 +159,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.addWidget(self.RCX) self.RDX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RDX.setFont(font) self.RDX.setText("RDX=") @@ -158,6 +167,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.addWidget(self.RDX) self.RSI = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RSI.setFont(font) self.RSI.setText("RSI=") @@ -165,6 +175,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.addWidget(self.RSI) self.RDI = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RDI.setFont(font) self.RDI.setText("RDI=") @@ -172,6 +183,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.addWidget(self.RDI) self.RBP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RBP.setFont(font) self.RBP.setText("RBP=") @@ -179,6 +191,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_16.addWidget(self.RBP) self.RSP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RSP.setFont(font) self.RSP.setText("RSP=") @@ -192,6 +205,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.setObjectName("verticalLayout_3") self.R8 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R8.setFont(font) self.R8.setText("R8=") @@ -199,6 +213,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.addWidget(self.R8) self.R9 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R9.setFont(font) self.R9.setText("R9=") @@ -206,6 +221,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.addWidget(self.R9) self.R10 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R10.setFont(font) self.R10.setText("R10=") @@ -213,6 +229,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.addWidget(self.R10) self.R11 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R11.setFont(font) self.R11.setText("R11=") @@ -220,6 +237,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.addWidget(self.R11) self.R12 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R12.setFont(font) self.R12.setText("R12=") @@ -227,6 +245,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.addWidget(self.R12) self.R13 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R13.setFont(font) self.R13.setText("R13=") @@ -234,6 +253,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.addWidget(self.R13) self.R14 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R14.setFont(font) self.R14.setText("R14=") @@ -241,6 +261,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_3.addWidget(self.R14) self.R15 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.R15.setFont(font) self.R15.setText("R15=") @@ -253,6 +274,7 @@ def setupUi(self, MainWindow_MemoryView): self.horizontalLayout_18.setObjectName("horizontalLayout_18") self.RIP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.RIP.setFont(font) self.RIP.setText("RIP=") @@ -282,6 +304,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.setObjectName("verticalLayout_2") self.EAX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.EAX.setFont(font) self.EAX.setText("EAX=") @@ -289,6 +312,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.EAX) self.EBX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.EBX.setFont(font) self.EBX.setText("EBX=") @@ -296,6 +320,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.EBX) self.ECX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.ECX.setFont(font) self.ECX.setText("ECX=") @@ -303,6 +328,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.ECX) self.EDX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.EDX.setFont(font) self.EDX.setText("EDX=") @@ -310,6 +336,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.EDX) self.ESI = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.ESI.setFont(font) self.ESI.setText("ESI=") @@ -317,6 +344,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.ESI) self.EDI = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.EDI.setFont(font) self.EDI.setText("EDI=") @@ -324,6 +352,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.EDI) self.EBP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.EBP.setFont(font) self.EBP.setText("EBP=") @@ -331,6 +360,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.EBP) self.ESP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.ESP.setFont(font) self.ESP.setText("ESP=") @@ -338,6 +368,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_2.addWidget(self.ESP) self.EIP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.EIP.setFont(font) self.EIP.setText("EIP=") @@ -352,6 +383,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_19.addWidget(self.stackedWidget) self.label_29 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_29.setFont(font) self.label_29.setObjectName("label_29") @@ -369,6 +401,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_5.setObjectName("verticalLayout_5") self.label_31 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_31.setFont(font) self.label_31.setText("CF") @@ -376,6 +409,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_5.addWidget(self.label_31) self.CF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.CF.setFont(font) self.CF.setText("0") @@ -387,6 +421,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_6.setObjectName("verticalLayout_6") self.label_35 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_35.setFont(font) self.label_35.setText("PF") @@ -394,6 +429,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_6.addWidget(self.label_35) self.PF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.PF.setFont(font) self.PF.setText("0") @@ -405,6 +441,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_7.setObjectName("verticalLayout_7") self.label_37 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_37.setFont(font) self.label_37.setText("AF") @@ -412,6 +449,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_7.addWidget(self.label_37) self.AF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.AF.setFont(font) self.AF.setText("0") @@ -423,6 +461,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_8.setObjectName("verticalLayout_8") self.label_39 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_39.setFont(font) self.label_39.setText("ZF") @@ -430,6 +469,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_8.addWidget(self.label_39) self.ZF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.ZF.setFont(font) self.ZF.setText("0") @@ -441,6 +481,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_9.setObjectName("verticalLayout_9") self.label_41 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_41.setFont(font) self.label_41.setText("SF") @@ -448,6 +489,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_9.addWidget(self.label_41) self.SF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.SF.setFont(font) self.SF.setText("0") @@ -459,6 +501,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_10.setObjectName("verticalLayout_10") self.label_43 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_43.setFont(font) self.label_43.setText("TF") @@ -466,6 +509,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_10.addWidget(self.label_43) self.TF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.TF.setFont(font) self.TF.setText("0") @@ -477,6 +521,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_11.setObjectName("verticalLayout_11") self.label_45 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_45.setFont(font) self.label_45.setText("IF") @@ -484,6 +529,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_11.addWidget(self.label_45) self.IF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.IF.setFont(font) self.IF.setText("0") @@ -495,6 +541,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_12.setObjectName("verticalLayout_12") self.label_47 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_47.setFont(font) self.label_47.setText("DF") @@ -502,6 +549,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_12.addWidget(self.label_47) self.DF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.DF.setFont(font) self.DF.setText("0") @@ -513,6 +561,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_13.setObjectName("verticalLayout_13") self.label_49 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_49.setFont(font) self.label_49.setText("OF") @@ -520,6 +569,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_13.addWidget(self.label_49) self.OF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.OF.setFont(font) self.OF.setText("0") @@ -531,6 +581,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_19.addItem(spacerItem4) self.label_30 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.label_30.setFont(font) self.label_30.setObjectName("label_30") @@ -548,6 +599,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_4.setObjectName("verticalLayout_4") self.CS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.CS.setFont(font) self.CS.setText("CS=") @@ -555,6 +607,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_4.addWidget(self.CS) self.ES = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.ES.setFont(font) self.ES.setText("ES=") @@ -568,6 +621,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_15.setObjectName("verticalLayout_15") self.SS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.SS.setFont(font) self.SS.setText("SS=") @@ -575,6 +629,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_15.addWidget(self.SS) self.GS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.GS.setFont(font) self.GS.setText("GS=") @@ -588,6 +643,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_18.setObjectName("verticalLayout_18") self.DS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.DS.setFont(font) self.DS.setText("DS=") @@ -595,6 +651,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_18.addWidget(self.DS) self.FS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.FS.setFont(font) self.FS.setText("FS=") @@ -604,6 +661,7 @@ def setupUi(self, MainWindow_MemoryView): self.verticalLayout_19.addLayout(self.horizontalLayout_2) self.pushButton_ShowFloatRegisters = QtWidgets.QPushButton(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() + font.setFamily("Monospace") font.setPointSize(9) self.pushButton_ShowFloatRegisters.setFont(font) self.pushButton_ShowFloatRegisters.setObjectName("pushButton_ShowFloatRegisters") @@ -631,7 +689,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Hex.setWidgetResizable(True) self.scrollArea_Hex.setObjectName("scrollArea_Hex") self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() - self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 524, 200)) + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 492, 212)) self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") self.gridLayout_11 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) self.gridLayout_11.setContentsMargins(0, 0, 0, 0) @@ -641,6 +699,9 @@ def setupUi(self, MainWindow_MemoryView): self.horizontalLayout_5.setSpacing(0) self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.tableWidget_HexView_Address = QtWidgets.QTableWidget(parent=self.scrollAreaWidgetContents_2) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_HexView_Address.setFont(font) self.tableWidget_HexView_Address.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_HexView_Address.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_HexView_Address.setShowGrid(False) @@ -658,6 +719,9 @@ def setupUi(self, MainWindow_MemoryView): self.line_5.setObjectName("line_5") self.horizontalLayout_5.addWidget(self.line_5) self.tableView_HexView_Hex = QHexView(parent=self.scrollAreaWidgetContents_2) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableView_HexView_Hex.setFont(font) self.tableView_HexView_Hex.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) self.tableView_HexView_Hex.setObjectName("tableView_HexView_Hex") self.horizontalLayout_5.addWidget(self.tableView_HexView_Hex) @@ -667,6 +731,9 @@ def setupUi(self, MainWindow_MemoryView): self.line_4.setObjectName("line_4") self.horizontalLayout_5.addWidget(self.line_4) self.tableView_HexView_Ascii = QAsciiView(parent=self.scrollAreaWidgetContents_2) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableView_HexView_Ascii.setFont(font) self.tableView_HexView_Ascii.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) self.tableView_HexView_Ascii.setObjectName("tableView_HexView_Ascii") self.horizontalLayout_5.addWidget(self.tableView_HexView_Ascii) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 77a54877..c834739c 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -75,6 +75,7 @@ + Monospace 9 @@ -158,6 +159,11 @@ 0 + + + Monospace + + 0 @@ -184,8 +190,8 @@ 0 0 - 336 - 342 + 335 + 330 @@ -218,6 +224,7 @@ + Monospace 9 @@ -292,6 +299,7 @@ + Monospace 9 @@ -304,6 +312,7 @@ + Monospace 9 @@ -316,6 +325,7 @@ + Monospace 9 @@ -328,6 +338,7 @@ + Monospace 9 @@ -340,6 +351,7 @@ + Monospace 9 @@ -352,6 +364,7 @@ + Monospace 9 @@ -364,6 +377,7 @@ + Monospace 9 @@ -376,6 +390,7 @@ + Monospace 9 @@ -408,6 +423,7 @@ + Monospace 9 @@ -420,6 +436,7 @@ + Monospace 9 @@ -432,6 +449,7 @@ + Monospace 9 @@ -444,6 +462,7 @@ + Monospace 9 @@ -456,6 +475,7 @@ + Monospace 9 @@ -468,6 +488,7 @@ + Monospace 9 @@ -480,6 +501,7 @@ + Monospace 9 @@ -492,6 +514,7 @@ + Monospace 9 @@ -513,6 +536,7 @@ + Monospace 9 @@ -589,6 +613,7 @@ + Monospace 9 @@ -601,6 +626,7 @@ + Monospace 9 @@ -613,6 +639,7 @@ + Monospace 9 @@ -625,6 +652,7 @@ + Monospace 9 @@ -637,6 +665,7 @@ + Monospace 9 @@ -649,6 +678,7 @@ + Monospace 9 @@ -661,6 +691,7 @@ + Monospace 9 @@ -673,6 +704,7 @@ + Monospace 9 @@ -685,6 +717,7 @@ + Monospace 9 @@ -720,6 +753,7 @@ + Monospace 9 @@ -749,6 +783,7 @@ + Monospace 9 @@ -761,6 +796,7 @@ + Monospace 9 @@ -780,6 +816,7 @@ + Monospace 9 @@ -792,6 +829,7 @@ + Monospace 9 @@ -811,6 +849,7 @@ + Monospace 9 @@ -823,6 +862,7 @@ + Monospace 9 @@ -842,6 +882,7 @@ + Monospace 9 @@ -854,6 +895,7 @@ + Monospace 9 @@ -873,6 +915,7 @@ + Monospace 9 @@ -885,6 +928,7 @@ + Monospace 9 @@ -904,6 +948,7 @@ + Monospace 9 @@ -916,6 +961,7 @@ + Monospace 9 @@ -935,6 +981,7 @@ + Monospace 9 @@ -947,6 +994,7 @@ + Monospace 9 @@ -966,6 +1014,7 @@ + Monospace 9 @@ -978,6 +1027,7 @@ + Monospace 9 @@ -997,6 +1047,7 @@ + Monospace 9 @@ -1009,6 +1060,7 @@ + Monospace 9 @@ -1041,6 +1093,7 @@ + Monospace 9 @@ -1070,6 +1123,7 @@ + Monospace 9 @@ -1082,6 +1136,7 @@ + Monospace 9 @@ -1114,6 +1169,7 @@ + Monospace 9 @@ -1126,6 +1182,7 @@ + Monospace 9 @@ -1158,6 +1215,7 @@ + Monospace 9 @@ -1170,6 +1228,7 @@ + Monospace 9 @@ -1186,6 +1245,7 @@ + Monospace 9 @@ -1268,8 +1328,8 @@ 0 0 - 524 - 200 + 492 + 212 @@ -1295,6 +1355,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -1326,6 +1391,11 @@ + + + Monospace + + QAbstractScrollArea::AdjustToContents @@ -1340,6 +1410,11 @@ + + + Monospace + + QAbstractScrollArea::AdjustToContents diff --git a/GUI/TableViews/AsciiView.py b/GUI/TableViews/AsciiView.py index d1f9fef5..291c58bc 100644 --- a/GUI/TableViews/AsciiView.py +++ b/GUI/TableViews/AsciiView.py @@ -23,8 +23,10 @@ class QAsciiView(QHexView): def __init__(self, parent=None): super().__init__(parent) - self.horizontalHeader().setMinimumSectionSize(15) - self.horizontalHeader().setDefaultSectionSize(15) + # 12 is minimum size with current font, otherwise it will be cut off + self.horizontalHeader().setMinimumSectionSize(12) + self.horizontalHeader().setDefaultSectionSize(12) + self.horizontalHeader().setMaximumSectionSize(12) self.write_type = typedefs.VALUE_INDEX.STRING_UTF8 self.delegate = QHexDelegate(1, ".+") self.delegate.closeEditor.connect(self.on_editor_close) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index d9cb753b..b4b8a46d 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -30,8 +30,10 @@ def __init__(self, parent=None): self.verticalHeader().setVisible(False) self.verticalHeader().setMinimumSectionSize(21) self.verticalHeader().setDefaultSectionSize(21) + self.verticalHeader().setMaximumSectionSize(21) self.horizontalHeader().setMinimumSectionSize(25) self.horizontalHeader().setDefaultSectionSize(25) + self.horizontalHeader().setMaximumSectionSize(25) self.setStyleSheet("QTableView {background-color: transparent;}") self.setShowGrid(False) self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked) @@ -65,10 +67,12 @@ def resize_to_contents(self): self.setMaximumWidth(size) def on_editor_close(self): + if not self.delegate.editor.isModified(): + return model: QHexModel = self.model() cell = self.currentIndex() index = cell.row() * model.columnCount() + cell.column() address = utils.modulo_address(model.current_address + index, debugcore.inferior_arch) - data = self.delegate.editor.text() + data = self.delegate.editor.text().upper() debugcore.write_memory(address, self.write_type, data, False) model.update_index(index, data) diff --git a/PINCE.py b/PINCE.py index 0f110c54..d2a4d40c 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1999,12 +1999,12 @@ def removeOffsetLayout(self): def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult): if pointer_chain_result != None: - base_deref = hex(pointer_chain_result.pointer_chain[0]).upper().replace("X", "x") + base_deref = utils.upper_hex(hex(pointer_chain_result.pointer_chain[0])) self.label_BaseAddressDeref.setText(f" → {base_deref}") for index, offsetFrame in enumerate(self.offsetsList): previousDerefText = self.caps_hex_or_error_indicator(pointer_chain_result.pointer_chain[index]) currentDerefText = self.caps_hex_or_error_indicator(pointer_chain_result.pointer_chain[index + 1]) - offsetText = self.caps_hex(offsetFrame.offsetText.text()) + offsetText = self.upper_hex(offsetFrame.offsetText.text()) operationalSign = "" if offsetText.startswith("-") else "+" calculation = f"{previousDerefText}{operationalSign}{offsetText}" if index != len(self.offsetsList) - 1: @@ -2019,10 +2019,7 @@ def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult) def caps_hex_or_error_indicator(self, address: int): if address == 0: return "??" - return self.caps_hex(hex(address)) - - def caps_hex(self, hex_str: str): - return hex_str.upper().replace("X", "x") + return utils.upper_hex(hex(address)) def update_value(self): if self.checkBox_IsPointer.isChecked(): @@ -3023,6 +3020,9 @@ def initialize_hex_view(self): self.tableWidget_HexView_Address.verticalHeader().setDefaultSectionSize( self.tableView_HexView_Hex.verticalHeader().defaultSectionSize() ) + self.tableWidget_HexView_Address.verticalHeader().setMaximumSectionSize( + self.tableView_HexView_Hex.verticalHeader().maximumSectionSize() + ) self.hex_update_timer = QTimer(timeout=self.hex_update_loop) self.hex_update_timer.start(200) @@ -3391,7 +3391,7 @@ def hex_dump_address(self, int_address, offset=HEX_VIEW_ROW_COUNT * HEX_VIEW_COL self.tableWidget_HexView_Address.setRowCount(HEX_VIEW_ROW_COUNT * HEX_VIEW_COL_COUNT) for row, current_offset in enumerate(range(HEX_VIEW_ROW_COUNT)): row_address = hex(utils.modulo_address(int_address + current_offset * 16, debugcore.inferior_arch)) - self.tableWidget_HexView_Address.setItem(row, 0, QTableWidgetItem(row_address)) + self.tableWidget_HexView_Address.setItem(row, 0, QTableWidgetItem(utils.upper_hex(row_address))) tableWidget_HexView_column_size = self.tableWidget_HexView_Address.sizeHintForColumn(0) + 5 self.tableWidget_HexView_Address.setMaximumWidth(tableWidget_HexView_column_size) self.tableWidget_HexView_Address.setMinimumWidth(tableWidget_HexView_column_size) @@ -5311,7 +5311,7 @@ def lineEdit_HexView_text_edited(self): return aob_array = aob_string.split() try: - self.lineEdit_AsciiView.setText(utils.aob_to_str(aob_array, "utf-8")) + self.lineEdit_AsciiView.setText(utils.aob_to_str(aob_array, "utf-8", replace_unprintable=False)) self.lineEdit_HexView.setStyleSheet("") # This should set background color back to QT default except ValueError: self.lineEdit_HexView.setStyleSheet("QLineEdit {background-color: rgba(255, 0, 0, 96);}") @@ -5337,7 +5337,7 @@ def refresh_view(self): except ValueError: return aob_array = debugcore.hex_dump(address, length) - ascii_str = utils.aob_to_str(aob_array, "utf-8") + ascii_str = utils.aob_to_str(aob_array, "utf-8", replace_unprintable=False) self.lineEdit_AsciiView.setText(ascii_str) self.lineEdit_HexView.setText(" ".join(aob_array)) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 68758f89..ecf84678 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1375,7 +1375,7 @@ def hex_dump(address, offset): FILE.seek(1, io.SEEK_CUR) # Necessary since read() failed to execute except (OSError, ValueError): pass - hex_byte_list.append(current_item) + hex_byte_list.append(utils.upper_hex(current_item)) return hex_byte_list diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 4196a96e..76ade117 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -114,6 +114,8 @@ def __init__(self): def invoke(self, arg, from_tty): registers = gdbutils.get_general_registers() + for key, value in registers.items(): + registers[key] = utils.upper_hex(value) registers.update(gdbutils.get_flag_registers()) registers.update(gdbutils.get_segment_registers()) send_to_pince(registers) diff --git a/libpince/utils.py b/libpince/utils.py index cb96ddf2..88ec9112 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -740,12 +740,13 @@ def assemble(instructions, address, inferior_arch): #:tag:ValueType -def aob_to_str(list_of_bytes, encoding="ascii"): +def aob_to_str(list_of_bytes, encoding="ascii", replace_unprintable=True): """Converts given array of hex strings to str Args: list_of_bytes (list): Must be returned from debugcore.hex_dump() encoding (str): See here-->https://docs.python.org/3/library/codecs.html#standard-encodings + replace_unprintable (bool): If True, replaces non-printable characters with a period (.) Returns: str: str equivalent of array @@ -767,18 +768,10 @@ def aob_to_str(list_of_bytes, encoding="ascii"): byte = sByte else: byte = int(sByte, 16) - """NOTE: replacing non-printable chars with a period will - have an adverse effect on the ability to edit hex/ASCII data - since the editor dialog will replace the hex bytes with 2e rather - than replacing only the edited bytes. - - So for now, don't replace them -- but be aware that this clutters - the ascii text in the memory view and does not look 'neat' - """ - # if ( (byte < 32) or (byte > 126) ): - # hexString += f'{46:02x}' # replace non-printable chars with a period (.) - # else: - hexString += f"{byte:02x}" + if replace_unprintable and ((byte < 32) or (byte > 126)): + hexString += f"{46:02x}" # replace non-printable chars with a period (.) + else: + hexString += f"{byte:02x}" hexBytes = bytes.fromhex(hexString) return hexBytes.decode(encoding, "surrogateescape") @@ -1189,3 +1182,9 @@ def wrapper(*args, **kwargs): traceback.print_exc() return wrapper + + +#:tag:Utilities +def upper_hex(hex_str: str): + """Converts the given hex string to uppercase while keeping the 'x' character lowercase""" + return hex_str.upper().replace("X", "x") From 330558f70278ff1a948ffe706eba186990cbcd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 10 May 2024 23:13:03 +0300 Subject: [PATCH 404/487] Fix case inconsistency in HexEditDialog --- GUI/AbstractTableModels/HexModel.py | 2 +- libpince/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GUI/AbstractTableModels/HexModel.py b/GUI/AbstractTableModels/HexModel.py index 83ee0917..70738269 100644 --- a/GUI/AbstractTableModels/HexModel.py +++ b/GUI/AbstractTableModels/HexModel.py @@ -92,5 +92,5 @@ def update_index(self, index: int, data: str): data = self.translate_data(data) if self.data_array[index] != data: self.cell_animation[index] = 6 - self.data_array[index] = utils.upper_hex(data) + self.data_array[index] = data self.layoutChanged.emit() diff --git a/libpince/utils.py b/libpince/utils.py index 88ec9112..0eb0d6eb 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -787,7 +787,7 @@ def str_to_aob(string, encoding="ascii"): Returns: str: AoB equivalent of the given string """ - s = str(binascii.hexlify(string.encode(encoding, "surrogateescape")), encoding) + s = str(binascii.hexlify(string.encode(encoding, "surrogateescape")), encoding).upper() return " ".join(s[i : i + 2] for i in range(0, len(s), 2)) From c9c58ca80d60f340e7995f27d24e3393dbf5691e Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 11 May 2024 02:38:18 +0100 Subject: [PATCH 405/487] Update libscanmem to newest commit --- ci/package.sh | 5 ++--- install_pince.sh | 10 +++++----- libscanmem-PINCE | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ci/package.sh b/ci/package.sh index f5704724..4dbe86d3 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -87,10 +87,9 @@ if [ ! -d "libpince/libscanmem" ]; then mkdir libpince/libscanmem fi cd libscanmem-PINCE -sh autogen.sh -./configure --prefix="$(pwd)" +cmake -DCMAKE_BUILD_TYPE=Release . make -j"$NUM_MAKE_JOBS" -cp --preserve .libs/libscanmem.so ../libpince/libscanmem +cp --preserve libscanmem.so ../libpince/libscanmem cp --preserve wrappers/scanmem.py ../libpince/libscanmem cd .. diff --git a/install_pince.sh b/install_pince.sh index 542fe32d..eed2cab4 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -57,8 +57,7 @@ exit_on_error() { # assumes you're in libscanmem directory compile_libscanmem() { - sh autogen.sh || return 1 - ./configure --prefix="$(pwd)" || return 1 + cmake -DCMAKE_BUILD_TYPE=Release . || return 1 make -j"$NUM_MAKE_JOBS" || return 1 chown -R "${CURRENT_USER}":"${CURRENT_USER}" . # give permissions for normal user to change file return 0 @@ -75,16 +74,17 @@ install_libscanmem() { ( echo "Entering libscanmem directory" cd libscanmem-PINCE || return 1 - if [ -d "./.libs" ]; then + if [ -f "./libscanmem.so" ]; then echo "Recompile libscanmem? [y/n]" read -r answer if echo "$answer" | grep -iq "^[Yy]"; then + make clean compile_libscanmem || return 1 fi else compile_libscanmem || return 1 fi - cp --preserve .libs/libscanmem.so ../libpince/libscanmem/ + cp --preserve libscanmem.so ../libpince/libscanmem/ cp --preserve wrappers/scanmem.py ../libpince/libscanmem echo "Exiting libscanmem directory" ) || return 1 @@ -126,7 +126,7 @@ ask_pkg_mgr() { } # About xcb packages -> https://github.com/cdgriffith/FastFlix/wiki/Common-questions-and-problems -PKG_NAMES_ALL="python3-pip gdb libtool" +PKG_NAMES_ALL="python3-pip gdb" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-dev python3-venv pkg-config qt6-l10n-tools libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" diff --git a/libscanmem-PINCE b/libscanmem-PINCE index fadbda39..10b325df 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit fadbda39cc9766ccaa80e1bc8aed4876e7107c53 +Subproject commit 10b325df2314bbdd0f3c475fdbf9e6c080fb7861 From db989c0727315bb6e283426964ac6863243f78c4 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 11 May 2024 02:47:54 +0100 Subject: [PATCH 406/487] Add CMake as explicit dependency in installer --- install_pince.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install_pince.sh b/install_pince.sh index eed2cab4..a3b774bd 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -126,11 +126,11 @@ ask_pkg_mgr() { } # About xcb packages -> https://github.com/cdgriffith/FastFlix/wiki/Common-questions-and-problems -PKG_NAMES_ALL="python3-pip gdb" +PKG_NAMES_ALL="python3-pip gdb cmake" PKG_NAMES_DEBIAN="$PKG_NAMES_ALL python3-dev python3-venv pkg-config qt6-l10n-tools libcairo2-dev libgirepository1.0-dev libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-cursor0" PKG_NAMES_SUSE="$PKG_NAMES_ALL gcc python3-devel qt6-tools-linguist typelib-1_0-Gtk-3_0 cairo-devel gobject-introspection-devel make" PKG_NAMES_FEDORA="$PKG_NAMES_ALL python3-devel qt6-linguist redhat-lsb cairo-devel gobject-introspection-devel cairo-gobject-devel" -PKG_NAMES_ARCH="python-pip qt6-tools gdb lsb-release pkgconf gobject-introspection-runtime" # arch defaults to py3 nowadays +PKG_NAMES_ARCH="python-pip qt6-tools gdb cmake lsb-release pkgconf gobject-introspection-runtime" # arch defaults to py3 nowadays INSTALL_COMMAND="install" From 757608cb35522e36bd9aeb35b2b5b3471f6b4083 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 11 May 2024 10:28:06 +0100 Subject: [PATCH 407/487] Update libscanmem to fix potential compilation error --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index 10b325df..948ac787 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit 10b325df2314bbdd0f3c475fdbf9e6c080fb7861 +Subproject commit 948ac7872301837d3cdf34bbf6a40267ed56a0ea From a152df4c4eb76d05d924b5985e355ea159e92199 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 11 May 2024 15:52:02 +0100 Subject: [PATCH 408/487] Update libscanmem again to fix small CMake check --- libscanmem-PINCE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libscanmem-PINCE b/libscanmem-PINCE index 948ac787..7e0fede9 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit 948ac7872301837d3cdf34bbf6a40267ed56a0ea +Subproject commit 7e0fede930534ae6c242526e7f202c56c2713538 From 76cbcf44b70e66431e8704b2d04940300ea56b5b Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 11 May 2024 18:01:45 +0100 Subject: [PATCH 409/487] Add error handling to AppImage packager --- ci/package.sh | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/ci/package.sh b/ci/package.sh index 4dbe86d3..5d8f64d9 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -63,18 +63,25 @@ chmod +x $CONDAPLUGIN # Create cleanup function to remove remaining deps/files cleanup () { - rm AppRun.sh - rm -rf ./AppDir - rm -rf ./_temp_home - rm $DEPLOYTOOL* - rm $CONDAPLUGIN* + cd $PACKAGEDIR + # Remove everything outside of package.sh and AppImage output + ls --hide=package.sh --hide=PINCE*.AppImage | xargs rm -rf } trap cleanup EXIT +# Error checking function +exit_on_failure() { + if [ "$?" -ne 0 ]; then + echo + echo "Error occured while creating AppImage! Check the log above!" + exit 1 + fi +} + # Create AppImage's AppDir with a Conda environment pre-baked # containing our required pip packages export PIP_REQUIREMENTS="-r ../requirements.txt" -$DEPLOYTOOL --appdir AppDir -pconda +$DEPLOYTOOL --appdir AppDir -pconda || exit_on_failure # Create PINCE directory mkdir -p AppDir/opt/PINCE @@ -87,14 +94,14 @@ if [ ! -d "libpince/libscanmem" ]; then mkdir libpince/libscanmem fi cd libscanmem-PINCE -cmake -DCMAKE_BUILD_TYPE=Release . -make -j"$NUM_MAKE_JOBS" +cmake -DCMAKE_BUILD_TYPE=Release . || exit_on_failure +make -j"$NUM_MAKE_JOBS" || exit_on_failure cp --preserve libscanmem.so ../libpince/libscanmem cp --preserve wrappers/scanmem.py ../libpince/libscanmem cd .. # Compile translations -${LRELEASE_CMD} i18n/ts/* +${LRELEASE_CMD} i18n/ts/* || exit_on_failure mkdir -p i18n/qm mv i18n/ts/*.qm i18n/qm/ @@ -135,8 +142,8 @@ wget "https://ftp.gnu.org/gnu/gdb/gdb-14.2.tar.gz" tar xvf gdb-14.2.tar.gz rm gdb-14.2.tar.gz cd gdb-14.2 -./configure --with-python="$(readlink -f ../wrapper.sh)" --prefix=/usr -make -j"$NUM_MAKE_JOBS" +./configure --with-python="$(readlink -f ../wrapper.sh)" --prefix=/usr || exit_on_failure +make -j"$NUM_MAKE_JOBS" || exit_on_failure make install DESTDIR=$INSTALLDIR cd .. rm -rf gdb-14.2 @@ -171,4 +178,4 @@ chmod +x AppRun.sh # Package AppDir into AppImage export LD_LIBRARY_PATH="$(readlink -f ./AppDir/usr/conda/lib)" -$DEPLOYTOOL --appdir AppDir/ --output appimage --custom-apprun AppRun.sh +$DEPLOYTOOL --appdir AppDir/ --output appimage --custom-apprun AppRun.sh || exit_on_failure From 3ac10ed3e5a17d3ce90395629fcd050125fffeb1 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 11 May 2024 22:58:32 +0100 Subject: [PATCH 410/487] Create "Release AppImage" GitHub workflow --- .github/workflows/release_appimage.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/release_appimage.yml diff --git a/.github/workflows/release_appimage.yml b/.github/workflows/release_appimage.yml new file mode 100644 index 00000000..fc2eba80 --- /dev/null +++ b/.github/workflows/release_appimage.yml @@ -0,0 +1,24 @@ +name: Release AppImage + +on: + push: + tags: + - "v*.*" + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install Dependencies + run: sudo apt install libfuse2 libmpc-dev libmpfr-dev gmpc-dev appstream qt6-l10n-tools libcairo2-dev libgirepository1.0-dev + - name: Build + run: | + export ARCH=x86_64 + ./ci/package.sh + - name: Release + uses: softprops/action-gh-release@v2 + with: + make_latest: true + files: ci/PINCE-x86_64.AppImage From 15855c4539163d9c47b7230cd79497202bd3c5aa Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sun, 12 May 2024 02:20:36 +0100 Subject: [PATCH 411/487] Update README.md --- README.md | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 1eae0494..fff4dd3c 100644 --- a/README.md +++ b/README.md @@ -59,40 +59,45 @@ Pre-release screenshots: - **Extendable with .so files at runtime** * See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) -# Installing +# Installing and running PINCE +### Users: +- No need to install. Just grab the latest AppImage over at [Releases](https://github.com/korcankaraokcu/PINCE/releases) and run the following commands in the same folder: +```bash +chmod +x PINCE-x86_64.AppImage +sudo -E ./PINCE-x86_64.AppImage ``` +- Our AppImage should run on any distro that is as new or newer than Ubuntu 22.04. Anything older than this might not work and is not officially supported. +- For Arch users, there's also an [AUR package](https://aur.archlinux.org/packages/pince-git/) but please bear in mind that **we're not the maintainers of the AUR package and it's not officially supported by us**. + - Please do not open an Issue unless you can reproduce the issue you're experiencing on our AppImages or local install. + +### Developers and Contributors: +- If you want to have a local install of PINCE so you can modify code or contribute with PRs, you'll have to use our installer script in the repo to setup a venv dev environment. +- To install local dev environment, run the following commands in a terminal anywhere you'd like to have the PINCE folder: +```bash git clone --recursive https://github.com/korcankaraokcu/PINCE cd PINCE sh install_pince.sh ``` -~~For Archlinux, you can also use the [AUR package](https://aur.archlinux.org/packages/pince-git/) as an alternative~~ Currently outdated, use the installation script - -If you like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them if you want +- Make sure to check our [Officially supported platforms](#officially-supported-platforms) section below. Our installer might not work on distros that are not listed there, but it will still try to install using packages from supported distros, just follow the on-screen instructions. +- If installer fails trying to install on an unsupported distro, you're on your own on trying to get the local dev environment up and running. Check `install_pince.sh` to get an idea about what you might need. +- If you'd like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them as well if you want. ***Notes:*** - If you are having problems with your default gdb version, you can use the `install_gdb.sh` script to install another version locally. Read the comments in it for more information - Check https://github.com/korcankaraokcu/PINCE/issues/116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` -# Running PINCE -Just run ```sh PINCE.sh``` in the PINCE directory - -# Contributing -Want to help? Check out [CONTRIBUTING.md](CONTRIBUTING.md) - -# License -GPLv3+. See [COPYING](COPYING) file for details - # Officially supported platforms -PINCE should technically run on any distro that comes with **Python 3.10+** and **PyQt 6.6+** installed or available in the package manager, but below is the list of distros that we officially support, as in we actively test on these and help with issues: +Local dev installs of PINCE should technically run on any distro that comes with **Python 3.10+** and **PyQt 6.6+** installed or available in the package manager, but below is the list of distros that we officially support, as in we actively test on these and help with issues: - Ubuntu 22.04+ - Debian 12+ (or Testing) -- Archlinux +- Arch Linux - Fedora 35+ -Should your distro not be officially supported, the installer can still try to install it for you by picking one of the base package managers appropriate for your distro but please **do not open an issue on GitHub** if it does not work for you. +# Contributing +Want to help? Check out [CONTRIBUTING.md](CONTRIBUTING.md) -If this happens and you can't figure out why, we might be able to guide you into making PINCE run in our Discord server, under the #issues channel, but remember that we only actively test the installer and PINCE on the distros listed above. +# License +GPLv3+. See [COPYING](COPYING) file for details # Trusted Sources * [Official github page](https://github.com/korcankaraokcu/PINCE) - * [AUR package for Archlinux](https://aur.archlinux.org/packages/pince-git/) From aaaa76aef690fe247ce48f1d69ab9c903fda1c74 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sun, 12 May 2024 12:27:53 +0100 Subject: [PATCH 412/487] Disable isort in PINCE --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 55ec8d78..25323d3c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,4 @@ [tool.black] line-length = 120 +[tool.isort] +skip_glob = ["*"] From d92aba2a1f175083d217cdccec8084c2f0009485 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sun, 12 May 2024 13:09:10 +0100 Subject: [PATCH 413/487] Change AppImage packager to supply newer libstdc++ --- ci/package.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/package.sh b/ci/package.sh index 5d8f64d9..ab37f93f 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -81,6 +81,7 @@ exit_on_failure() { # Create AppImage's AppDir with a Conda environment pre-baked # containing our required pip packages export PIP_REQUIREMENTS="-r ../requirements.txt" +export CONDA_PACKAGES="libstdcxx-ng" # Need this to get libstdc++ higher than 6.0.29 $DEPLOYTOOL --appdir AppDir -pconda || exit_on_failure # Create PINCE directory From 6b170faff032a423fa4cb89213340ceda69fb80d Mon Sep 17 00:00:00 2001 From: Bloodiko Date: Sun, 12 May 2024 20:13:04 +0200 Subject: [PATCH 414/487] fix AddressEditWindow error --- PINCE.py | 2 +- libpince/utils.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index d2a4d40c..82fdff7e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2004,7 +2004,7 @@ def update_deref_labels(self, pointer_chain_result: typedefs.PointerChainResult) for index, offsetFrame in enumerate(self.offsetsList): previousDerefText = self.caps_hex_or_error_indicator(pointer_chain_result.pointer_chain[index]) currentDerefText = self.caps_hex_or_error_indicator(pointer_chain_result.pointer_chain[index + 1]) - offsetText = self.upper_hex(offsetFrame.offsetText.text()) + offsetText = utils.upper_hex(offsetFrame.offsetText.text()) operationalSign = "" if offsetText.startswith("-") else "+" calculation = f"{previousDerefText}{operationalSign}{offsetText}" if index != len(self.offsetsList) - 1: diff --git a/libpince/utils.py b/libpince/utils.py index 0eb0d6eb..a5c6573b 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -1177,8 +1177,6 @@ def wrapper(*args, **kwargs): try: func(*args, **kwargs) except: - # print(f' Args: {args}' ) - # print(f' Kwargs: {kwargs}' ) traceback.print_exc() return wrapper @@ -1187,4 +1185,7 @@ def wrapper(*args, **kwargs): #:tag:Utilities def upper_hex(hex_str: str): """Converts the given hex string to uppercase while keeping the 'x' character lowercase""" + # check if the given string is a hex string, if not return the string as is + if not regexes.hex_number_gui.match(hex_str): + return hex_str return hex_str.upper().replace("X", "x") From cb3537d0d8a1cd7559b82e002ab85ee770c157d9 Mon Sep 17 00:00:00 2001 From: OpenNetSurfer <168825895+OpenNetSurfer@users.noreply.github.com> Date: Sun, 12 May 2024 20:26:56 +0000 Subject: [PATCH 415/487] "Not" Scan Type Feature (#257) * Added "Not" option as a scan type --- PINCE.py | 8 +++++++- i18n/ts/it_IT.ts | 5 +++++ i18n/ts/zh_CN.ts | 5 +++++ libpince/typedefs.py | 14 +++++++++++--- tr/tr.py | 1 + 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index 82fdff7e..6f26fdea 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1234,6 +1234,7 @@ def comboBox_ScanType_current_index_changed(self): def comboBox_ScanType_init(self): scan_type_text = { typedefs.SCAN_TYPE.EXACT: tr.EXACT, + typedefs.SCAN_TYPE.NOT: tr.NOT, typedefs.SCAN_TYPE.INCREASED: tr.INCREASED, typedefs.SCAN_TYPE.INCREASED_BY: tr.INCREASED_BY, typedefs.SCAN_TYPE.DECREASED: tr.DECREASED, @@ -1246,8 +1247,9 @@ def comboBox_ScanType_init(self): typedefs.SCAN_TYPE.UNKNOWN: tr.UNKNOWN_VALUE, } current_type = self.comboBox_ScanType.currentData(Qt.ItemDataRole.UserRole) + value_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) self.comboBox_ScanType.clear() - items = typedefs.SCAN_TYPE.get_list(self.scan_mode) + items = typedefs.SCAN_TYPE.get_list(self.scan_mode, value_type) old_index = 0 for index, type_index in enumerate(items): if current_type == type_index: @@ -1318,6 +1320,9 @@ def validate_search(self, search_for: str, search_for2: str): } if type_index in cmp_symbols: return cmp_symbols[type_index] + " " + search_for + + if type_index == typedefs.SCAN_TYPE.NOT: + search_for = "!= " + search_for return search_for def pushButton_NextScan_clicked(self): @@ -1422,6 +1427,7 @@ def comboBox_ValueType_current_index_changed(self): if "float" in validator_str or validator_str == "number": validator_str = "float" + self.comboBox_ScanType_init() self.lineEdit_Scan.setValidator(guiutils.validator_map[validator_str]) self.lineEdit_Scan2.setValidator(guiutils.validator_map[validator_str]) scanmem.send_command("option scan_data_type {}".format(scanmem_type)) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index fe2219a7..92a5053e 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -2484,6 +2484,11 @@ Proceed? Tracing has been completed + + + Not + + Exact diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 130e8b47..d1868c32 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -2555,6 +2555,11 @@ Proceed? Tracing has been completed 追踪已完成 + + + Not + + Exact diff --git a/libpince/typedefs.py b/libpince/typedefs.py index ecc3f2ab..6228e82f 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -328,20 +328,24 @@ class SCAN_TYPE: CHANGED = 8 UNCHANGED = 9 UNKNOWN = 10 + NOT = 11 @staticmethod - def get_list(scan_mode): + def get_list(scan_mode, value_type): + list = [] if scan_mode == SCAN_MODE.NEW: - return [ + list = [ SCAN_TYPE.EXACT, + SCAN_TYPE.NOT, SCAN_TYPE.LESS, SCAN_TYPE.MORE, SCAN_TYPE.BETWEEN, SCAN_TYPE.UNKNOWN, ] else: - return [ + list = [ SCAN_TYPE.EXACT, + SCAN_TYPE.NOT, SCAN_TYPE.INCREASED, SCAN_TYPE.INCREASED_BY, SCAN_TYPE.DECREASED, @@ -353,6 +357,10 @@ def get_list(scan_mode): SCAN_TYPE.UNCHANGED, ] + if value_type == SCAN_INDEX.AOB or value_type == SCAN_INDEX.STRING: + del list[1] + + return list class SCAN_MODE: NEW = 0 diff --git a/tr/tr.py b/tr/tr.py index 4deda6b1..3d786ed0 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -335,6 +335,7 @@ def translate(): WAITING_FOR_BREAKPOINT = QT_TR_NOOP("Waiting for breakpoint to trigger") TRACING_CANCELED = QT_TR_NOOP("Tracing has been canceled") TRACING_COMPLETED = QT_TR_NOOP("Tracing has been completed") + NOT = QT_TR_NOOP("Not") EXACT = QT_TR_NOOP("Exact") INCREASED = QT_TR_NOOP("Increased") INCREASED_BY = QT_TR_NOOP("Increased by") From d7425735adbb761333ffa7e3c16b1ce5058f5012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 12 May 2024 23:44:53 +0300 Subject: [PATCH 416/487] Remove redundant code --- libpince/typedefs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libpince/typedefs.py b/libpince/typedefs.py index 6228e82f..2d1bdf22 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -332,7 +332,6 @@ class SCAN_TYPE: @staticmethod def get_list(scan_mode, value_type): - list = [] if scan_mode == SCAN_MODE.NEW: list = [ SCAN_TYPE.EXACT, @@ -359,9 +358,10 @@ def get_list(scan_mode, value_type): if value_type == SCAN_INDEX.AOB or value_type == SCAN_INDEX.STRING: del list[1] - + return list + class SCAN_MODE: NEW = 0 ONGOING = 1 From 8f5b416dcdbef0919aa62f31d7e2698429a362ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 13 May 2024 00:52:31 +0300 Subject: [PATCH 417/487] Add monospace to more widgets --- CONTRIBUTING.md | 2 ++ GUI/BookmarkWidget.py | 17 ++++++++++------- GUI/BookmarkWidget.ui | 8 +++++++- GUI/BreakpointInfoWidget.py | 12 +++++++++--- GUI/BreakpointInfoWidget.ui | 13 ++++++++++++- GUI/DissectCodeDialog.py | 5 ++++- GUI/DissectCodeDialog.ui | 5 +++++ GUI/ExamineReferrersWidget.py | 24 +++++++++++++++--------- GUI/ExamineReferrersWidget.ui | 10 ++++++++++ GUI/FunctionsInfoWidget.py | 20 +++++++++++++------- GUI/FunctionsInfoWidget.ui | 13 ++++++++++++- GUI/LogFileWidget.py | 11 +++++++---- GUI/LogFileWidget.ui | 5 +++++ GUI/MemoryRegionsWidget.py | 7 +++++-- GUI/MemoryRegionsWidget.ui | 5 +++++ GUI/MemoryViewerWindow.py | 10 +++++----- GUI/MemoryViewerWindow.ui | 8 ++++---- GUI/ReferencedCallsWidget.py | 24 +++++++++++++++--------- GUI/ReferencedCallsWidget.ui | 10 ++++++++++ GUI/ReferencedStringsWidget.py | 26 ++++++++++++++++---------- GUI/ReferencedStringsWidget.ui | 10 ++++++++++ GUI/RestoreInstructionsWidget.py | 9 ++++++--- GUI/RestoreInstructionsWidget.ui | 9 +++++++-- GUI/SearchOpcodeWidget.py | 27 +++++++++++++++------------ GUI/SearchOpcodeWidget.ui | 5 +++++ GUI/StackTraceInfoWidget.py | 30 ++++++++++++++++++------------ GUI/StackTraceInfoWidget.ui | 20 ++++++++++++++++---- GUI/TrackWatchpointWidget.py | 27 ++++++++++++++++++--------- GUI/TrackWatchpointWidget.ui | 21 +++++++++++++++++++-- 29 files changed, 285 insertions(+), 108 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9cef4b3d..fe7b3740 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,6 +115,8 @@ Consider doing these when creating a new QTableWidget or QTableView - 15/02/2024 - Don't always trust the "Adjust Size" button of the Qt Designer, it might expand widgets much more than needed, especially for smaller widgets. Consider the use cases and adjust manually. This also helps functions like `guiutils.center_to_parent` work properly +- 13/05/2024 - Monospace font and `utils.upper_hex` function greatly improve readability if the text area includes hex data, consider using those when creating new text areas. Memory Viewer is a good example for this + - 02/09/2018 - All functions with docstrings should have their subfunctions written after their docstrings. For instance: ```python def test(): diff --git a/GUI/BookmarkWidget.py b/GUI/BookmarkWidget.py index 4f843a9b..62577ae3 100644 --- a/GUI/BookmarkWidget.py +++ b/GUI/BookmarkWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'BookmarkWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -19,26 +19,29 @@ def setupUi(self, Form): self.horizontalLayout.setObjectName("horizontalLayout") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.label = QtWidgets.QLabel(Form) + self.label = QtWidgets.QLabel(parent=Form) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) - self.listWidget = QtWidgets.QListWidget(Form) + self.listWidget = QtWidgets.QListWidget(parent=Form) + font = QtGui.QFont() + font.setFamily("Monospace") + self.listWidget.setFont(font) self.listWidget.setObjectName("listWidget") self.verticalLayout.addWidget(self.listWidget) self.horizontalLayout.addLayout(self.verticalLayout) self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2.setObjectName("verticalLayout_2") - self.label_2 = QtWidgets.QLabel(Form) + self.label_2 = QtWidgets.QLabel(parent=Form) self.label_2.setObjectName("label_2") self.verticalLayout_2.addWidget(self.label_2) - self.lineEdit_Info = QtWidgets.QLineEdit(Form) + self.lineEdit_Info = QtWidgets.QLineEdit(parent=Form) self.lineEdit_Info.setReadOnly(True) self.lineEdit_Info.setObjectName("lineEdit_Info") self.verticalLayout_2.addWidget(self.lineEdit_Info) - self.label_3 = QtWidgets.QLabel(Form) + self.label_3 = QtWidgets.QLabel(parent=Form) self.label_3.setObjectName("label_3") self.verticalLayout_2.addWidget(self.label_3) - self.lineEdit_Comment = QtWidgets.QLineEdit(Form) + self.lineEdit_Comment = QtWidgets.QLineEdit(parent=Form) self.lineEdit_Comment.setReadOnly(True) self.lineEdit_Comment.setObjectName("lineEdit_Comment") self.verticalLayout_2.addWidget(self.lineEdit_Comment) diff --git a/GUI/BookmarkWidget.ui b/GUI/BookmarkWidget.ui index a0b7a9be..09cbfecc 100644 --- a/GUI/BookmarkWidget.ui +++ b/GUI/BookmarkWidget.ui @@ -26,7 +26,13 @@ - + + + + Monospace + + + diff --git a/GUI/BreakpointInfoWidget.py b/GUI/BreakpointInfoWidget.py index 634fae32..d634521e 100644 --- a/GUI/BreakpointInfoWidget.py +++ b/GUI/BreakpointInfoWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'BreakpointInfoWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -17,7 +17,10 @@ def setupUi(self, TabWidget): self.tab_BreakpointInfo.setObjectName("tab_BreakpointInfo") self.gridLayout_2 = QtWidgets.QGridLayout(self.tab_BreakpointInfo) self.gridLayout_2.setObjectName("gridLayout_2") - self.tableWidget_BreakpointInfo = QtWidgets.QTableWidget(self.tab_BreakpointInfo) + self.tableWidget_BreakpointInfo = QtWidgets.QTableWidget(parent=self.tab_BreakpointInfo) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_BreakpointInfo.setFont(font) self.tableWidget_BreakpointInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_BreakpointInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_BreakpointInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -54,7 +57,10 @@ def setupUi(self, TabWidget): self.tab_RawBreakpointInfo.setObjectName("tab_RawBreakpointInfo") self.gridLayout = QtWidgets.QGridLayout(self.tab_RawBreakpointInfo) self.gridLayout.setObjectName("gridLayout") - self.textBrowser_BreakpointInfo = QtWidgets.QTextBrowser(self.tab_RawBreakpointInfo) + self.textBrowser_BreakpointInfo = QtWidgets.QTextBrowser(parent=self.tab_RawBreakpointInfo) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_BreakpointInfo.setFont(font) self.textBrowser_BreakpointInfo.setObjectName("textBrowser_BreakpointInfo") self.gridLayout.addWidget(self.textBrowser_BreakpointInfo, 0, 0, 1, 1) TabWidget.addTab(self.tab_RawBreakpointInfo, "") diff --git a/GUI/BreakpointInfoWidget.ui b/GUI/BreakpointInfoWidget.ui index 5bbff2c7..e8137ed3 100644 --- a/GUI/BreakpointInfoWidget.ui +++ b/GUI/BreakpointInfoWidget.ui @@ -23,6 +23,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -105,7 +110,13 @@ - + + + + Monospace + + + diff --git a/GUI/DissectCodeDialog.py b/GUI/DissectCodeDialog.py index efcd7932..2c432f3f 100644 --- a/GUI/DissectCodeDialog.py +++ b/GUI/DissectCodeDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'DissectCodeDialog.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -19,6 +19,9 @@ def setupUi(self, Dialog): self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") self.tableWidget_ExecutableMemoryRegions = QtWidgets.QTableWidget(parent=self.splitter) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_ExecutableMemoryRegions.setFont(font) self.tableWidget_ExecutableMemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_ExecutableMemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_ExecutableMemoryRegions.setWordWrap(False) diff --git a/GUI/DissectCodeDialog.ui b/GUI/DissectCodeDialog.ui index bcbbe7d6..74cbe9cd 100644 --- a/GUI/DissectCodeDialog.ui +++ b/GUI/DissectCodeDialog.ui @@ -20,6 +20,11 @@ Qt::Horizontal + + + Monospace + + QAbstractItemView::NoEditTriggers diff --git a/GUI/ExamineReferrersWidget.py b/GUI/ExamineReferrersWidget.py index 31224403..833b0172 100644 --- a/GUI/ExamineReferrersWidget.py +++ b/GUI/ExamineReferrersWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ExamineReferrersWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -16,34 +16,40 @@ def setupUi(self, Form): Form.setToolTip("") self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.splitter = QtWidgets.QSplitter(Form) + self.splitter = QtWidgets.QSplitter(parent=Form) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") - self.layoutWidget = QtWidgets.QWidget(self.splitter) + self.layoutWidget = QtWidgets.QWidget(parent=self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lineEdit_Regex = QtWidgets.QLineEdit(self.layoutWidget) + self.lineEdit_Regex = QtWidgets.QLineEdit(parent=self.layoutWidget) self.lineEdit_Regex.setObjectName("lineEdit_Regex") self.horizontalLayout_2.addWidget(self.lineEdit_Regex) - self.checkBox_CaseSensitive = QtWidgets.QCheckBox(self.layoutWidget) + self.checkBox_CaseSensitive = QtWidgets.QCheckBox(parent=self.layoutWidget) self.checkBox_CaseSensitive.setObjectName("checkBox_CaseSensitive") self.horizontalLayout_2.addWidget(self.checkBox_CaseSensitive) - self.checkBox_Regex = QtWidgets.QCheckBox(self.layoutWidget) + self.checkBox_Regex = QtWidgets.QCheckBox(parent=self.layoutWidget) self.checkBox_Regex.setObjectName("checkBox_Regex") self.horizontalLayout_2.addWidget(self.checkBox_Regex) - self.pushButton_Search = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_Search = QtWidgets.QPushButton(parent=self.layoutWidget) self.pushButton_Search.setObjectName("pushButton_Search") self.horizontalLayout_2.addWidget(self.pushButton_Search) self.verticalLayout.addLayout(self.horizontalLayout_2) - self.listWidget_Referrers = QtWidgets.QListWidget(self.layoutWidget) + self.listWidget_Referrers = QtWidgets.QListWidget(parent=self.layoutWidget) + font = QtGui.QFont() + font.setFamily("Monospace") + self.listWidget_Referrers.setFont(font) self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.listWidget_Referrers.setObjectName("listWidget_Referrers") self.verticalLayout.addWidget(self.listWidget_Referrers) - self.textBrowser_DisasInfo = QtWidgets.QTextBrowser(self.splitter) + self.textBrowser_DisasInfo = QtWidgets.QTextBrowser(parent=self.splitter) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_DisasInfo.setFont(font) self.textBrowser_DisasInfo.setLineWrapMode(QtWidgets.QTextEdit.LineWrapMode.NoWrap) self.textBrowser_DisasInfo.setObjectName("textBrowser_DisasInfo") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) diff --git a/GUI/ExamineReferrersWidget.ui b/GUI/ExamineReferrersWidget.ui index f44699eb..2af499d9 100644 --- a/GUI/ExamineReferrersWidget.ui +++ b/GUI/ExamineReferrersWidget.ui @@ -67,6 +67,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -75,6 +80,11 @@ + + + Monospace + + QTextEdit::NoWrap diff --git a/GUI/FunctionsInfoWidget.py b/GUI/FunctionsInfoWidget.py index 32784d45..84ce319c 100644 --- a/GUI/FunctionsInfoWidget.py +++ b/GUI/FunctionsInfoWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'FunctionsInfoWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -15,7 +15,10 @@ def setupUi(self, Form): Form.resize(640, 555) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.tableWidget_SymbolInfo = QtWidgets.QTableWidget(Form) + self.tableWidget_SymbolInfo = QtWidgets.QTableWidget(parent=Form) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_SymbolInfo.setFont(font) self.tableWidget_SymbolInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_SymbolInfo.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_SymbolInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -34,21 +37,24 @@ def setupUi(self, Form): self.gridLayout.addWidget(self.tableWidget_SymbolInfo, 2, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.lineEdit_SearchInput = QtWidgets.QLineEdit(Form) + self.lineEdit_SearchInput = QtWidgets.QLineEdit(parent=Form) self.lineEdit_SearchInput.setObjectName("lineEdit_SearchInput") self.horizontalLayout.addWidget(self.lineEdit_SearchInput) - self.checkBox_CaseSensitive = QtWidgets.QCheckBox(Form) + self.checkBox_CaseSensitive = QtWidgets.QCheckBox(parent=Form) self.checkBox_CaseSensitive.setObjectName("checkBox_CaseSensitive") self.horizontalLayout.addWidget(self.checkBox_CaseSensitive) - self.pushButton_Search = QtWidgets.QPushButton(Form) + self.pushButton_Search = QtWidgets.QPushButton(parent=Form) self.pushButton_Search.setObjectName("pushButton_Search") self.horizontalLayout.addWidget(self.pushButton_Search) - self.pushButton_Help = QtWidgets.QPushButton(Form) + self.pushButton_Help = QtWidgets.QPushButton(parent=Form) self.pushButton_Help.setText("") self.pushButton_Help.setObjectName("pushButton_Help") self.horizontalLayout.addWidget(self.pushButton_Help) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) - self.textBrowser_AddressInfo = QtWidgets.QTextBrowser(Form) + self.textBrowser_AddressInfo = QtWidgets.QTextBrowser(parent=Form) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_AddressInfo.setFont(font) self.textBrowser_AddressInfo.setObjectName("textBrowser_AddressInfo") self.gridLayout.addWidget(self.textBrowser_AddressInfo, 1, 0, 1, 1) diff --git a/GUI/FunctionsInfoWidget.ui b/GUI/FunctionsInfoWidget.ui index 0906e9ba..3fb27c7e 100644 --- a/GUI/FunctionsInfoWidget.ui +++ b/GUI/FunctionsInfoWidget.ui @@ -16,6 +16,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -91,7 +96,13 @@ - + + + + Monospace + + + diff --git a/GUI/LogFileWidget.py b/GUI/LogFileWidget.py index 21e8edc2..1cf14c8a 100644 --- a/GUI/LogFileWidget.py +++ b/GUI/LogFileWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'LogFileWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -17,15 +17,18 @@ def setupUi(self, Form): self.gridLayout.setObjectName("gridLayout") self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.label_FilePath = QtWidgets.QLabel(Form) + self.label_FilePath = QtWidgets.QLabel(parent=Form) self.label_FilePath.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_FilePath.setObjectName("label_FilePath") self.horizontalLayout.addWidget(self.label_FilePath) - self.label_LoggingStatus = QtWidgets.QLabel(Form) + self.label_LoggingStatus = QtWidgets.QLabel(parent=Form) self.label_LoggingStatus.setObjectName("label_LoggingStatus") self.horizontalLayout.addWidget(self.label_LoggingStatus) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) - self.textBrowser_LogContent = QtWidgets.QTextBrowser(Form) + self.textBrowser_LogContent = QtWidgets.QTextBrowser(parent=Form) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_LogContent.setFont(font) self.textBrowser_LogContent.setLineWrapMode(QtWidgets.QTextEdit.LineWrapMode.NoWrap) self.textBrowser_LogContent.setObjectName("textBrowser_LogContent") self.gridLayout.addWidget(self.textBrowser_LogContent, 1, 0, 1, 1) diff --git a/GUI/LogFileWidget.ui b/GUI/LogFileWidget.ui index 3eedf60f..b0aaf6ad 100644 --- a/GUI/LogFileWidget.ui +++ b/GUI/LogFileWidget.ui @@ -37,6 +37,11 @@ + + + Monospace + + QTextEdit::NoWrap diff --git a/GUI/MemoryRegionsWidget.py b/GUI/MemoryRegionsWidget.py index 7c7a48cc..cbb9898f 100644 --- a/GUI/MemoryRegionsWidget.py +++ b/GUI/MemoryRegionsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MemoryRegionsWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -15,7 +15,10 @@ def setupUi(self, Form): Form.resize(684, 539) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.tableWidget_MemoryRegions = QtWidgets.QTableWidget(Form) + self.tableWidget_MemoryRegions = QtWidgets.QTableWidget(parent=Form) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_MemoryRegions.setFont(font) self.tableWidget_MemoryRegions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_MemoryRegions.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_MemoryRegions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) diff --git a/GUI/MemoryRegionsWidget.ui b/GUI/MemoryRegionsWidget.ui index 73d494ab..43f58942 100644 --- a/GUI/MemoryRegionsWidget.ui +++ b/GUI/MemoryRegionsWidget.ui @@ -16,6 +16,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 389fecf0..f850565f 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'MemoryViewerWindow.ui' # -# Created by: PyQt6 UI code generator 6.6.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -85,7 +85,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Registers.setWidgetResizable(True) self.scrollArea_Registers.setObjectName("scrollArea_Registers") self.scrollAreaWidgetContents_Registers = QtWidgets.QWidget() - self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 335, 330)) + self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 335, 342)) self.scrollAreaWidgetContents_Registers.setObjectName("scrollAreaWidgetContents_Registers") self.gridLayout_8 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_Registers) self.gridLayout_8.setContentsMargins(0, 0, 0, 0) @@ -689,7 +689,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Hex.setWidgetResizable(True) self.scrollArea_Hex.setObjectName("scrollArea_Hex") self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() - self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 492, 212)) + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 492, 200)) self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") self.gridLayout_11 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) self.gridLayout_11.setContentsMargins(0, 0, 0, 0) @@ -773,7 +773,7 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_9.setObjectName("gridLayout_9") self.tableWidget_StackTrace = QtWidgets.QTableWidget(parent=self.StackTrace) font = QtGui.QFont() - font.setPointSize(9) + font.setFamily("Monospace") self.tableWidget_StackTrace.setFont(font) self.tableWidget_StackTrace.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_StackTrace.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) @@ -800,7 +800,7 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_10.setObjectName("gridLayout_10") self.tableWidget_Stack = QtWidgets.QTableWidget(parent=self.Stack) font = QtGui.QFont() - font.setPointSize(9) + font.setFamily("Monospace") self.tableWidget_Stack.setFont(font) self.tableWidget_Stack.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Stack.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index c834739c..3a8c1538 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -191,7 +191,7 @@ 0 0 335 - 330 + 342 @@ -1329,7 +1329,7 @@ 0 0 492 - 212 + 200 @@ -1508,7 +1508,7 @@ - 9 + Monospace @@ -1570,7 +1570,7 @@ - 9 + Monospace diff --git a/GUI/ReferencedCallsWidget.py b/GUI/ReferencedCallsWidget.py index e71cd008..47b9fbb4 100644 --- a/GUI/ReferencedCallsWidget.py +++ b/GUI/ReferencedCallsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ReferencedCallsWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -16,30 +16,33 @@ def setupUi(self, Form): Form.setToolTip("") self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.splitter = QtWidgets.QSplitter(Form) + self.splitter = QtWidgets.QSplitter(parent=Form) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") - self.layoutWidget = QtWidgets.QWidget(self.splitter) + self.layoutWidget = QtWidgets.QWidget(parent=self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lineEdit_Regex = QtWidgets.QLineEdit(self.layoutWidget) + self.lineEdit_Regex = QtWidgets.QLineEdit(parent=self.layoutWidget) self.lineEdit_Regex.setObjectName("lineEdit_Regex") self.horizontalLayout_2.addWidget(self.lineEdit_Regex) - self.checkBox_CaseSensitive = QtWidgets.QCheckBox(self.layoutWidget) + self.checkBox_CaseSensitive = QtWidgets.QCheckBox(parent=self.layoutWidget) self.checkBox_CaseSensitive.setObjectName("checkBox_CaseSensitive") self.horizontalLayout_2.addWidget(self.checkBox_CaseSensitive) - self.checkBox_Regex = QtWidgets.QCheckBox(self.layoutWidget) + self.checkBox_Regex = QtWidgets.QCheckBox(parent=self.layoutWidget) self.checkBox_Regex.setObjectName("checkBox_Regex") self.horizontalLayout_2.addWidget(self.checkBox_Regex) - self.pushButton_Search = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_Search = QtWidgets.QPushButton(parent=self.layoutWidget) self.pushButton_Search.setObjectName("pushButton_Search") self.horizontalLayout_2.addWidget(self.pushButton_Search) self.verticalLayout.addLayout(self.horizontalLayout_2) - self.tableWidget_References = QtWidgets.QTableWidget(self.layoutWidget) + self.tableWidget_References = QtWidgets.QTableWidget(parent=self.layoutWidget) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_References.setFont(font) self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -56,7 +59,10 @@ def setupUi(self, Form): self.tableWidget_References.verticalHeader().setDefaultSectionSize(16) self.tableWidget_References.verticalHeader().setMinimumSectionSize(16) self.verticalLayout.addWidget(self.tableWidget_References) - self.listWidget_Referrers = QtWidgets.QListWidget(self.splitter) + self.listWidget_Referrers = QtWidgets.QListWidget(parent=self.splitter) + font = QtGui.QFont() + font.setFamily("Monospace") + self.listWidget_Referrers.setFont(font) self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.listWidget_Referrers.setObjectName("listWidget_Referrers") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) diff --git a/GUI/ReferencedCallsWidget.ui b/GUI/ReferencedCallsWidget.ui index d5899ee3..b629b72c 100644 --- a/GUI/ReferencedCallsWidget.ui +++ b/GUI/ReferencedCallsWidget.ui @@ -64,6 +64,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -106,6 +111,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers diff --git a/GUI/ReferencedStringsWidget.py b/GUI/ReferencedStringsWidget.py index e77293c4..4fc51879 100644 --- a/GUI/ReferencedStringsWidget.py +++ b/GUI/ReferencedStringsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'ReferencedStringsWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -16,30 +16,33 @@ def setupUi(self, Form): Form.setToolTip("") self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.splitter = QtWidgets.QSplitter(Form) + self.splitter = QtWidgets.QSplitter(parent=Form) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") - self.layoutWidget = QtWidgets.QWidget(self.splitter) + self.layoutWidget = QtWidgets.QWidget(parent=self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lineEdit_Regex = QtWidgets.QLineEdit(self.layoutWidget) + self.lineEdit_Regex = QtWidgets.QLineEdit(parent=self.layoutWidget) self.lineEdit_Regex.setObjectName("lineEdit_Regex") self.horizontalLayout_2.addWidget(self.lineEdit_Regex) - self.checkBox_CaseSensitive = QtWidgets.QCheckBox(self.layoutWidget) + self.checkBox_CaseSensitive = QtWidgets.QCheckBox(parent=self.layoutWidget) self.checkBox_CaseSensitive.setObjectName("checkBox_CaseSensitive") self.horizontalLayout_2.addWidget(self.checkBox_CaseSensitive) - self.checkBox_Regex = QtWidgets.QCheckBox(self.layoutWidget) + self.checkBox_Regex = QtWidgets.QCheckBox(parent=self.layoutWidget) self.checkBox_Regex.setObjectName("checkBox_Regex") self.horizontalLayout_2.addWidget(self.checkBox_Regex) - self.pushButton_Search = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_Search = QtWidgets.QPushButton(parent=self.layoutWidget) self.pushButton_Search.setObjectName("pushButton_Search") self.horizontalLayout_2.addWidget(self.pushButton_Search) self.verticalLayout.addLayout(self.horizontalLayout_2) - self.tableWidget_References = QtWidgets.QTableWidget(self.layoutWidget) + self.tableWidget_References = QtWidgets.QTableWidget(parent=self.layoutWidget) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_References.setFont(font) self.tableWidget_References.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_References.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_References.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -62,12 +65,15 @@ def setupUi(self, Form): self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) - self.comboBox_ValueType = QtWidgets.QComboBox(self.layoutWidget) + self.comboBox_ValueType = QtWidgets.QComboBox(parent=self.layoutWidget) self.comboBox_ValueType.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents) self.comboBox_ValueType.setObjectName("comboBox_ValueType") self.horizontalLayout.addWidget(self.comboBox_ValueType) self.verticalLayout.addLayout(self.horizontalLayout) - self.listWidget_Referrers = QtWidgets.QListWidget(self.splitter) + self.listWidget_Referrers = QtWidgets.QListWidget(parent=self.splitter) + font = QtGui.QFont() + font.setFamily("Monospace") + self.listWidget_Referrers.setFont(font) self.listWidget_Referrers.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.listWidget_Referrers.setObjectName("listWidget_Referrers") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) diff --git a/GUI/ReferencedStringsWidget.ui b/GUI/ReferencedStringsWidget.ui index 4c8e075a..3384c90d 100644 --- a/GUI/ReferencedStringsWidget.ui +++ b/GUI/ReferencedStringsWidget.ui @@ -64,6 +64,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -138,6 +143,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers diff --git a/GUI/RestoreInstructionsWidget.py b/GUI/RestoreInstructionsWidget.py index 82533bef..c07a1369 100644 --- a/GUI/RestoreInstructionsWidget.py +++ b/GUI/RestoreInstructionsWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'RestoreInstructionsWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,10 +12,13 @@ class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") - Form.resize(400, 400) + Form.resize(429, 420) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.tableWidget_Instructions = QtWidgets.QTableWidget(Form) + self.tableWidget_Instructions = QtWidgets.QTableWidget(parent=Form) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_Instructions.setFont(font) self.tableWidget_Instructions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Instructions.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Instructions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) diff --git a/GUI/RestoreInstructionsWidget.ui b/GUI/RestoreInstructionsWidget.ui index 1a12c0af..7553c219 100644 --- a/GUI/RestoreInstructionsWidget.ui +++ b/GUI/RestoreInstructionsWidget.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 400 + 429 + 420 @@ -16,6 +16,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers diff --git a/GUI/SearchOpcodeWidget.py b/GUI/SearchOpcodeWidget.py index 45761c4e..5af0e3ef 100644 --- a/GUI/SearchOpcodeWidget.py +++ b/GUI/SearchOpcodeWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'SearchOpcodeWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -17,42 +17,45 @@ def setupUi(self, Form): self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.label_3 = QtWidgets.QLabel(Form) + self.label_3 = QtWidgets.QLabel(parent=Form) self.label_3.setObjectName("label_3") self.horizontalLayout_2.addWidget(self.label_3) - self.lineEdit_Regex = QtWidgets.QLineEdit(Form) + self.lineEdit_Regex = QtWidgets.QLineEdit(parent=Form) self.lineEdit_Regex.setObjectName("lineEdit_Regex") self.horizontalLayout_2.addWidget(self.lineEdit_Regex) - self.checkBox_CaseSensitive = QtWidgets.QCheckBox(Form) + self.checkBox_CaseSensitive = QtWidgets.QCheckBox(parent=Form) self.checkBox_CaseSensitive.setObjectName("checkBox_CaseSensitive") self.horizontalLayout_2.addWidget(self.checkBox_CaseSensitive) - self.checkBox_Regex = QtWidgets.QCheckBox(Form) + self.checkBox_Regex = QtWidgets.QCheckBox(parent=Form) self.checkBox_Regex.setObjectName("checkBox_Regex") self.horizontalLayout_2.addWidget(self.checkBox_Regex) - self.pushButton_Search = QtWidgets.QPushButton(Form) + self.pushButton_Search = QtWidgets.QPushButton(parent=Form) self.pushButton_Search.setObjectName("pushButton_Search") self.horizontalLayout_2.addWidget(self.pushButton_Search) - self.pushButton_Help = QtWidgets.QPushButton(Form) + self.pushButton_Help = QtWidgets.QPushButton(parent=Form) self.pushButton_Help.setText("") self.pushButton_Help.setObjectName("pushButton_Help") self.horizontalLayout_2.addWidget(self.pushButton_Help) self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.label = QtWidgets.QLabel(Form) + self.label = QtWidgets.QLabel(parent=Form) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) - self.lineEdit_Start = QtWidgets.QLineEdit(Form) + self.lineEdit_Start = QtWidgets.QLineEdit(parent=Form) self.lineEdit_Start.setObjectName("lineEdit_Start") self.horizontalLayout.addWidget(self.lineEdit_Start) - self.label_2 = QtWidgets.QLabel(Form) + self.label_2 = QtWidgets.QLabel(parent=Form) self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) - self.lineEdit_End = QtWidgets.QLineEdit(Form) + self.lineEdit_End = QtWidgets.QLineEdit(parent=Form) self.lineEdit_End.setObjectName("lineEdit_End") self.horizontalLayout.addWidget(self.lineEdit_End) self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) - self.tableWidget_Opcodes = QtWidgets.QTableWidget(Form) + self.tableWidget_Opcodes = QtWidgets.QTableWidget(parent=Form) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_Opcodes.setFont(font) self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) diff --git a/GUI/SearchOpcodeWidget.ui b/GUI/SearchOpcodeWidget.ui index 0e08c267..593b27f2 100644 --- a/GUI/SearchOpcodeWidget.ui +++ b/GUI/SearchOpcodeWidget.ui @@ -92,6 +92,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers diff --git a/GUI/StackTraceInfoWidget.py b/GUI/StackTraceInfoWidget.py index b923e7a1..eb8ff40b 100644 --- a/GUI/StackTraceInfoWidget.py +++ b/GUI/StackTraceInfoWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'StackTraceInfoWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -15,29 +15,35 @@ def setupUi(self, Form): Form.resize(768, 440) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.splitter = QtWidgets.QSplitter(Form) + self.splitter = QtWidgets.QSplitter(parent=Form) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") - self.widget = QtWidgets.QWidget(self.splitter) - self.widget.setObjectName("widget") - self.verticalLayout = QtWidgets.QVBoxLayout(self.widget) + self.layoutWidget = QtWidgets.QWidget(parent=self.splitter) + self.layoutWidget.setObjectName("layoutWidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") - self.label = QtWidgets.QLabel(self.widget) + self.label = QtWidgets.QLabel(parent=self.layoutWidget) self.label.setObjectName("label") self.verticalLayout.addWidget(self.label) - self.listWidget_ReturnAddresses = QtWidgets.QListWidget(self.widget) + self.listWidget_ReturnAddresses = QtWidgets.QListWidget(parent=self.layoutWidget) + font = QtGui.QFont() + font.setFamily("Monospace") + self.listWidget_ReturnAddresses.setFont(font) self.listWidget_ReturnAddresses.setObjectName("listWidget_ReturnAddresses") self.verticalLayout.addWidget(self.listWidget_ReturnAddresses) - self.widget1 = QtWidgets.QWidget(self.splitter) - self.widget1.setObjectName("widget1") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget1) + self.layoutWidget1 = QtWidgets.QWidget(parent=self.splitter) + self.layoutWidget1.setObjectName("layoutWidget1") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.layoutWidget1) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.label_2 = QtWidgets.QLabel(self.widget1) + self.label_2 = QtWidgets.QLabel(parent=self.layoutWidget1) self.label_2.setObjectName("label_2") self.verticalLayout_2.addWidget(self.label_2) - self.textBrowser_Info = QtWidgets.QTextBrowser(self.widget1) + self.textBrowser_Info = QtWidgets.QTextBrowser(parent=self.layoutWidget1) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_Info.setFont(font) self.textBrowser_Info.setObjectName("textBrowser_Info") self.verticalLayout_2.addWidget(self.textBrowser_Info) self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) diff --git a/GUI/StackTraceInfoWidget.ui b/GUI/StackTraceInfoWidget.ui index 857ef1ba..c8092fc3 100644 --- a/GUI/StackTraceInfoWidget.ui +++ b/GUI/StackTraceInfoWidget.ui @@ -19,7 +19,7 @@ Qt::Horizontal - + @@ -29,11 +29,17 @@ - + + + + Monospace + + + - + @@ -43,7 +49,13 @@ - + + + + Monospace + + + diff --git a/GUI/TrackWatchpointWidget.py b/GUI/TrackWatchpointWidget.py index abec21cd..8f6f03f3 100644 --- a/GUI/TrackWatchpointWidget.py +++ b/GUI/TrackWatchpointWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TrackWatchpointWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.0 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -15,18 +15,21 @@ def setupUi(self, Form): Form.resize(530, 493) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") - self.splitter_2 = QtWidgets.QSplitter(Form) + self.splitter_2 = QtWidgets.QSplitter(parent=Form) self.splitter_2.setOrientation(QtCore.Qt.Orientation.Vertical) self.splitter_2.setObjectName("splitter_2") - self.splitter = QtWidgets.QSplitter(self.splitter_2) + self.splitter = QtWidgets.QSplitter(parent=self.splitter_2) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") - self.layoutWidget = QtWidgets.QWidget(self.splitter) + self.layoutWidget = QtWidgets.QWidget(parent=self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") - self.tableWidget_Opcodes = QtWidgets.QTableWidget(self.layoutWidget) + self.tableWidget_Opcodes = QtWidgets.QTableWidget(parent=self.layoutWidget) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_Opcodes.setFont(font) self.tableWidget_Opcodes.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_Opcodes.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) self.tableWidget_Opcodes.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) @@ -45,16 +48,22 @@ def setupUi(self, Form): self.verticalLayout.addWidget(self.tableWidget_Opcodes) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.pushButton_Refresh = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_Refresh = QtWidgets.QPushButton(parent=self.layoutWidget) self.pushButton_Refresh.setObjectName("pushButton_Refresh") self.horizontalLayout.addWidget(self.pushButton_Refresh) - self.pushButton_Stop = QtWidgets.QPushButton(self.layoutWidget) + self.pushButton_Stop = QtWidgets.QPushButton(parent=self.layoutWidget) self.pushButton_Stop.setObjectName("pushButton_Stop") self.horizontalLayout.addWidget(self.pushButton_Stop) self.verticalLayout.addLayout(self.horizontalLayout) - self.textBrowser_Info = QtWidgets.QTextBrowser(self.splitter) + self.textBrowser_Info = QtWidgets.QTextBrowser(parent=self.splitter) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_Info.setFont(font) self.textBrowser_Info.setObjectName("textBrowser_Info") - self.textBrowser_Disassemble = QtWidgets.QTextBrowser(self.splitter_2) + self.textBrowser_Disassemble = QtWidgets.QTextBrowser(parent=self.splitter_2) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_Disassemble.setFont(font) self.textBrowser_Disassemble.setObjectName("textBrowser_Disassemble") self.gridLayout.addWidget(self.splitter_2, 0, 0, 1, 1) diff --git a/GUI/TrackWatchpointWidget.ui b/GUI/TrackWatchpointWidget.ui index 08caa114..d8b2a8a3 100644 --- a/GUI/TrackWatchpointWidget.ui +++ b/GUI/TrackWatchpointWidget.ui @@ -27,6 +27,11 @@ + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -83,9 +88,21 @@ - + + + + Monospace + + + + + + + + Monospace + + - From 0fd4168652f59085a1d889550dd320e86db517e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 14 May 2024 23:47:51 +0300 Subject: [PATCH 418/487] Add initial pointer scanner GUI --- GUI/PointerScanDialog.py | 130 ++++++++++++++++ GUI/PointerScanDialog.ui | 291 ++++++++++++++++++++++++++++++++++++ GUI/PointerScannerWindow.py | 81 ++++++++++ GUI/PointerScannerWindow.ui | 120 +++++++++++++++ PINCE.py | 37 +++++ tr/tr.py | 1 + 6 files changed, 660 insertions(+) create mode 100644 GUI/PointerScanDialog.py create mode 100644 GUI/PointerScanDialog.ui create mode 100644 GUI/PointerScannerWindow.py create mode 100644 GUI/PointerScannerWindow.ui diff --git a/GUI/PointerScanDialog.py b/GUI/PointerScanDialog.py new file mode 100644 index 00000000..ecb93641 --- /dev/null +++ b/GUI/PointerScanDialog.py @@ -0,0 +1,130 @@ +# Form implementation generated from reading ui file 'PointerScanDialog.ui' +# +# Created by: PyQt6 UI code generator 6.4.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(386, 320) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(parent=Dialog) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.lineEdit_Address = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Address.setObjectName("lineEdit_Address") + self.horizontalLayout.addWidget(self.lineEdit_Address) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.label_2 = QtWidgets.QLabel(parent=Dialog) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.spinBox_Depth = QtWidgets.QSpinBox(parent=Dialog) + self.spinBox_Depth.setMinimum(1) + self.spinBox_Depth.setObjectName("spinBox_Depth") + self.horizontalLayout.addWidget(self.spinBox_Depth) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_3 = QtWidgets.QLabel(parent=Dialog) + self.label_3.setObjectName("label_3") + self.horizontalLayout_2.addWidget(self.label_3) + self.lineEdit_ScanRangeStart = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_ScanRangeStart.setObjectName("lineEdit_ScanRangeStart") + self.horizontalLayout_2.addWidget(self.lineEdit_ScanRangeStart) + self.label_4 = QtWidgets.QLabel(parent=Dialog) + self.label_4.setObjectName("label_4") + self.horizontalLayout_2.addWidget(self.label_4) + self.lineEdit_ScanRangeEnd = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_ScanRangeEnd.setObjectName("lineEdit_ScanRangeEnd") + self.horizontalLayout_2.addWidget(self.lineEdit_ScanRangeEnd) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_2.addItem(spacerItem2) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_5 = QtWidgets.QLabel(parent=Dialog) + self.label_5.setObjectName("label_5") + self.horizontalLayout_3.addWidget(self.label_5) + self.lineEdit_LRange = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_LRange.setObjectName("lineEdit_LRange") + self.horizontalLayout_3.addWidget(self.lineEdit_LRange) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_3.addItem(spacerItem3) + self.verticalLayout.addLayout(self.horizontalLayout_3) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.label_6 = QtWidgets.QLabel(parent=Dialog) + self.label_6.setObjectName("label_6") + self.horizontalLayout_4.addWidget(self.label_6) + self.spinBox_Node = QtWidgets.QSpinBox(parent=Dialog) + self.spinBox_Node.setMinimum(1) + self.spinBox_Node.setObjectName("spinBox_Node") + self.horizontalLayout_4.addWidget(self.spinBox_Node) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem4) + self.verticalLayout.addLayout(self.horizontalLayout_4) + self.horizontalLayout_5 = QtWidgets.QHBoxLayout() + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.label_7 = QtWidgets.QLabel(parent=Dialog) + self.label_7.setObjectName("label_7") + self.horizontalLayout_5.addWidget(self.label_7) + self.lineEdit_Last = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Last.setObjectName("lineEdit_Last") + self.horizontalLayout_5.addWidget(self.lineEdit_Last) + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_5.addItem(spacerItem5) + self.verticalLayout.addLayout(self.horizontalLayout_5) + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.label_8 = QtWidgets.QLabel(parent=Dialog) + self.label_8.setObjectName("label_8") + self.horizontalLayout_6.addWidget(self.label_8) + self.lineEdit_Max = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Max.setObjectName("lineEdit_Max") + self.horizontalLayout_6.addWidget(self.lineEdit_Max) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_6.addItem(spacerItem6) + self.verticalLayout.addLayout(self.horizontalLayout_6) + self.checkBox_Cycle = QtWidgets.QCheckBox(parent=Dialog) + self.checkBox_Cycle.setObjectName("checkBox_Cycle") + self.verticalLayout.addWidget(self.checkBox_Cycle) + spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout.addItem(spacerItem7) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Pointer Scan")) + self.label.setText(_translate("Dialog", "Address")) + self.label_2.setText(_translate("Dialog", "Depth")) + self.label_3.setText(_translate("Dialog", "Scan Range")) + self.label_4.setText(_translate("Dialog", "<->")) + self.label_5.setText(_translate("Dialog", "LRange")) + self.label_6.setText(_translate("Dialog", "Minimum Chain Length")) + self.label_7.setText(_translate("Dialog", "Last Offset (optional)")) + self.label_8.setText(_translate("Dialog", "Max Result Count")) + self.checkBox_Cycle.setText(_translate("Dialog", "Circular Reference")) diff --git a/GUI/PointerScanDialog.ui b/GUI/PointerScanDialog.ui new file mode 100644 index 00000000..efc5bc5f --- /dev/null +++ b/GUI/PointerScanDialog.ui @@ -0,0 +1,291 @@ + + + Dialog + + + + 0 + 0 + 386 + 320 + + + + Pointer Scan + + + + + + + + + + Address + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Depth + + + + + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Scan Range + + + + + + + + + + <-> + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + LRange + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Minimum Chain Length + + + + + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Last Offset (optional) + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Max Result Count + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Circular Reference + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/GUI/PointerScannerWindow.py b/GUI/PointerScannerWindow.py new file mode 100644 index 00000000..a129efef --- /dev/null +++ b/GUI/PointerScannerWindow.py @@ -0,0 +1,81 @@ +# Form implementation generated from reading ui file 'PointerScannerWindow.ui' +# +# Created by: PyQt6 UI code generator 6.4.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(783, 691) + self.centralwidget = QtWidgets.QWidget(parent=MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout.setObjectName("gridLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.comboBox_ValueType = QtWidgets.QComboBox(parent=self.centralwidget) + self.comboBox_ValueType.setObjectName("comboBox_ValueType") + self.horizontalLayout.addWidget(self.comboBox_ValueType) + spacerItem = QtWidgets.QSpacerItem(684, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.textBrowser = QtWidgets.QTextBrowser(parent=self.centralwidget) + self.textBrowser.setObjectName("textBrowser") + self.gridLayout.addWidget(self.textBrowser, 1, 0, 1, 1) + self.tableWidget_ScanResult = QtWidgets.QTableWidget(parent=self.centralwidget) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_ScanResult.setFont(font) + self.tableWidget_ScanResult.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_ScanResult.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) + self.tableWidget_ScanResult.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_ScanResult.setObjectName("tableWidget_ScanResult") + self.tableWidget_ScanResult.setColumnCount(0) + self.tableWidget_ScanResult.setRowCount(0) + self.tableWidget_ScanResult.horizontalHeader().setStretchLastSection(True) + self.tableWidget_ScanResult.verticalHeader().setVisible(False) + self.tableWidget_ScanResult.verticalHeader().setDefaultSectionSize(16) + self.tableWidget_ScanResult.verticalHeader().setMinimumSectionSize(16) + self.gridLayout.addWidget(self.tableWidget_ScanResult, 2, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(parent=MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 783, 22)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(parent=self.menubar) + self.menuFile.setObjectName("menuFile") + self.menuRe_scan = QtWidgets.QMenu(parent=self.menubar) + self.menuRe_scan.setObjectName("menuRe_scan") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.actionOpen = QtGui.QAction(parent=MainWindow) + self.actionOpen.setObjectName("actionOpen") + self.actionSave = QtGui.QAction(parent=MainWindow) + self.actionSave.setObjectName("actionSave") + self.actionRescan_memory = QtGui.QAction(parent=MainWindow) + self.actionRescan_memory.setObjectName("actionRescan_memory") + self.menuFile.addAction(self.actionOpen) + self.menuFile.addAction(self.actionSave) + self.menuRe_scan.addAction(self.actionRescan_memory) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuRe_scan.menuAction()) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "Pointer Scanner")) + self.tableWidget_ScanResult.setSortingEnabled(True) + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.menuRe_scan.setTitle(_translate("MainWindow", "Pointer Scanner")) + self.actionOpen.setText(_translate("MainWindow", "Open")) + self.actionSave.setText(_translate("MainWindow", "Save")) + self.actionRescan_memory.setText(_translate("MainWindow", "Rescan memory")) diff --git a/GUI/PointerScannerWindow.ui b/GUI/PointerScannerWindow.ui new file mode 100644 index 00000000..39759cb3 --- /dev/null +++ b/GUI/PointerScannerWindow.ui @@ -0,0 +1,120 @@ + + + MainWindow + + + + 0 + 0 + 783 + 691 + + + + Pointer Scanner + + + + + + + + + + + + Qt::Horizontal + + + + 684 + 20 + + + + + + + + + + + + + + Monospace + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + false + + + 16 + + + 16 + + + + + + + + + 0 + 0 + 783 + 22 + + + + + File + + + + + + + Pointer Scanner + + + + + + + + + + Open + + + + + Save + + + + + Rescan memory + + + + + + diff --git a/PINCE.py b/PINCE.py index 6f26fdea..8d2930f2 100755 --- a/PINCE.py +++ b/PINCE.py @@ -134,6 +134,8 @@ from GUI.ReferencedCallsWidget import Ui_Form as ReferencedCallsWidget from GUI.ExamineReferrersWidget import Ui_Form as ExamineReferrersWidget from GUI.RestoreInstructionsWidget import Ui_Form as RestoreInstructionsWidget +from GUI.PointerScanDialog import Ui_Dialog as PointerScanDialog +from GUI.PointerScannerWindow import Ui_MainWindow as PointerScannerWindow from GUI.AbstractTableModels.HexModel import QHexModel from GUI.AbstractTableModels.AsciiModel import QAsciiModel @@ -723,6 +725,8 @@ def treeWidget_AddressTable_context_menu_event(self, event): browse_region = menu.addAction(f"{tr.BROWSE_MEMORY_REGION}[Ctrl+B]") disassemble = menu.addAction(f"{tr.DISASSEMBLE_ADDRESS}[Ctrl+D]") menu.addSeparator() + pointer_scan = menu.addAction(tr.POINTER_SCAN) + menu.addSeparator() what_writes = menu.addAction(tr.WHAT_WRITES) what_reads = menu.addAction(tr.WHAT_READS) what_accesses = menu.addAction(tr.WHAT_ACCESSES) @@ -746,6 +750,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): freeze_menu.menuAction(), browse_region, disassemble, + pointer_scan, what_writes, what_reads, what_accesses, @@ -793,6 +798,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): freeze_dec: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DECREMENT), browse_region: self.browse_region_for_selected_row, disassemble: self.disassemble_selected_row, + pointer_scan: self.exec_pointer_scan_dialog, what_writes: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.WRITE_ONLY), what_reads: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.READ_ONLY), what_accesses: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.BOTH), @@ -808,6 +814,16 @@ def treeWidget_AddressTable_context_menu_event(self, event): except KeyError: pass + def exec_pointer_scan_dialog(self): + selected_row = guiutils.get_current_item(self.treeWidget_AddressTable) + if not selected_row: + return + address = selected_row.text(ADDR_COL).strip("P->") + dialog = PointerScanDialogForm(self, address) + if dialog.exec(): + pointer_window = PointerScannerWindowForm(self) + pointer_window.show() + def exec_track_watchpoint_widget(self, watchpoint_type): selected_row = guiutils.get_current_item(self.treeWidget_AddressTable) if not selected_row: @@ -6282,6 +6298,27 @@ def copy_to_clipboard(row): pass +class PointerScanDialogForm(QDialog, PointerScanDialog): + def __init__(self, parent, address): + super().__init__(parent) + self.setupUi(self) + self.lineEdit_Address.setText(address) + guiutils.center_to_parent(self) + + +class PointerScannerWindowForm(QMainWindow, PointerScannerWindow): + def __init__(self, parent): + super().__init__(parent) + self.setupUi(self) + self.tableWidget_ScanResult.hide() + self.actionRescan_memory.triggered.connect(self.rescan) + guiutils.center_to_parent(self) + + def rescan(self): + dialog = PointerScanDialogForm(self, "0x0") + dialog.exec() + + def handle_exit(): global exiting exiting = 1 diff --git a/tr/tr.py b/tr/tr.py index 3d786ed0..73a68279 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -75,6 +75,7 @@ def translate(): COPY = QT_TR_NOOP("Copy") PASTE = QT_TR_NOOP("Paste") PASTE_INSIDE = QT_TR_NOOP("Paste inside") + POINTER_SCAN = QT_TR_NOOP("Pointer scan for this address (WIP)") WHAT_WRITES = QT_TR_NOOP("Find out what writes to this address") WHAT_READS = QT_TR_NOOP("Find out what reads this address") WHAT_ACCESSES = QT_TR_NOOP("Find out what accesses this address") From 4e6514478057011da67f96b3d2e014af6d9c3e3b Mon Sep 17 00:00:00 2001 From: brkzlr Date: Wed, 15 May 2024 14:42:15 +0100 Subject: [PATCH 419/487] Update CONTRIBUTING.md about formatter --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fe7b3740..008376a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,9 @@ - [tests](./libpince/gdb_python_scripts/tests) - An example for .so extension, read more [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) # Code Style -Formatting style is black defaults, except line length is 120. You can use black without parameters since we already use `pyproject.toml` for this setting. Please do not format automatically generated files under GUI folder. Your changes will be overwritten by Qt Designer. More info at [UI Files](#ui-files) +Formatting style is [Black](https://github.com/psf/black) defaults, except line length is 120. You can use Black without parameters since we already use `pyproject.toml` for this setting. + +***You must format the files you changed using Black before you open a PR!*** Please do not format automatically generated files under GUI folder. Your changes will be overwritten by Qt Designer. More info at [UI Files](#ui-files) - Max characters per line: 120 - Variable naming for libpince: - Classes: PascalCase From ad6ba1acd41f3e832b3a0eabf1063a1c7f954df8 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Thu, 16 May 2024 20:03:13 +0100 Subject: [PATCH 420/487] Add initial pointer scanning support by integrating libptrscan --- .gitignore | 2 +- GUI/PointerScanDialog.py | 115 +++++++++++++++++------ GUI/PointerScanDialog.ui | 182 ++++++++++++++++++++++++++++++++---- GUI/PointerScannerWindow.py | 43 ++++----- GUI/PointerScannerWindow.ui | 72 +++++++------- PINCE.py | 85 ++++++++++++++++- ci/package.sh | 11 +++ install_pince.sh | 22 +++++ libpince/utils.py | 4 + 9 files changed, 430 insertions(+), 106 deletions(-) diff --git a/.gitignore b/.gitignore index 1b1135a9..dbd87125 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,8 @@ __pycache__/ .vscode/* !.vscode/launch.json !.vscode/settings.json -libscanmem.so* libpince/libscanmem/* +libpince/libptrscan/* *.directory *.lprof *.qm diff --git a/GUI/PointerScanDialog.py b/GUI/PointerScanDialog.py index ecb93641..fc92dca8 100644 --- a/GUI/PointerScanDialog.py +++ b/GUI/PointerScanDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'PointerScanDialog.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.7.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,7 +12,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(386, 320) + Dialog.resize(386, 390) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.verticalLayout = QtWidgets.QVBoxLayout() @@ -32,6 +32,7 @@ def setupUi(self, Dialog): self.horizontalLayout.addWidget(self.label_2) self.spinBox_Depth = QtWidgets.QSpinBox(parent=Dialog) self.spinBox_Depth.setMinimum(1) + self.spinBox_Depth.setProperty("value", 3) self.spinBox_Depth.setObjectName("spinBox_Depth") self.horizontalLayout.addWidget(self.spinBox_Depth) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -42,28 +43,73 @@ def setupUi(self, Dialog): self.label_3 = QtWidgets.QLabel(parent=Dialog) self.label_3.setObjectName("label_3") self.horizontalLayout_2.addWidget(self.label_3) - self.lineEdit_ScanRangeStart = QtWidgets.QLineEdit(parent=Dialog) - self.lineEdit_ScanRangeStart.setObjectName("lineEdit_ScanRangeStart") - self.horizontalLayout_2.addWidget(self.lineEdit_ScanRangeStart) + self.spinBox_ScanRangeStart = QtWidgets.QSpinBox(parent=Dialog) + self.spinBox_ScanRangeStart.setMaximum(16777215) + self.spinBox_ScanRangeStart.setDisplayIntegerBase(16) + self.spinBox_ScanRangeStart.setObjectName("spinBox_ScanRangeStart") + self.horizontalLayout_2.addWidget(self.spinBox_ScanRangeStart) self.label_4 = QtWidgets.QLabel(parent=Dialog) self.label_4.setObjectName("label_4") self.horizontalLayout_2.addWidget(self.label_4) - self.lineEdit_ScanRangeEnd = QtWidgets.QLineEdit(parent=Dialog) - self.lineEdit_ScanRangeEnd.setObjectName("lineEdit_ScanRangeEnd") - self.horizontalLayout_2.addWidget(self.lineEdit_ScanRangeEnd) + self.spinBox_ScanRangeEnd = QtWidgets.QSpinBox(parent=Dialog) + self.spinBox_ScanRangeEnd.setSuffix("") + self.spinBox_ScanRangeEnd.setMaximum(16777215) + self.spinBox_ScanRangeEnd.setProperty("value", 1000) + self.spinBox_ScanRangeEnd.setDisplayIntegerBase(16) + self.spinBox_ScanRangeEnd.setObjectName("spinBox_ScanRangeEnd") + self.horizontalLayout_2.addWidget(self.spinBox_ScanRangeEnd) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout_2.addItem(spacerItem2) self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout_7 = QtWidgets.QHBoxLayout() + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.checkBox_Path = QtWidgets.QCheckBox(parent=Dialog) + self.checkBox_Path.setObjectName("checkBox_Path") + self.horizontalLayout_7.addWidget(self.checkBox_Path) + self.lineEdit_Path = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_Path.setEnabled(True) + self.lineEdit_Path.setText("") + self.lineEdit_Path.setDragEnabled(False) + self.lineEdit_Path.setReadOnly(True) + self.lineEdit_Path.setClearButtonEnabled(False) + self.lineEdit_Path.setObjectName("lineEdit_Path") + self.horizontalLayout_7.addWidget(self.lineEdit_Path) + self.pushButton_PathBrowse = QtWidgets.QPushButton(parent=Dialog) + self.pushButton_PathBrowse.setEnabled(False) + self.pushButton_PathBrowse.setObjectName("pushButton_PathBrowse") + self.horizontalLayout_7.addWidget(self.pushButton_PathBrowse) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_7.addItem(spacerItem3) + self.verticalLayout.addLayout(self.horizontalLayout_7) + self.horizontalLayout_8 = QtWidgets.QHBoxLayout() + self.horizontalLayout_8.setObjectName("horizontalLayout_8") + self.label_11 = QtWidgets.QLabel(parent=Dialog) + self.label_11.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label_11.setObjectName("label_11") + self.horizontalLayout_8.addWidget(self.label_11) + self.verticalLayout.addLayout(self.horizontalLayout_8) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.label_5 = QtWidgets.QLabel(parent=Dialog) self.label_5.setObjectName("label_5") self.horizontalLayout_3.addWidget(self.label_5) - self.lineEdit_LRange = QtWidgets.QLineEdit(parent=Dialog) - self.lineEdit_LRange.setObjectName("lineEdit_LRange") - self.horizontalLayout_3.addWidget(self.lineEdit_LRange) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_3.addItem(spacerItem3) + self.spinBox_ScanLRangeStart = QtWidgets.QSpinBox(parent=Dialog) + self.spinBox_ScanLRangeStart.setMaximum(16777215) + self.spinBox_ScanLRangeStart.setProperty("value", 0) + self.spinBox_ScanLRangeStart.setDisplayIntegerBase(16) + self.spinBox_ScanLRangeStart.setObjectName("spinBox_ScanLRangeStart") + self.horizontalLayout_3.addWidget(self.spinBox_ScanLRangeStart) + self.label_9 = QtWidgets.QLabel(parent=Dialog) + self.label_9.setObjectName("label_9") + self.horizontalLayout_3.addWidget(self.label_9) + self.spinBox_ScanLRangeEnd = QtWidgets.QSpinBox(parent=Dialog) + self.spinBox_ScanLRangeEnd.setMaximum(16777215) + self.spinBox_ScanLRangeEnd.setProperty("value", 0) + self.spinBox_ScanLRangeEnd.setDisplayIntegerBase(16) + self.spinBox_ScanLRangeEnd.setObjectName("spinBox_ScanLRangeEnd") + self.horizontalLayout_3.addWidget(self.spinBox_ScanLRangeEnd) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_3.addItem(spacerItem4) self.verticalLayout.addLayout(self.horizontalLayout_3) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") @@ -71,11 +117,12 @@ def setupUi(self, Dialog): self.label_6.setObjectName("label_6") self.horizontalLayout_4.addWidget(self.label_6) self.spinBox_Node = QtWidgets.QSpinBox(parent=Dialog) - self.spinBox_Node.setMinimum(1) + self.spinBox_Node.setMinimum(0) + self.spinBox_Node.setProperty("value", 0) self.spinBox_Node.setObjectName("spinBox_Node") self.horizontalLayout_4.addWidget(self.spinBox_Node) - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem4) + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem5) self.verticalLayout.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") @@ -85,25 +132,27 @@ def setupUi(self, Dialog): self.lineEdit_Last = QtWidgets.QLineEdit(parent=Dialog) self.lineEdit_Last.setObjectName("lineEdit_Last") self.horizontalLayout_5.addWidget(self.lineEdit_Last) - spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_5.addItem(spacerItem5) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_5.addItem(spacerItem6) self.verticalLayout.addLayout(self.horizontalLayout_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.label_8 = QtWidgets.QLabel(parent=Dialog) self.label_8.setObjectName("label_8") self.horizontalLayout_6.addWidget(self.label_8) - self.lineEdit_Max = QtWidgets.QLineEdit(parent=Dialog) - self.lineEdit_Max.setObjectName("lineEdit_Max") - self.horizontalLayout_6.addWidget(self.lineEdit_Max) - spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_6.addItem(spacerItem6) + self.spinBox_Max = QtWidgets.QSpinBox(parent=Dialog) + self.spinBox_Max.setMaximum(1000) + self.spinBox_Max.setProperty("value", 0) + self.spinBox_Max.setObjectName("spinBox_Max") + self.horizontalLayout_6.addWidget(self.spinBox_Max) + spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_6.addItem(spacerItem7) self.verticalLayout.addLayout(self.horizontalLayout_6) self.checkBox_Cycle = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_Cycle.setObjectName("checkBox_Cycle") self.verticalLayout.addWidget(self.checkBox_Cycle) - spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout.addItem(spacerItem7) + spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout.addItem(spacerItem8) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -122,9 +171,17 @@ def retranslateUi(self, Dialog): self.label.setText(_translate("Dialog", "Address")) self.label_2.setText(_translate("Dialog", "Depth")) self.label_3.setText(_translate("Dialog", "Scan Range")) + self.spinBox_ScanRangeStart.setPrefix(_translate("Dialog", "0x")) self.label_4.setText(_translate("Dialog", "<->")) - self.label_5.setText(_translate("Dialog", "LRange")) + self.spinBox_ScanRangeEnd.setPrefix(_translate("Dialog", "0x")) + self.checkBox_Path.setText(_translate("Dialog", "Save Results To File")) + self.pushButton_PathBrowse.setText(_translate("Dialog", "Browse")) + self.label_11.setText(_translate("Dialog", "Optional Parameters (0 or empty will use defaults)")) + self.label_5.setText(_translate("Dialog", "Last Offset Scan Range")) + self.spinBox_ScanLRangeStart.setPrefix(_translate("Dialog", "0x")) + self.label_9.setText(_translate("Dialog", "<->")) + self.spinBox_ScanLRangeEnd.setPrefix(_translate("Dialog", "0x")) self.label_6.setText(_translate("Dialog", "Minimum Chain Length")) - self.label_7.setText(_translate("Dialog", "Last Offset (optional)")) - self.label_8.setText(_translate("Dialog", "Max Result Count")) - self.checkBox_Cycle.setText(_translate("Dialog", "Circular Reference")) + self.label_7.setText(_translate("Dialog", "Last Offset Value")) + self.label_8.setText(_translate("Dialog", "Max Results")) + self.checkBox_Cycle.setText(_translate("Dialog", "Solve Circular References")) diff --git a/GUI/PointerScanDialog.ui b/GUI/PointerScanDialog.ui index efc5bc5f..0263be09 100644 --- a/GUI/PointerScanDialog.ui +++ b/GUI/PointerScanDialog.ui @@ -7,7 +7,7 @@ 0 0 386 - 320 + 390 @@ -31,7 +31,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -53,12 +53,15 @@ 1 + + 3 + - Qt::Horizontal + Qt::Orientation::Horizontal @@ -80,7 +83,17 @@ - + + + 0x + + + 16777215 + + + 16 + + @@ -90,12 +103,28 @@ - + + + + + + 0x + + + 16777215 + + + 1000 + + + 16 + + - Qt::Horizontal + Qt::Orientation::Horizontal @@ -107,22 +136,125 @@ + + + + + + Save Results To File + + + + + + + true + + + + + + false + + + true + + + false + + + + + + + false + + + Browse + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Optional Parameters (0 or empty will use defaults) + + + Qt::AlignmentFlag::AlignCenter + + + + + - LRange + Last Offset Scan Range + + + + + + + 0x + + + 16777215 + + + 0 + + + 16 + + + + + + + <-> - + + + 0x + + + 16777215 + + + 0 + + + 16 + + - Qt::Horizontal + Qt::Orientation::Horizontal @@ -146,14 +278,17 @@ - 1 + 0 + + + 0 - Qt::Horizontal + Qt::Orientation::Horizontal @@ -170,7 +305,7 @@ - Last Offset (optional) + Last Offset Value @@ -180,7 +315,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -197,17 +332,24 @@ - Max Result Count + Max Results - + + + 1000 + + + 0 + + - Qt::Horizontal + Qt::Orientation::Horizontal @@ -222,14 +364,14 @@ - Circular Reference + Solve Circular References - Qt::Vertical + Qt::Orientation::Vertical @@ -242,10 +384,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok diff --git a/GUI/PointerScannerWindow.py b/GUI/PointerScannerWindow.py index a129efef..d2a2fced 100644 --- a/GUI/PointerScannerWindow.py +++ b/GUI/PointerScannerWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'PointerScannerWindow.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.7.0 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -17,17 +17,6 @@ def setupUi(self, MainWindow): self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - self.comboBox_ValueType = QtWidgets.QComboBox(parent=self.centralwidget) - self.comboBox_ValueType.setObjectName("comboBox_ValueType") - self.horizontalLayout.addWidget(self.comboBox_ValueType) - spacerItem = QtWidgets.QSpacerItem(684, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem) - self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) - self.textBrowser = QtWidgets.QTextBrowser(parent=self.centralwidget) - self.textBrowser.setObjectName("textBrowser") - self.gridLayout.addWidget(self.textBrowser, 1, 0, 1, 1) self.tableWidget_ScanResult = QtWidgets.QTableWidget(parent=self.centralwidget) font = QtGui.QFont() font.setFamily("Monospace") @@ -43,9 +32,20 @@ def setupUi(self, MainWindow): self.tableWidget_ScanResult.verticalHeader().setDefaultSectionSize(16) self.tableWidget_ScanResult.verticalHeader().setMinimumSectionSize(16) self.gridLayout.addWidget(self.tableWidget_ScanResult, 2, 0, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.pushButton_Clear = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton_Clear.setObjectName("pushButton_Clear") + self.horizontalLayout.addWidget(self.pushButton_Clear) + spacerItem = QtWidgets.QSpacerItem(684, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.textEdit = QtWidgets.QTextEdit(parent=self.centralwidget) + self.textEdit.setObjectName("textEdit") + self.gridLayout.addWidget(self.textEdit, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(parent=MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 783, 22)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 783, 30)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(parent=self.menubar) self.menuFile.setObjectName("menuFile") @@ -57,12 +57,12 @@ def setupUi(self, MainWindow): MainWindow.setStatusBar(self.statusbar) self.actionOpen = QtGui.QAction(parent=MainWindow) self.actionOpen.setObjectName("actionOpen") - self.actionSave = QtGui.QAction(parent=MainWindow) - self.actionSave.setObjectName("actionSave") + self.actionSaveAs = QtGui.QAction(parent=MainWindow) + self.actionSaveAs.setObjectName("actionSaveAs") self.actionRescan_memory = QtGui.QAction(parent=MainWindow) self.actionRescan_memory.setObjectName("actionRescan_memory") self.menuFile.addAction(self.actionOpen) - self.menuFile.addAction(self.actionSave) + self.menuFile.addAction(self.actionSaveAs) self.menuRe_scan.addAction(self.actionRescan_memory) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuRe_scan.menuAction()) @@ -74,8 +74,9 @@ def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Pointer Scanner")) self.tableWidget_ScanResult.setSortingEnabled(True) - self.menuFile.setTitle(_translate("MainWindow", "File")) - self.menuRe_scan.setTitle(_translate("MainWindow", "Pointer Scanner")) - self.actionOpen.setText(_translate("MainWindow", "Open")) - self.actionSave.setText(_translate("MainWindow", "Save")) - self.actionRescan_memory.setText(_translate("MainWindow", "Rescan memory")) + self.pushButton_Clear.setText(_translate("MainWindow", "Clear")) + self.menuFile.setTitle(_translate("MainWindow", "Fi&le")) + self.menuRe_scan.setTitle(_translate("MainWindow", "Poi&nter Scanner")) + self.actionOpen.setText(_translate("MainWindow", "&Open")) + self.actionSaveAs.setText(_translate("MainWindow", "&Save As...")) + self.actionRescan_memory.setText(_translate("MainWindow", "&Rescan memory")) diff --git a/GUI/PointerScannerWindow.ui b/GUI/PointerScannerWindow.ui index 39759cb3..5f6d7d32 100644 --- a/GUI/PointerScannerWindow.ui +++ b/GUI/PointerScannerWindow.ui @@ -15,29 +15,6 @@ - - - - - - - - - Qt::Horizontal - - - - 684 - 20 - - - - - - - - - @@ -46,13 +23,13 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::SingleSelection + QAbstractItemView::SelectionMode::SingleSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows true @@ -71,6 +48,33 @@ + + + + + + Clear + + + + + + + Qt::Orientation::Horizontal + + + + 684 + 20 + + + + + + + + + @@ -79,19 +83,19 @@ 0 0 783 - 22 + 30 - File + Fi&le - + - Pointer Scanner + Poi&nter Scanner @@ -101,17 +105,17 @@ - Open + &Open - + - Save + &Save As... - Rescan memory + &Rescan memory diff --git a/PINCE.py b/PINCE.py index 8d2930f2..bcaca826 100755 --- a/PINCE.py +++ b/PINCE.py @@ -94,6 +94,7 @@ from libpince import utils, debugcore, typedefs from libpince.libscanmem.scanmem import Scanmem +from libpince.libptrscan.ptrscan import PointerScan, FFIRange, FFIParam from GUI.Settings.themes import get_theme from GUI.Settings.themes import theme_list from GUI.Utils import guiutils @@ -280,6 +281,8 @@ exiting = 0 scanmem = Scanmem(os.path.join(utils.get_libpince_directory(), "libscanmem", "libscanmem.so")) +ptrscan = PointerScan(os.path.join(utils.get_libpince_directory(), "libptrscan", "libptrscan.so")) +ptrscan.set_pointer_offset_symbol("->") threadpool = QThreadPool() # Placeholder number, may have to be changed in the future @@ -1490,6 +1493,7 @@ def attach_to_pid(self, pid: int): if attach_result == typedefs.ATTACH_RESULT.SUCCESSFUL: self.apply_after_init() scanmem.pid(pid) + ptrscan.set_process(pid) self.on_new_process() # TODO: This makes PINCE call on_process_stop twice when attaching @@ -6297,13 +6301,67 @@ def copy_to_clipboard(row): except KeyError: pass - class PointerScanDialogForm(QDialog, PointerScanDialog): def __init__(self, parent, address): super().__init__(parent) self.setupUi(self) self.lineEdit_Address.setText(address) guiutils.center_to_parent(self) + self.checkBox_Path.stateChanged.connect(self.checkBox_Path_stateChanged) + self.pushButton_PathBrowse.clicked.connect(self.pushButton_PathBrowse_clicked) + self.buttonBox.accepted.connect(self.buttonBox_accepted) + + def checkBox_Path_stateChanged(self, state: Qt.CheckState): + if Qt.CheckState(state) == Qt.CheckState.Checked: + self.pushButton_PathBrowse.setEnabled(True) + filename = f"{utils.get_process_name(debugcore.currentpid)}.scandata" + self.lineEdit_Path.setText(os.getcwd() + f"/{filename}") + else: + self.pushButton_PathBrowse.setEnabled(False) + self.lineEdit_Path.clear() + + def pushButton_PathBrowse_clicked(self): + scan_filter = "Pointer Scan Data (*.scandata)" + filename, _ = QFileDialog.getSaveFileName(parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter) + if filename != "": + if not re.search(r"\.scandata$", filename): + filename = filename + ".scandata" + self.lineEdit_Path.setText(filename) + + def buttonBox_accepted(self): + params: FFIParam = FFIParam() + try: + addr_val = int(self.lineEdit_Address.text(), 16) + except ValueError: + addr_val = 0 + params.addr(addr_val) + params.depth(self.spinBox_Depth.value()) + params.srange(FFIRange(self.spinBox_ScanRangeStart.value(), self.spinBox_ScanRangeEnd.value())) + lrange_start = self.spinBox_ScanLRangeStart.value() + lrange_end = self.spinBox_ScanLRangeEnd.value() + if lrange_start == 0 and lrange_end == 0: + lrange_val = None + else: + lrange_val = FFIRange(lrange_start, lrange_end) + params.lrange(lrange_val) + params.node(utils.return_optional_int(self.spinBox_Node.value())) + try: + last_val = int(self.lineEdit_Last.text(), 16) + except ValueError: + last_val = None + params.last(last_val) + params.max(utils.return_optional_int(self.spinBox_Max.value())) + params.cycle(self.checkBox_Cycle.isChecked()) + modules = ptrscan.list_modules_pince() # TODO: maybe cache this and let user refresh with a button + ptrscan.set_modules(modules) # TODO: maybe cache this and let user refresh with a button + ptrscan.create_pointer_map() # TODO: maybe cache this and let user refresh with a button + if self.checkBox_Path.isChecked(): + filename = self.lineEdit_Path.text() + if os.path.isfile(filename): + os.remove(filename) + else: + filename = None + ptrscan.scan_pointer_chain(params, filename) class PointerScannerWindowForm(QMainWindow, PointerScannerWindow): @@ -6311,9 +6369,34 @@ def __init__(self, parent): super().__init__(parent) self.setupUi(self) self.tableWidget_ScanResult.hide() + self.pushButton_Clear.pressed.connect(self.pushButton_Clear_pressed) + self.actionOpen.triggered.connect(self.actionOpen_triggered) + self.actionSaveAs.triggered.connect(self.actionSaveAs_triggered) self.actionRescan_memory.triggered.connect(self.rescan) guiutils.center_to_parent(self) + def pushButton_Clear_pressed(self): + self.textEdit.clear() + + def actionOpen_triggered(self): + scan_filter = "Pointer Scan Data (*.scandata)" + filename, _ = QFileDialog.getOpenFileName(parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter) + if filename != "": + self.textEdit.clear() + with open(filename) as file: + lines = file.read().split(os.linesep) + for line in lines: + self.textEdit.append(line) + + def actionSaveAs_triggered(self): + scan_filter = "Pointer Scan Data (*.scandata)" + filename, _ = QFileDialog.getSaveFileName(parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter) + if filename != "": + if not re.search(r"\.scandata$", filename): + filename = filename + ".scandata" + with open(filename, "w") as file: + file.write(self.textEdit.toPlainText()) + def rescan(self): dialog = PointerScanDialogForm(self, "0x0") dialog.exec() diff --git a/ci/package.sh b/ci/package.sh index ab37f93f..d14252ef 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -101,6 +101,17 @@ cp --preserve libscanmem.so ../libpince/libscanmem cp --preserve wrappers/scanmem.py ../libpince/libscanmem cd .. +# Install libptrscan +if [ ! -d "libpince/libptrscan" ]; then + mkdir libpince/libptrscan +fi +pushd libpince/libptrscan +wget https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.zip || exit_on_failure +unzip -j -u libptrscan_pince-x86_64-unknown-linux-gnu.zip || exit_on_failure +rm -f libptrscan_pince-x86_64-unknown-linux-gnu.zip +mv libptrscan_pince.so libptrscan.so +popd + # Compile translations ${LRELEASE_CMD} i18n/ts/* || exit_on_failure mkdir -p i18n/qm diff --git a/install_pince.sh b/install_pince.sh index a3b774bd..d84f7454 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -91,6 +91,27 @@ install_libscanmem() { return 0 } +install_libptrscan() { + echo "Downloading libptrscan" + + if [ ! -d "libpince/libptrscan" ]; then + mkdir libpince/libptrscan + chown -R "${CURRENT_USER}":"${CURRENT_USER}" libpince/libptrscan + fi + ( + pushd libpince/libptrscan + # Source code download as we might be forced to distribute it due to licence + wget https://github.com/kekeimiku/PointerSearcher-X/archive/refs/tags/v0.7.3-dylib.tar.gz || return 1 + # Actual .so and py wrapper + wget https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.zip || return 1 + unzip -j -u libptrscan_pince-x86_64-unknown-linux-gnu.zip || return 1 + rm -f libptrscan_pince-x86_64-unknown-linux-gnu.zip + mv libptrscan_pince.so libptrscan.so + popd + ) || return 1 + return 0 +} + ask_pkg_mgr() { echo echo "Your distro is not officially supported! Trying to install anyway." @@ -207,6 +228,7 @@ pip3 install --upgrade pip || exit_on_error pip3 install -r requirements.txt || exit_on_error install_libscanmem || exit_on_error +install_libptrscan || exit_on_error compile_translations || exit_on_error diff --git a/libpince/utils.py b/libpince/utils.py index a5c6573b..5dbcfd12 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -1189,3 +1189,7 @@ def upper_hex(hex_str: str): if not regexes.hex_number_gui.match(hex_str): return hex_str return hex_str.upper().replace("X", "x") + + +def return_optional_int(val: int) -> int | None: + return None if val == 0 else val From 9ad2424fc2c49f60a76a4b10d2f9bea5ccc6f9d4 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Thu, 16 May 2024 22:33:18 +0100 Subject: [PATCH 421/487] Fix About menu error in AppImage --- PINCE.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index bcaca826..092dc0ae 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2850,9 +2850,10 @@ def __init__(self, parent): self.setWindowFlags(Qt.WindowType.Window) # This section has untranslated text since it's just a placeholder - license_text = open("COPYING").read() - authors_text = open("AUTHORS").read() - thanks_text = open("THANKS").read() + pince_dir = utils.get_script_directory() + license_text = open(f"{pince_dir}/COPYING").read() + authors_text = open(f"{pince_dir}/AUTHORS").read() + thanks_text = open(f"{pince_dir}/THANKS").read() self.textBrowser_License.setPlainText(license_text) self.textBrowser_Contributors.append( "This is only a placeholder, this section may look different when the project finishes" From e899beed9aa4d4ccf45081ad891085a9c3c4f38c Mon Sep 17 00:00:00 2001 From: brkzlr Date: Fri, 17 May 2024 08:53:30 +0100 Subject: [PATCH 422/487] Change installer and packager to use cURL instead of wget. Also change libptrscan from .zip to .tar.gz --- ci/package.sh | 14 +++++++------- install_pince.sh | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ci/package.sh b/ci/package.sh index d14252ef..4a08524c 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -53,11 +53,11 @@ case $OS_NAME in esac # Download necessary tools -wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +curl -L -O https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage DEPLOYTOOL=./linuxdeploy-x86_64.AppImage chmod +x $DEPLOYTOOL -wget https://raw.githubusercontent.com/TheAssassin/linuxdeploy-plugin-conda/master/linuxdeploy-plugin-conda.sh +curl -L -O https://raw.githubusercontent.com/TheAssassin/linuxdeploy-plugin-conda/master/linuxdeploy-plugin-conda.sh CONDAPLUGIN=./linuxdeploy-plugin-conda.sh chmod +x $CONDAPLUGIN @@ -106,9 +106,9 @@ if [ ! -d "libpince/libptrscan" ]; then mkdir libpince/libptrscan fi pushd libpince/libptrscan -wget https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.zip || exit_on_failure -unzip -j -u libptrscan_pince-x86_64-unknown-linux-gnu.zip || exit_on_failure -rm -f libptrscan_pince-x86_64-unknown-linux-gnu.zip +curl -L -o libptrscan.tar.gz https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.tar.gz || exit_on_failure +tar xf libptrscan.tar.gz --strip-components 1 || exit_on_failure +rm -f libptrscan.tar.gz mv libptrscan_pince.so libptrscan.so popd @@ -150,8 +150,8 @@ INSTALLDIR=$(pwd)/AppDir export CONDA_PREFIX="$(readlink -f $INSTALLDIR/usr/conda)" # Grab latest GDB at time of writing and compile it with our conda Python -wget "https://ftp.gnu.org/gnu/gdb/gdb-14.2.tar.gz" -tar xvf gdb-14.2.tar.gz +curl -L -O "https://ftp.gnu.org/gnu/gdb/gdb-14.2.tar.gz" +tar xf gdb-14.2.tar.gz rm gdb-14.2.tar.gz cd gdb-14.2 ./configure --with-python="$(readlink -f ../wrapper.sh)" --prefix=/usr || exit_on_failure diff --git a/install_pince.sh b/install_pince.sh index d84f7454..18bc3e4e 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -101,11 +101,11 @@ install_libptrscan() { ( pushd libpince/libptrscan # Source code download as we might be forced to distribute it due to licence - wget https://github.com/kekeimiku/PointerSearcher-X/archive/refs/tags/v0.7.3-dylib.tar.gz || return 1 + curl -L -O https://github.com/kekeimiku/PointerSearcher-X/archive/refs/tags/v0.7.3-dylib.tar.gz || return 1 # Actual .so and py wrapper - wget https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.zip || return 1 - unzip -j -u libptrscan_pince-x86_64-unknown-linux-gnu.zip || return 1 - rm -f libptrscan_pince-x86_64-unknown-linux-gnu.zip + curl -L -o libptrscan.tar.gz https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.tar.gz || return 1 + tar xf libptrscan.tar.gz --strip-components 1 || return 1 + rm -f libptrscan.tar.gz mv libptrscan_pince.so libptrscan.so popd ) || return 1 From 49c4caad9d0256efe583580725ebd58726fd5285 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Fri, 17 May 2024 10:51:32 +0100 Subject: [PATCH 423/487] Change pointer scanner GUI to inform user of scan start --- GUI/PointerScanDialog.py | 2 +- GUI/PointerScanDialog.ui | 2 +- PINCE.py | 24 +++++++++++++++++++++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/GUI/PointerScanDialog.py b/GUI/PointerScanDialog.py index fc92dca8..fa517221 100644 --- a/GUI/PointerScanDialog.py +++ b/GUI/PointerScanDialog.py @@ -155,7 +155,7 @@ def setupUi(self, Dialog): self.verticalLayout.addItem(spacerItem8) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel) self.buttonBox.setObjectName("buttonBox") self.verticalLayout.addWidget(self.buttonBox) self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) diff --git a/GUI/PointerScanDialog.ui b/GUI/PointerScanDialog.ui index 0263be09..c42fc3f6 100644 --- a/GUI/PointerScanDialog.ui +++ b/GUI/PointerScanDialog.ui @@ -387,7 +387,7 @@ Qt::Orientation::Horizontal - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + QDialogButtonBox::StandardButton::Cancel diff --git a/PINCE.py b/PINCE.py index 092dc0ae..8d59e4b5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -6310,7 +6310,10 @@ def __init__(self, parent, address): guiutils.center_to_parent(self) self.checkBox_Path.stateChanged.connect(self.checkBox_Path_stateChanged) self.pushButton_PathBrowse.clicked.connect(self.pushButton_PathBrowse_clicked) - self.buttonBox.accepted.connect(self.buttonBox_accepted) + self.scan_button = self.buttonBox.addButton("Scan", QDialogButtonBox.ButtonRole.ActionRole) + if self.scan_button: + self.scan_button.clicked.connect(self.scan_button_clicked) + self.ptrscan_thread: Worker | None = None def checkBox_Path_stateChanged(self, state: Qt.CheckState): if Qt.CheckState(state) == Qt.CheckState.Checked: @@ -6329,7 +6332,17 @@ def pushButton_PathBrowse_clicked(self): filename = filename + ".scandata" self.lineEdit_Path.setText(filename) - def buttonBox_accepted(self): + def reject(self): + if self.ptrscan_thread: + return + return super().reject() + + def scan_button_clicked(self): + global threadpool + if debugcore.currentpid == -1: + return + self.scan_button.setText("Scanning") + self.buttonBox.setEnabled(False) params: FFIParam = FFIParam() try: addr_val = int(self.lineEdit_Address.text(), 16) @@ -6362,7 +6375,12 @@ def buttonBox_accepted(self): os.remove(filename) else: filename = None - ptrscan.scan_pointer_chain(params, filename) + self.ptrscan_thread = Worker(ptrscan.scan_pointer_chain, params, filename) + self.ptrscan_thread.signals.finished.connect(self.ptrscan_callback) + threadpool.start(self.ptrscan_thread) + + def ptrscan_callback(self): + self.accept() class PointerScannerWindowForm(QMainWindow, PointerScannerWindow): From faf2bd648ddc8a67139cfa79da52e9f4c2bf91cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 17 May 2024 13:26:09 +0300 Subject: [PATCH 424/487] Replace pushd and popd commands with cd --- ci/package.sh | 4 ++-- install_pince.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/package.sh b/ci/package.sh index 4a08524c..6d31577e 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -105,12 +105,12 @@ cd .. if [ ! -d "libpince/libptrscan" ]; then mkdir libpince/libptrscan fi -pushd libpince/libptrscan +cd libpince/libptrscan curl -L -o libptrscan.tar.gz https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.tar.gz || exit_on_failure tar xf libptrscan.tar.gz --strip-components 1 || exit_on_failure rm -f libptrscan.tar.gz mv libptrscan_pince.so libptrscan.so -popd +cd ../.. # Compile translations ${LRELEASE_CMD} i18n/ts/* || exit_on_failure diff --git a/install_pince.sh b/install_pince.sh index 18bc3e4e..80ef65cb 100755 --- a/install_pince.sh +++ b/install_pince.sh @@ -99,7 +99,7 @@ install_libptrscan() { chown -R "${CURRENT_USER}":"${CURRENT_USER}" libpince/libptrscan fi ( - pushd libpince/libptrscan + cd libpince/libptrscan # Source code download as we might be forced to distribute it due to licence curl -L -O https://github.com/kekeimiku/PointerSearcher-X/archive/refs/tags/v0.7.3-dylib.tar.gz || return 1 # Actual .so and py wrapper @@ -107,7 +107,7 @@ install_libptrscan() { tar xf libptrscan.tar.gz --strip-components 1 || return 1 rm -f libptrscan.tar.gz mv libptrscan_pince.so libptrscan.so - popd + cd ../.. ) || return 1 return 0 } From 63674e9753228ee82b763632bb69922de590e81a Mon Sep 17 00:00:00 2001 From: brkzlr Date: Fri, 17 May 2024 20:17:25 +0100 Subject: [PATCH 425/487] Make pointer scanning interruptable --- PINCE.py | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/PINCE.py b/PINCE.py index 8d59e4b5..d05c0ed9 100755 --- a/PINCE.py +++ b/PINCE.py @@ -306,6 +306,22 @@ def run(self): self.signals.finished.emit() +class InterruptableWorker(QThread): + def __init__(self, fn, *args, **kwargs): + super().__init__() + self.fn = fn + self.args = args + self.kwargs = kwargs + self.signals = WorkerSignals() + + def run(self): + self.fn(*self.args, **self.kwargs) + self.signals.finished.emit() + + def stop(self): + self.terminate() + + def except_hook(exception_type, value, tb): focused_widget = app.focusWidget() if focused_widget and exception_type == typedefs.GDBInitializeException: @@ -6313,15 +6329,17 @@ def __init__(self, parent, address): self.scan_button = self.buttonBox.addButton("Scan", QDialogButtonBox.ButtonRole.ActionRole) if self.scan_button: self.scan_button.clicked.connect(self.scan_button_clicked) - self.ptrscan_thread: Worker | None = None + self.ptrscan_thread: InterruptableWorker | None = None + self.ptrmap_filename: str | None = None def checkBox_Path_stateChanged(self, state: Qt.CheckState): if Qt.CheckState(state) == Qt.CheckState.Checked: self.pushButton_PathBrowse.setEnabled(True) - filename = f"{utils.get_process_name(debugcore.currentpid)}.scandata" - self.lineEdit_Path.setText(os.getcwd() + f"/{filename}") + self.ptrmap_filename = f"{utils.get_process_name(debugcore.currentpid)}.scandata" + self.lineEdit_Path.setText(os.getcwd() + f"/{self.ptrmap_filename}") else: self.pushButton_PathBrowse.setEnabled(False) + self.ptrmap_filename = None self.lineEdit_Path.clear() def pushButton_PathBrowse_clicked(self): @@ -6330,19 +6348,21 @@ def pushButton_PathBrowse_clicked(self): if filename != "": if not re.search(r"\.scandata$", filename): filename = filename + ".scandata" + self.ptrmap_filename = filename self.lineEdit_Path.setText(filename) def reject(self): if self.ptrscan_thread: - return + self.ptrscan_thread.stop() return super().reject() def scan_button_clicked(self): - global threadpool if debugcore.currentpid == -1: return self.scan_button.setText("Scanning") - self.buttonBox.setEnabled(False) + self.scan_button.setEnabled(False) + self.pushButton_PathBrowse.setEnabled(False) + self.checkBox_Path.setEnabled(False) params: FFIParam = FFIParam() try: addr_val = int(self.lineEdit_Address.text(), 16) @@ -6369,15 +6389,11 @@ def scan_button_clicked(self): modules = ptrscan.list_modules_pince() # TODO: maybe cache this and let user refresh with a button ptrscan.set_modules(modules) # TODO: maybe cache this and let user refresh with a button ptrscan.create_pointer_map() # TODO: maybe cache this and let user refresh with a button - if self.checkBox_Path.isChecked(): - filename = self.lineEdit_Path.text() - if os.path.isfile(filename): - os.remove(filename) - else: - filename = None - self.ptrscan_thread = Worker(ptrscan.scan_pointer_chain, params, filename) + if self.ptrmap_filename and os.path.isfile(self.ptrmap_filename): + os.remove(self.ptrmap_filename) + self.ptrscan_thread = InterruptableWorker(ptrscan.scan_pointer_chain, params, self.ptrmap_filename) self.ptrscan_thread.signals.finished.connect(self.ptrscan_callback) - threadpool.start(self.ptrscan_thread) + self.ptrscan_thread.start() def ptrscan_callback(self): self.accept() From 10656eca53c307775fd941f6a7b08ca680ef2c0b Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 18 May 2024 18:04:45 +0100 Subject: [PATCH 426/487] Fix incorrect scan types for String and AOB value types --- libpince/typedefs.py | 54 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/libpince/typedefs.py b/libpince/typedefs.py index 2d1bdf22..2bc34c5f 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -333,31 +333,37 @@ class SCAN_TYPE: @staticmethod def get_list(scan_mode, value_type): if scan_mode == SCAN_MODE.NEW: - list = [ - SCAN_TYPE.EXACT, - SCAN_TYPE.NOT, - SCAN_TYPE.LESS, - SCAN_TYPE.MORE, - SCAN_TYPE.BETWEEN, - SCAN_TYPE.UNKNOWN, - ] + if value_type == SCAN_INDEX.STRING or value_type == SCAN_INDEX.AOB: + list = [ + SCAN_TYPE.EXACT, + SCAN_TYPE.UNKNOWN, + ] + else: + list = [ + SCAN_TYPE.EXACT, + SCAN_TYPE.NOT, + SCAN_TYPE.LESS, + SCAN_TYPE.MORE, + SCAN_TYPE.BETWEEN, + SCAN_TYPE.UNKNOWN, + ] else: - list = [ - SCAN_TYPE.EXACT, - SCAN_TYPE.NOT, - SCAN_TYPE.INCREASED, - SCAN_TYPE.INCREASED_BY, - SCAN_TYPE.DECREASED, - SCAN_TYPE.DECREASED_BY, - SCAN_TYPE.LESS, - SCAN_TYPE.MORE, - SCAN_TYPE.BETWEEN, - SCAN_TYPE.CHANGED, - SCAN_TYPE.UNCHANGED, - ] - - if value_type == SCAN_INDEX.AOB or value_type == SCAN_INDEX.STRING: - del list[1] + if value_type == SCAN_INDEX.STRING or value_type == SCAN_INDEX.AOB: + list = [SCAN_TYPE.EXACT] + else: + list = [ + SCAN_TYPE.EXACT, + SCAN_TYPE.NOT, + SCAN_TYPE.INCREASED, + SCAN_TYPE.INCREASED_BY, + SCAN_TYPE.DECREASED, + SCAN_TYPE.DECREASED_BY, + SCAN_TYPE.LESS, + SCAN_TYPE.MORE, + SCAN_TYPE.BETWEEN, + SCAN_TYPE.CHANGED, + SCAN_TYPE.UNCHANGED, + ] return list From e753a8f2554655839b16bbcd7bac47f5e47346f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 19 May 2024 15:11:31 +0300 Subject: [PATCH 427/487] Fix tracer --- GUI/TraceInstructionsPromptDialog.py | 29 +- GUI/TraceInstructionsPromptDialog.ui | 38 +-- PINCE.py | 91 +++---- libpince/debugcore.py | 265 ++++++++++--------- libpince/gdb_python_scripts/gdbextensions.py | 82 +----- libpince/typedefs.py | 3 +- libpince/utils.py | 20 +- tr/tr.py | 1 - 8 files changed, 194 insertions(+), 335 deletions(-) diff --git a/GUI/TraceInstructionsPromptDialog.py b/GUI/TraceInstructionsPromptDialog.py index 7006c7c6..3dfec4c4 100644 --- a/GUI/TraceInstructionsPromptDialog.py +++ b/GUI/TraceInstructionsPromptDialog.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TraceInstructionsPromptDialog.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,7 +12,7 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(306, 381) + Dialog.resize(269, 294) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.verticalLayout = QtWidgets.QVBoxLayout() @@ -42,22 +42,10 @@ def setupUi(self, Dialog): self.checkBox_StopAfterTrace = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_StopAfterTrace.setObjectName("checkBox_StopAfterTrace") self.verticalLayout.addWidget(self.checkBox_StopAfterTrace) - self.checkBox_GeneralRegisters = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_GeneralRegisters.setChecked(True) - self.checkBox_GeneralRegisters.setObjectName("checkBox_GeneralRegisters") - self.verticalLayout.addWidget(self.checkBox_GeneralRegisters) - self.checkBox_FlagRegisters = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_FlagRegisters.setChecked(True) - self.checkBox_FlagRegisters.setObjectName("checkBox_FlagRegisters") - self.verticalLayout.addWidget(self.checkBox_FlagRegisters) - self.checkBox_SegmentRegisters = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_SegmentRegisters.setChecked(True) - self.checkBox_SegmentRegisters.setObjectName("checkBox_SegmentRegisters") - self.verticalLayout.addWidget(self.checkBox_SegmentRegisters) - self.checkBox_FloatRegisters = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_FloatRegisters.setChecked(True) - self.checkBox_FloatRegisters.setObjectName("checkBox_FloatRegisters") - self.verticalLayout.addWidget(self.checkBox_FloatRegisters) + self.checkBox_CollectRegisters = QtWidgets.QCheckBox(parent=Dialog) + self.checkBox_CollectRegisters.setChecked(True) + self.checkBox_CollectRegisters.setObjectName("checkBox_CollectRegisters") + self.verticalLayout.addWidget(self.checkBox_CollectRegisters) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) @@ -81,7 +69,4 @@ def retranslateUi(self, Dialog): self.label_2.setText(_translate("Dialog", "Stop condition(Optional, gdb expression):")) self.checkBox_StepOver.setText(_translate("Dialog", "Step over instead of single step")) self.checkBox_StopAfterTrace.setText(_translate("Dialog", "Stop when tracing ends")) - self.checkBox_GeneralRegisters.setText(_translate("Dialog", "Collect general registers")) - self.checkBox_FlagRegisters.setText(_translate("Dialog", "Collect flag registers")) - self.checkBox_SegmentRegisters.setText(_translate("Dialog", "Collect segment registers")) - self.checkBox_FloatRegisters.setText(_translate("Dialog", "Collect float registers")) + self.checkBox_CollectRegisters.setText(_translate("Dialog", "Collect registers")) diff --git a/GUI/TraceInstructionsPromptDialog.ui b/GUI/TraceInstructionsPromptDialog.ui index 558f3d24..57d4de78 100644 --- a/GUI/TraceInstructionsPromptDialog.ui +++ b/GUI/TraceInstructionsPromptDialog.ui @@ -6,8 +6,8 @@ 0 0 - 306 - 381 + 269 + 294 @@ -74,39 +74,9 @@ - + - Collect general registers - - - true - - - - - - - Collect flag registers - - - true - - - - - - - Collect segment registers - - - true - - - - - - - Collect float registers + Collect registers true diff --git a/PINCE.py b/PINCE.py index d05c0ed9..c2dc3ab3 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4953,21 +4953,8 @@ def get_values(self): else: step_mode = typedefs.STEP_MODE.SINGLE_STEP stop_after_trace = self.checkBox_StopAfterTrace.isChecked() - collect_general_registers = self.checkBox_GeneralRegisters.isChecked() - collect_flag_registers = self.checkBox_FlagRegisters.isChecked() - collect_segment_registers = self.checkBox_SegmentRegisters.isChecked() - collect_float_registers = self.checkBox_FloatRegisters.isChecked() - return ( - max_trace_count, - trigger_condition, - stop_condition, - step_mode, - stop_after_trace, - collect_general_registers, - collect_flag_registers, - collect_segment_registers, - collect_float_registers, - ) + collect_registers = self.checkBox_CollectRegisters.isChecked() + return max_trace_count, trigger_condition, stop_condition, step_mode, stop_after_trace, collect_registers def accept(self): if int(self.lineEdit_MaxTraceCount.text()) >= 1: @@ -4979,18 +4966,17 @@ def accept(self): class TraceInstructionsWaitWidgetForm(QWidget, TraceInstructionsWaitWidget): widget_closed = pyqtSignal() - def __init__(self, parent, address, breakpoint): + def __init__(self, parent, address: str, tracer: debugcore.Tracer): super().__init__(parent) self.setupUi(self) self.status_to_text = { typedefs.TRACE_STATUS.IDLE: tr.WAITING_FOR_BREAKPOINT, typedefs.TRACE_STATUS.CANCELED: tr.TRACING_CANCELED, - typedefs.TRACE_STATUS.PROCESSING: tr.PROCESSING_DATA, typedefs.TRACE_STATUS.FINISHED: tr.TRACING_COMPLETED, } - self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) + self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window) self.address = address - self.breakpoint = breakpoint + self.tracer = tracer media_directory = utils.get_media_directory() self.movie = QMovie(media_directory + "/TraceInstructionsWaitWidget/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) @@ -5000,33 +4986,31 @@ def __init__(self, parent, address, breakpoint): self.movie.setSpeed(100) self.movie.start() self.pushButton_Cancel.clicked.connect(self.close) + tracer_thread = Worker(tracer.tracer_loop) + tracer_thread.signals.finished.connect(self.close) + threadpool.start(tracer_thread) self.status_timer = QTimer() - self.status_timer.setInterval(30) + self.status_timer.setInterval(50) self.status_timer.timeout.connect(self.change_status) self.status_timer.start() guiutils.center_to_parent(self) def change_status(self): - status_info = debugcore.get_trace_instructions_status(self.breakpoint) - if status_info[0] == typedefs.TRACE_STATUS.FINISHED or status_info[0] == typedefs.TRACE_STATUS.PROCESSING: - self.close() - return - if status_info[0] == typedefs.TRACE_STATUS.TRACING: - self.label_StatusText.setText(status_info[1]) + if self.tracer.trace_status == typedefs.TRACE_STATUS.TRACING: + self.label_StatusText.setText(f"{self.tracer.current_trace_count} / {self.tracer.max_trace_count}") else: - self.label_StatusText.setText(self.status_to_text[status_info[0]]) + self.label_StatusText.setText(self.status_to_text[self.tracer.trace_status]) app.processEvents() def closeEvent(self, event: QCloseEvent): self.status_timer.stop() - self.label_StatusText.setText(tr.PROCESSING_DATA) + self.label_StatusText.setText(tr.TRACING_COMPLETED) self.pushButton_Cancel.setVisible(False) self.adjustSize() app.processEvents() - status_info = debugcore.get_trace_instructions_status(self.breakpoint) - if status_info[0] == typedefs.TRACE_STATUS.TRACING or status_info[0] == typedefs.TRACE_STATUS.PROCESSING: - debugcore.cancel_trace_instructions(self.breakpoint) - while debugcore.get_trace_instructions_status(self.breakpoint)[0] != typedefs.TRACE_STATUS.FINISHED: + if self.tracer.trace_status == typedefs.TRACE_STATUS.TRACING: + self.tracer.cancel_trace() + while self.tracer.trace_status != typedefs.TRACE_STATUS.FINISHED: sleep(0.1) app.processEvents() debugcore.delete_breakpoint(self.address) @@ -5039,7 +5023,7 @@ def __init__(self, parent, address="", prompt_dialog=True): super().__init__(parent) self.setupUi(self) self.address = address - self.trace_data = None + self.tracer = debugcore.Tracer() self.treeWidget_InstructionInfo.currentItemChanged.connect(self.display_collected_data) self.treeWidget_InstructionInfo.itemDoubleClicked.connect(self.treeWidget_InstructionInfo_item_double_clicked) self.treeWidget_InstructionInfo.contextMenuEvent = self.treeWidget_InstructionInfo_context_menu_event @@ -5053,14 +5037,13 @@ def __init__(self, parent, address="", prompt_dialog=True): prompt_dialog = TraceInstructionsPromptDialogForm(self) if prompt_dialog.exec(): params = (address,) + prompt_dialog.get_values() - breakpoint = debugcore.trace_instructions(*params) + breakpoint = self.tracer.set_breakpoint(*params) if not breakpoint: QMessageBox.information(self, tr.ERROR, tr.BREAKPOINT_FAILED.format(address)) self.close() return self.showMaximized() - self.breakpoint = breakpoint - self.wait_dialog = TraceInstructionsWaitWidgetForm(self, address, breakpoint) + self.wait_dialog = TraceInstructionsWaitWidgetForm(self, address, self.tracer) self.wait_dialog.widget_closed.connect(self.show_trace_info) self.wait_dialog.show() else: @@ -5076,19 +5059,11 @@ def display_collected_data(self, QTreeWidgetItem_current): self.textBrowser_RegisterInfo.verticalScrollBar().minimum() ) - def show_trace_info(self, trace_data=None): + def show_trace_info(self): self.treeWidget_InstructionInfo.setStyleSheet("QTreeWidget::item{ height: 16px; }") parent = QTreeWidgetItem(self.treeWidget_InstructionInfo) self.treeWidget_InstructionInfo.setRootIndex(self.treeWidget_InstructionInfo.indexFromItem(parent)) - if trace_data: - trace_tree, current_root_index = trace_data - else: - trace_data = debugcore.get_trace_instructions_info(self.breakpoint) - if trace_data: - trace_tree, current_root_index = trace_data - else: - return - self.trace_data = copy.deepcopy(trace_data) + trace_tree, current_root_index = copy.deepcopy(self.tracer.trace_data) while current_root_index is not None: try: current_index = trace_tree[current_root_index][2][0] # Get the first child @@ -5111,7 +5086,7 @@ def save_file(self): file_path = QFileDialog.getSaveFileName(self, tr.SAVE_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] if file_path: file_path = utils.append_file_extension(file_path, "trace") - if not utils.save_file(self.trace_data, file_path): + if not utils.save_file(self.tracer.trace_data, file_path): QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) def load_file(self): @@ -5123,7 +5098,8 @@ def load_file(self): QMessageBox.information(self, tr.ERROR, tr.FILE_LOAD_ERROR.format(file_path)) return self.treeWidget_InstructionInfo.clear() - self.show_trace_info(content) + self.tracer.trace_data = content + self.show_trace_info() def treeWidget_InstructionInfo_context_menu_event(self, event): menu = QMenu() @@ -6318,6 +6294,7 @@ def copy_to_clipboard(row): except KeyError: pass + class PointerScanDialogForm(QDialog, PointerScanDialog): def __init__(self, parent, address): super().__init__(parent) @@ -6344,7 +6321,9 @@ def checkBox_Path_stateChanged(self, state: Qt.CheckState): def pushButton_PathBrowse_clicked(self): scan_filter = "Pointer Scan Data (*.scandata)" - filename, _ = QFileDialog.getSaveFileName(parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter) + filename, _ = QFileDialog.getSaveFileName( + parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter + ) if filename != "": if not re.search(r"\.scandata$", filename): filename = filename + ".scandata" @@ -6386,9 +6365,9 @@ def scan_button_clicked(self): params.last(last_val) params.max(utils.return_optional_int(self.spinBox_Max.value())) params.cycle(self.checkBox_Cycle.isChecked()) - modules = ptrscan.list_modules_pince() # TODO: maybe cache this and let user refresh with a button - ptrscan.set_modules(modules) # TODO: maybe cache this and let user refresh with a button - ptrscan.create_pointer_map() # TODO: maybe cache this and let user refresh with a button + modules = ptrscan.list_modules_pince() # TODO: maybe cache this and let user refresh with a button + ptrscan.set_modules(modules) # TODO: maybe cache this and let user refresh with a button + ptrscan.create_pointer_map() # TODO: maybe cache this and let user refresh with a button if self.ptrmap_filename and os.path.isfile(self.ptrmap_filename): os.remove(self.ptrmap_filename) self.ptrscan_thread = InterruptableWorker(ptrscan.scan_pointer_chain, params, self.ptrmap_filename) @@ -6415,7 +6394,9 @@ def pushButton_Clear_pressed(self): def actionOpen_triggered(self): scan_filter = "Pointer Scan Data (*.scandata)" - filename, _ = QFileDialog.getOpenFileName(parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter) + filename, _ = QFileDialog.getOpenFileName( + parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter + ) if filename != "": self.textEdit.clear() with open(filename) as file: @@ -6425,7 +6406,9 @@ def actionOpen_triggered(self): def actionSaveAs_triggered(self): scan_filter = "Pointer Scan Data (*.scandata)" - filename, _ = QFileDialog.getSaveFileName(parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter) + filename, _ = QFileDialog.getSaveFileName( + parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter + ) if filename != "": if not re.search(r"\.scandata$", filename): filename = filename + ".scandata" diff --git a/libpince/debugcore.py b/libpince/debugcore.py index ecf84678..70f1570b 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -18,7 +18,7 @@ from threading import Lock, Thread, Condition from time import sleep, time from collections import OrderedDict, defaultdict -import pexpect, os, sys, ctypes, pickle, json, shelve, re, struct, io +import pexpect, os, sys, ctypes, pickle, shelve, re, struct, io from . import utils, typedefs, regexes self_pid = os.getpid() @@ -113,6 +113,9 @@ # Return value of the current send_command call will be an empty string cancel_send_command = False +# A boolean value. Used by state_observe_thread to check if a tracing session is active +active_trace = False + #:tag:GDBInformation #:doc: # A string. Holds the last command sent to gdb @@ -301,7 +304,7 @@ def check_inferior_status(): inferior_status = typedefs.INFERIOR_STATUS.STOPPED else: inferior_status = typedefs.INFERIOR_STATUS.RUNNING - if old_status != inferior_status: + if old_status != inferior_status and not active_trace: with status_changed_condition: status_changed_condition.notify_all() @@ -386,15 +389,17 @@ def can_attach(pid): #:tag:Debug -def wait_for_stop(timeout=1): +def wait_for_stop(timeout=0): """Block execution till the inferior stops Args: - timeout (float): Timeout time in seconds + timeout (float): Timeout time in seconds, passing 0 will wait for stop indefinitely """ remaining_time = timeout while inferior_status == typedefs.INFERIOR_STATUS.RUNNING: sleep(typedefs.CONST_TIME.GDB_INPUT_SLEEP) + if timeout == 0: + continue remaining_time -= typedefs.CONST_TIME.GDB_INPUT_SLEEP if remaining_time < 0: break @@ -1885,128 +1890,136 @@ def get_track_breakpoint_info(breakpoint): return output -@execute_with_temporary_interruption -#:tag:Tools -def trace_instructions( - expression, - max_trace_count=1000, - trigger_condition="", - stop_condition="", - step_mode=typedefs.STEP_MODE.SINGLE_STEP, - stop_after_trace=False, - collect_general_registers=True, - collect_flag_registers=True, - collect_segment_registers=True, - collect_float_registers=True, -): - """Starts tracing instructions at the address evaluated by the given expression - There can be only one tracing process at a time, calling this function without waiting the first tracing process - meet an end may cause bizarre behaviour - Use get_trace_instructions_info() to get info about the breakpoint you set - - Args: - expression (str): Any gdb expression - max_trace_count (int): Maximum number of steps will be taken while tracing. Must be greater than or equal to 1 - trigger_condition (str): Optional, any gdb expression. Tracing will start if the condition is met - stop_condition (str): Optional, any gdb expression. Tracing will stop whenever the condition is met - step_mode (int): Can be a member of typedefs.STEP_MODE - stop_after_trace (bool): Inferior won't be continuing after the tracing process - collect_general_registers (bool): Collect general registers while stepping - collect_flag_registers (bool): Collect flag registers while stepping - collect_segment_registers (bool): Collect segment registers while stepping - collect_float_registers (bool): Collect float registers while stepping - - Returns: - str: Number of the breakpoint set - None: If fails to set any breakpoint or if max_trace_count is not valid - """ - if max_trace_count < 1: - print("max_trace_count must be greater than or equal to 1") - return - if type(max_trace_count) != int: - print("max_trace_count must be an integer") - return - breakpoint = add_breakpoint(expression, on_hit=typedefs.BREAKPOINT_ON_HIT.TRACE) - if not breakpoint: - return - modify_breakpoint(expression, typedefs.BREAKPOINT_MODIFY.CONDITION, condition=trigger_condition) - contents_send = (typedefs.TRACE_STATUS.IDLE, "") - trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) - pickle.dump(contents_send, open(trace_status_file, "wb")) - param_str = ( - breakpoint, - max_trace_count, - stop_condition, - step_mode, - stop_after_trace, - collect_general_registers, - collect_flag_registers, - collect_segment_registers, - collect_float_registers, - ) - send_command("commands " + breakpoint + "\npince-trace-instructions " + str(param_str) + "\nend") - return breakpoint - - -#:tag:Tools -def get_trace_instructions_info(breakpoint): - """Gathers the information of the tracing process for the given breakpoint - - Args: - breakpoint (str): breakpoint number, must be returned from trace_instructions() - - Returns: - list: [node1, node2, node3, ...] - node-->[(line_info, register_dict), parent_index, child_index_list] - If an error occurs while reading, an empty list returned instead - - Check PINCE.TraceInstructionsWindowForm.show_trace_info() to see how to traverse the tree - If you just want to search something in the trace data, you can enumerate the tree instead of traversing - Root always be an empty node, it's up to you to use or delete it - Any "call" instruction creates a node in SINGLE_STEP mode - Any "ret" instruction creates a parent regardless of the mode - """ - trace_instructions_file = utils.get_trace_instructions_file(currentpid, breakpoint) - try: - output = json.load(open(trace_instructions_file, "r"), object_pairs_hook=OrderedDict) - except: - output = [] - return output - - -#:tag:Tools -def get_trace_instructions_status(breakpoint): - """Returns the current state of tracing process for given breakpoint - - Args: - breakpoint (str): breakpoint number, must be returned from trace_instructions() - - Returns: - tuple:(status_id, status_str) - - status_id-->(int) A member of typedefs.TRACE_STATUS - status_str-->(str) Status string, only used with typedefs.TRACE_STATUS.TRACING - - Returns a tuple of (None, "") if fails to gather info - """ - trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) - try: - output = pickle.load(open(trace_status_file, "rb")) - except: - output = None, "" - return output - - -#:tag:Tools -def cancel_trace_instructions(breakpoint): - """Finishes the trace instruction process early on for the given breakpoint - - Args: - breakpoint (str): breakpoint number, must be returned from trace_instructions() - """ - status_info = (typedefs.TRACE_STATUS.CANCELED, "") - trace_status_file = utils.get_trace_instructions_status_file(currentpid, breakpoint) - pickle.dump(status_info, open(trace_status_file, "wb")) +class Tracer: + def __init__(self) -> None: + """Use set_breakpoint after init""" + self.breakpoint = "" + self.max_trace_count = 1000 + self.stop_condition = "" + self.step_mode = typedefs.STEP_MODE.SINGLE_STEP + self.stop_after_trace = False + self.collect_registers = True + self.trace_status = typedefs.TRACE_STATUS.IDLE + self.current_trace_count = 0 + self.trace_data = [] + + @execute_with_temporary_interruption + def set_breakpoint( + self, + expression: str, + max_trace_count: int = 1000, + trigger_condition: str = "", + stop_condition: str = "", + step_mode: typedefs.STEP_MODE = typedefs.STEP_MODE.SINGLE_STEP, + stop_after_trace: bool = False, + collect_registers: bool = True, + ) -> str: + """Sets the breakpoint for tracing instructions at the address evaluated by the given expression + There can be only one trace at a time, don't call this function twice before the first trace finishes + Use tracer_loop with a thread to start the actual tracing event + + Args: + expression (str): Any gdb expression + max_trace_count (int): Maximum number of steps taken while tracing. Must be greater than or equal to 1 + trigger_condition (str): Optional, any gdb expression. Tracing will start if the condition is met + stop_condition (str): Optional, any gdb expression. Tracing will stop whenever the condition is met + step_mode (int): Can be a member of typedefs.STEP_MODE + stop_after_trace (bool): Inferior won't be continuing after the tracing process + collect_registers (bool): Collect registers while stepping + + Returns: + str: Number of the breakpoint set + None: If fails to set any breakpoint or if max_trace_count is not valid + """ + if max_trace_count < 1: + print("max_trace_count must be greater than or equal to 1") + return + if type(max_trace_count) != int: + print("max_trace_count must be an integer") + return + breakpoint = add_breakpoint(expression, on_hit=typedefs.BREAKPOINT_ON_HIT.TRACE) + if not breakpoint: + return + modify_breakpoint(expression, typedefs.BREAKPOINT_MODIFY.CONDITION, condition=trigger_condition) + self.trace_status = typedefs.TRACE_STATUS.IDLE + ( + self.breakpoint, + self.max_trace_count, + self.stop_condition, + self.step_mode, + self.stop_after_trace, + self.collect_registers, + ) = (breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_registers) + send_command("commands " + breakpoint + "\npince-trace-instructions " + breakpoint + "\nend") + return breakpoint + + def tracer_loop(self): + global active_trace + active_trace = True + self.current_trace_count = 0 + trace_status_file = utils.get_trace_status_file(currentpid, self.breakpoint) + while self.trace_status == typedefs.TRACE_STATUS.IDLE: + try: + with open(trace_status_file, "r") as trace_file: + self.trace_status = int(trace_file.read()) + except (ValueError, FileNotFoundError): + pass + delete_breakpoint(self.breakpoint) + self.trace_status = typedefs.TRACE_STATUS.TRACING + + # The reason we don't use a tree class is to make the tree json-compatible + # tree format-->[node1, node2, node3, ...] + # node-->[(line_info, register_dict), parent_index, child_index_list] + tree = [] + current_index = 0 # Avoid calling len() + current_root_index = 0 + root_index = 0 + + # Root always be an empty node, it's up to you to use or delete it + tree.append([("", None), None, []]) + for x in range(self.max_trace_count): + if self.trace_status == typedefs.TRACE_STATUS.CANCELED: + break + line_info = send_command("x/i $pc", cli_output=True).splitlines()[0].split(maxsplit=1)[1] + collect_dict = OrderedDict() + if self.collect_registers: + collect_dict.update(read_registers()) + collect_dict.update(read_float_registers()) + current_index += 1 + tree.append([(line_info, collect_dict), current_root_index, []]) + tree[current_root_index][2].append(current_index) # Add a child + self.current_trace_count = x + 1 + if regexes.trace_instructions_ret.search(line_info): + if tree[current_root_index][1] is None: # If no parents exist + current_index += 1 + tree.append([("", None), None, [current_root_index]]) + tree[current_root_index][1] = current_index # Set new parent + current_root_index = current_index # current_node=current_node.parent + root_index = current_root_index # set new root + else: + current_root_index = tree[current_root_index][1] # current_node=current_node.parent + elif self.step_mode == typedefs.STEP_MODE.SINGLE_STEP: + if regexes.trace_instructions_call.search(line_info): + current_root_index = current_index + if self.stop_condition: + try: + if str(parse_and_eval(self.stop_condition)) == "1": + break + except: + pass + if self.step_mode == typedefs.STEP_MODE.SINGLE_STEP: + step_instruction() + elif self.step_mode == typedefs.STEP_MODE.STEP_OVER: + step_over_instruction() + wait_for_stop() + self.trace_data = (tree, root_index) + self.trace_status = typedefs.TRACE_STATUS.FINISHED + active_trace = False + if not self.stop_after_trace: + continue_inferior() + + def cancel_trace(self): + self.trace_status = typedefs.TRACE_STATUS.CANCELED #:tag:Tools diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 76ade117..41456979 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -350,85 +350,9 @@ def __init__(self): super(TraceInstructions, self).__init__("pince-trace-instructions", gdb.COMMAND_USER) def invoke(self, arg, from_tty): - ( - breakpoint, - max_trace_count, - stop_condition, - step_mode, - stop_after_trace, - collect_general_registers, - collect_flag_registers, - collect_segment_registers, - collect_float_registers, - ) = eval(arg) - gdb.execute("delete " + breakpoint) - trace_status_file = utils.get_trace_instructions_status_file(pid, breakpoint) - - # The reason we don't use a tree class is to make the tree json-compatible - # tree format-->[node1, node2, node3, ...] - # node-->[(line_info, register_dict), parent_index, child_index_list] - tree = [] - current_index = 0 # Avoid calling len() - current_root_index = 0 - root_index = 0 - - # Root always be an empty node, it's up to you to use or delete it - tree.append([("", None), None, []]) - for x in range(max_trace_count): - try: - output = pickle.load(open(trace_status_file, "rb")) - if output[0] == typedefs.TRACE_STATUS.CANCELED: - break - except: - pass - line_info = gdb.execute("x/i $pc", to_string=True).splitlines()[0].split(maxsplit=1)[1] - collect_dict = OrderedDict() - if collect_general_registers: - collect_dict.update(gdbutils.get_general_registers()) - if collect_flag_registers: - collect_dict.update(gdbutils.get_flag_registers()) - if collect_segment_registers: - collect_dict.update(gdbutils.get_segment_registers()) - if collect_float_registers: - collect_dict.update(gdbutils.get_float_registers()) - current_index += 1 - tree.append([(line_info, collect_dict), current_root_index, []]) - tree[current_root_index][2].append(current_index) # Add a child - status_info = ( - typedefs.TRACE_STATUS.TRACING, - line_info + "\n(" + str(x + 1) + "/" + str(max_trace_count) + ")", - ) - pickle.dump(status_info, open(trace_status_file, "wb")) - if regexes.trace_instructions_ret.search(line_info): - if tree[current_root_index][1] is None: # If no parents exist - current_index += 1 - tree.append([("", None), None, [current_root_index]]) - tree[current_root_index][1] = current_index # Set new parent - current_root_index = current_index # current_node=current_node.parent - root_index = current_root_index # set new root - else: - current_root_index = tree[current_root_index][1] # current_node=current_node.parent - elif step_mode == typedefs.STEP_MODE.SINGLE_STEP: - if regexes.trace_instructions_call.search(line_info): - current_root_index = current_index - if stop_condition: - try: - if str(gdb.parse_and_eval(stop_condition)) == "1": - break - except: - pass - if step_mode == typedefs.STEP_MODE.SINGLE_STEP: - gdb.execute("stepi", to_string=True) - elif step_mode == typedefs.STEP_MODE.STEP_OVER: - gdb.execute("nexti", to_string=True) - status_info = (typedefs.TRACE_STATUS.PROCESSING, "") - pickle.dump(status_info, open(trace_status_file, "wb")) - trace_instructions_file = utils.get_trace_instructions_file(pid, breakpoint) - json.dump((tree, root_index), open(trace_instructions_file, "w")) - status_info = (typedefs.TRACE_STATUS.FINISHED, "") - pickle.dump(status_info, open(trace_status_file, "wb")) - if not stop_after_trace: - gdb.execute("c&") + trace_status_file = utils.get_trace_status_file(pid, arg) + with open(trace_status_file, "w") as trace_file: + trace_file.write(str(typedefs.TRACE_STATUS.TRACING)) class InitSoFile(gdb.Command): diff --git a/libpince/typedefs.py b/libpince/typedefs.py index 2bc34c5f..7980c6bf 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -109,8 +109,7 @@ class TRACE_STATUS: IDLE = 1 TRACING = 2 CANCELED = 3 - PROCESSING = 4 - FINISHED = 5 + FINISHED = 4 class STOP_REASON: diff --git a/libpince/utils.py b/libpince/utils.py index 5dbcfd12..c622952e 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -384,20 +384,6 @@ def get_track_breakpoint_file(pid, breakpoint): return get_ipc_path(pid) + "/" + breakpoint + "_track_breakpoint.txt" -#:tag:Tools -def get_trace_instructions_file(pid, breakpoint): - """Get the path of trace instructions file for given pid and breakpoint - - Args: - pid (int,str): PID of the process - breakpoint (str): breakpoint number - - Returns: - str: Path of trace instructions file - """ - return get_tmp_path(pid) + "/" + breakpoint + "_trace.txt" - - #:tag:Utilities def append_file_extension(string, extension): """Appends the given extension to the given string if it doesn't end with the given extension @@ -477,15 +463,15 @@ def load_file(file_path, load_method="json"): #:tag:Tools -def get_trace_instructions_status_file(pid, breakpoint): - """Get the path of trace instructions status file for given pid and breakpoint +def get_trace_status_file(pid, breakpoint): + """Get the path of trace status file for given pid and breakpoint Args: pid (int,str): PID of the process breakpoint (str): breakpoint number Returns: - str: Path of trace instructions status file + str: Path of trace status file """ return get_ipc_path(pid) + "/" + breakpoint + "_trace_status.txt" diff --git a/tr/tr.py b/tr/tr.py index 73a68279..40b80d82 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -278,7 +278,6 @@ def translate(): ACCESSED_BY = QT_TR_NOOP("Accessed by {}") DELETE_BREAKPOINT_FAILED = QT_TR_NOOP("Unable to delete breakpoint at expression {}") MAX_TRACE_COUNT_ASSERT_GT = QT_TR_NOOP("Max trace count must be greater than or equal to {}") - PROCESSING_DATA = QT_TR_NOOP("Processing the collected data") SAVE_TRACE_FILE = QT_TR_NOOP("Save trace file") # Same applies here, keep (*.trace) and (*) From 6447c35cf381e04944a31f2e4eea69efcc62468a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 19 May 2024 15:24:15 +0300 Subject: [PATCH 428/487] Apply monospace font to tracer --- GUI/TraceInstructionsWindow.py | 28 +++++++++++++++++----------- GUI/TraceInstructionsWindow.ui | 13 ++++++++++++- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/GUI/TraceInstructionsWindow.py b/GUI/TraceInstructionsWindow.py index 3d422800..c5b26dad 100644 --- a/GUI/TraceInstructionsWindow.py +++ b/GUI/TraceInstructionsWindow.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TraceInstructionsWindow.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -13,36 +13,42 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(704, 545) - self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget = QtWidgets.QWidget(parent=MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.splitter = QtWidgets.QSplitter(self.centralwidget) + self.splitter = QtWidgets.QSplitter(parent=self.centralwidget) self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) self.splitter.setObjectName("splitter") - self.treeWidget_InstructionInfo = QtWidgets.QTreeWidget(self.splitter) + self.treeWidget_InstructionInfo = QtWidgets.QTreeWidget(parent=self.splitter) + font = QtGui.QFont() + font.setFamily("Monospace") + self.treeWidget_InstructionInfo.setFont(font) self.treeWidget_InstructionInfo.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.treeWidget_InstructionInfo.setObjectName("treeWidget_InstructionInfo") self.treeWidget_InstructionInfo.headerItem().setText(0, "1") self.treeWidget_InstructionInfo.header().setVisible(False) - self.textBrowser_RegisterInfo = QtWidgets.QTextBrowser(self.splitter) + self.textBrowser_RegisterInfo = QtWidgets.QTextBrowser(parent=self.splitter) + font = QtGui.QFont() + font.setFamily("Monospace") + self.textBrowser_RegisterInfo.setFont(font) self.textBrowser_RegisterInfo.setObjectName("textBrowser_RegisterInfo") self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) - self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar = QtWidgets.QMenuBar(parent=MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 704, 22)) self.menubar.setObjectName("menubar") - self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile = QtWidgets.QMenu(parent=self.menubar) self.menuFile.setObjectName("menuFile") MainWindow.setMenuBar(self.menubar) - self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) - self.actionOpen = QtGui.QAction(MainWindow) + self.actionOpen = QtGui.QAction(parent=MainWindow) self.actionOpen.setObjectName("actionOpen") - self.actionSave = QtGui.QAction(MainWindow) + self.actionSave = QtGui.QAction(parent=MainWindow) self.actionSave.setObjectName("actionSave") - self.actionSave_as_a_text_file = QtGui.QAction(MainWindow) + self.actionSave_as_a_text_file = QtGui.QAction(parent=MainWindow) self.actionSave_as_a_text_file.setObjectName("actionSave_as_a_text_file") self.menuFile.addAction(self.actionOpen) self.menuFile.addAction(self.actionSave) diff --git a/GUI/TraceInstructionsWindow.ui b/GUI/TraceInstructionsWindow.ui index 6d6092bb..76fddbdf 100644 --- a/GUI/TraceInstructionsWindow.ui +++ b/GUI/TraceInstructionsWindow.ui @@ -21,6 +21,11 @@ Qt::Horizontal + + + Monospace + + QAbstractItemView::NoEditTriggers @@ -33,7 +38,13 @@ - + + + + Monospace + + + From 8d6a1bd70e7ee252e8f2420893123d40f72b7965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 20 May 2024 14:33:41 +0300 Subject: [PATCH 429/487] Fix inferior_status not being updated --- libpince/debugcore.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 70f1570b..f3137603 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -295,16 +295,17 @@ def check_inferior_status(): # Get the last match only to optimize parsing stop_info = matches[-1][0] if stop_info: - bp_num = regexes.breakpoint_number.search(stop_info) - - # Return -1 for invalid breakpoints to ignore racing conditions - if bp_num and breakpoint_on_hit_dict.get(bp_num.group(1), -1) != typedefs.BREAKPOINT_ON_HIT.BREAK: - return stop_reason = typedefs.STOP_REASON.DEBUG inferior_status = typedefs.INFERIOR_STATUS.STOPPED else: inferior_status = typedefs.INFERIOR_STATUS.RUNNING - if old_status != inferior_status and not active_trace: + bp_num = regexes.breakpoint_number.search(stop_info) + # Return -1 for invalid breakpoints to ignore racing conditions + if not ( + old_status == inferior_status + or (bp_num and breakpoint_on_hit_dict.get(bp_num.group(1), -1) != typedefs.BREAKPOINT_ON_HIT.BREAK) + or active_trace + ): with status_changed_condition: status_changed_condition.notify_all() From 492903a7900d46648f8f6763150bf8651d340fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 20 May 2024 15:10:55 +0300 Subject: [PATCH 430/487] Disable user debug options while tracing --- PINCE.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/PINCE.py b/PINCE.py index c2dc3ab3..63077c0d 100755 --- a/PINCE.py +++ b/PINCE.py @@ -689,17 +689,22 @@ def auto_attach_loop(self): # Instead of using Qt functions, try to use their signals to prevent crashes @utils.ignore_exceptions def pause_hotkey_pressed(self): - debugcore.interrupt_inferior(typedefs.STOP_REASON.PAUSE) + if not debugcore.active_trace: + debugcore.interrupt_inferior(typedefs.STOP_REASON.PAUSE) @utils.ignore_exceptions def break_hotkey_pressed(self): - debugcore.interrupt_inferior() + if not debugcore.active_trace: + debugcore.interrupt_inferior() @utils.ignore_exceptions def continue_hotkey_pressed(self): - if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: - return - debugcore.continue_inferior() + if not ( + debugcore.currentpid == -1 + or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING + or debugcore.active_trace + ): + debugcore.continue_inferior() @utils.ignore_exceptions def toggle_attach_hotkey_pressed(self): @@ -3074,31 +3079,31 @@ def show_trace_window(self): TraceInstructionsWindowForm(self, prompt_dialog=False) def step_instruction(self): - if ( + if not ( debugcore.currentpid == -1 + or debugcore.active_trace or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or self.updating_memoryview ): - return - debugcore.step_instruction() + debugcore.step_instruction() def step_over_instruction(self): - if ( + if not ( debugcore.currentpid == -1 + or debugcore.active_trace or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or self.updating_memoryview ): - return - debugcore.step_over_instruction() + debugcore.step_over_instruction() def execute_till_return(self): - if ( + if not ( debugcore.currentpid == -1 + or debugcore.active_trace or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING or self.updating_memoryview ): - return - debugcore.execute_till_return() + debugcore.execute_till_return() def set_address(self): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: From 2d095d39866e563129affe451ad11502d8b35f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 21 May 2024 16:11:23 +0300 Subject: [PATCH 431/487] Fix trace status design --- PINCE.py | 2 -- libpince/debugcore.py | 27 ++++++++++---------- libpince/gdb_python_scripts/gdbextensions.py | 4 +-- libpince/utils.py | 19 +++++++++++--- tr/tr.py | 1 - 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/PINCE.py b/PINCE.py index 63077c0d..f2316590 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4976,7 +4976,6 @@ def __init__(self, parent, address: str, tracer: debugcore.Tracer): self.setupUi(self) self.status_to_text = { typedefs.TRACE_STATUS.IDLE: tr.WAITING_FOR_BREAKPOINT, - typedefs.TRACE_STATUS.CANCELED: tr.TRACING_CANCELED, typedefs.TRACE_STATUS.FINISHED: tr.TRACING_COMPLETED, } self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window) @@ -5018,7 +5017,6 @@ def closeEvent(self, event: QCloseEvent): while self.tracer.trace_status != typedefs.TRACE_STATUS.FINISHED: sleep(0.1) app.processEvents() - debugcore.delete_breakpoint(self.address) self.widget_closed.emit() super().closeEvent(event) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index f3137603..7d1ff93b 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1893,8 +1893,9 @@ def get_track_breakpoint_info(breakpoint): class Tracer: def __init__(self) -> None: - """Use set_breakpoint after init""" - self.breakpoint = "" + """Use tracer_loop after init, then set_breakpoint. There can be only one trace at a time + Don't create a new trace object before finishing the last one""" + self.expression = "" self.max_trace_count = 1000 self.stop_condition = "" self.step_mode = typedefs.STEP_MODE.SINGLE_STEP @@ -1903,6 +1904,8 @@ def __init__(self) -> None: self.trace_status = typedefs.TRACE_STATUS.IDLE self.current_trace_count = 0 self.trace_data = [] + self.cancel = False + utils.change_trace_status(currentpid, self.trace_status) @execute_with_temporary_interruption def set_breakpoint( @@ -1916,8 +1919,6 @@ def set_breakpoint( collect_registers: bool = True, ) -> str: """Sets the breakpoint for tracing instructions at the address evaluated by the given expression - There can be only one trace at a time, don't call this function twice before the first trace finishes - Use tracer_loop with a thread to start the actual tracing event Args: expression (str): Any gdb expression @@ -1942,30 +1943,30 @@ def set_breakpoint( if not breakpoint: return modify_breakpoint(expression, typedefs.BREAKPOINT_MODIFY.CONDITION, condition=trigger_condition) - self.trace_status = typedefs.TRACE_STATUS.IDLE ( - self.breakpoint, + self.expression, self.max_trace_count, self.stop_condition, self.step_mode, self.stop_after_trace, self.collect_registers, - ) = (breakpoint, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_registers) - send_command("commands " + breakpoint + "\npince-trace-instructions " + breakpoint + "\nend") + ) = (expression, max_trace_count, stop_condition, step_mode, stop_after_trace, collect_registers) + send_command("commands " + breakpoint + "\npince-trace-instructions\nend") return breakpoint def tracer_loop(self): global active_trace active_trace = True self.current_trace_count = 0 - trace_status_file = utils.get_trace_status_file(currentpid, self.breakpoint) - while self.trace_status == typedefs.TRACE_STATUS.IDLE: + trace_status_file = utils.get_trace_status_file(currentpid) + while self.trace_status == typedefs.TRACE_STATUS.IDLE and not self.cancel: try: with open(trace_status_file, "r") as trace_file: self.trace_status = int(trace_file.read()) except (ValueError, FileNotFoundError): pass - delete_breakpoint(self.breakpoint) + sleep(0.1) + delete_breakpoint(self.expression) self.trace_status = typedefs.TRACE_STATUS.TRACING # The reason we don't use a tree class is to make the tree json-compatible @@ -1979,7 +1980,7 @@ def tracer_loop(self): # Root always be an empty node, it's up to you to use or delete it tree.append([("", None), None, []]) for x in range(self.max_trace_count): - if self.trace_status == typedefs.TRACE_STATUS.CANCELED: + if self.cancel: break line_info = send_command("x/i $pc", cli_output=True).splitlines()[0].split(maxsplit=1)[1] collect_dict = OrderedDict() @@ -2020,7 +2021,7 @@ def tracer_loop(self): continue_inferior() def cancel_trace(self): - self.trace_status = typedefs.TRACE_STATUS.CANCELED + self.cancel = True #:tag:Tools diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index 41456979..d481162a 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -350,9 +350,7 @@ def __init__(self): super(TraceInstructions, self).__init__("pince-trace-instructions", gdb.COMMAND_USER) def invoke(self, arg, from_tty): - trace_status_file = utils.get_trace_status_file(pid, arg) - with open(trace_status_file, "w") as trace_file: - trace_file.write(str(typedefs.TRACE_STATUS.TRACING)) + utils.change_trace_status(pid, typedefs.TRACE_STATUS.TRACING) class InitSoFile(gdb.Command): diff --git a/libpince/utils.py b/libpince/utils.py index c622952e..94eb894b 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -463,17 +463,28 @@ def load_file(file_path, load_method="json"): #:tag:Tools -def get_trace_status_file(pid, breakpoint): - """Get the path of trace status file for given pid and breakpoint +def get_trace_status_file(pid): + """Get the path of trace status file for given pid Args: pid (int,str): PID of the process - breakpoint (str): breakpoint number Returns: str: Path of trace status file """ - return get_ipc_path(pid) + "/" + breakpoint + "_trace_status.txt" + return get_ipc_path(pid) + "/_trace_status.txt" + + +def change_trace_status(pid: int | str, trace_status: int): + """Change trace status for given pid + + Args: + pid (int,str): PID of the process + trace_status (int): New trace status, can be a member of typedefs.TRACE_STATUS + """ + trace_status_file = get_trace_status_file(pid) + with open(trace_status_file, "w") as trace_file: + trace_file.write(str(trace_status)) #:tag:Tools diff --git a/tr/tr.py b/tr/tr.py index 40b80d82..95058a33 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -333,7 +333,6 @@ def translate(): SELECT_ONE_REGION = QT_TR_NOOP("Select at least one region") DISSECT_CODE = QT_TR_NOOP("You need to dissect code first\n" "Proceed?") WAITING_FOR_BREAKPOINT = QT_TR_NOOP("Waiting for breakpoint to trigger") - TRACING_CANCELED = QT_TR_NOOP("Tracing has been canceled") TRACING_COMPLETED = QT_TR_NOOP("Tracing has been completed") NOT = QT_TR_NOOP("Not") EXACT = QT_TR_NOOP("Exact") From 569d3d83c665d19ad194cb4518df3068c78eec92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 21 May 2024 16:30:51 +0300 Subject: [PATCH 432/487] Fix tracer docs --- README.md | 2 +- libpince/debugcore.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fff4dd3c..9acc0b3c 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Pre-release screenshots: * **Chained Breakpoints:** Just like CE, PINCE allows you to set multiple, connected breakpoints at once. If an event(such as condition modification or deletion) happens in one of the breakpoints, other connected breakpoints will get affected as well * **Watchpoint Tracking:** Allows you to see which instructions have been accessing to the specified address, just like "What accesses/writes to this address" feature in CE * **Breakpoint Tracking:** Allows you to track down addresses calculated by the given register expressions at the specified instruction, just like "Find out what addresses this instruction accesses" feature in CE with a little addon, you can enter multiple register expressions, this allows you to check the value of "esi" even if the instruction is something irrelevant like "mov [eax],edx" - * **Tracing:** Almost the same with CE. But unlike CE, you can stop tracing whenever you want. Created from scratch with shittons of custom features instead of using gdb's trace&collect commands because some people have too much time on their hands + * **Tracing:** Almost the same with CE. But unlike CE, you can stop tracing whenever you want. Created from scratch with custom features instead of using gdb's built-in trace commands, this allows tracing to be done without the need of a gdbserver * **Collision Detection:** GDB normally permits setting unlimited watchpoints next to each other. But this behaviour leads to unexpected outcomes such as causing GDB or the inferior become completely inoperable. GDB also doesn't care about the number(max 4) or the size(x86->max 4, x64->max 8) of hardware breakpoints. Fortunately, PINCE checks for these problems whenever you set a new breakpoint and detects them before they happen and then inhibits them in a smart way. Lets say you want to set a breakpoint in the size of 32 bytes. But the maximum size for a breakpoint is 8! So, PINCE creates 4 different breakpoints with the size of 8 bytes and then chains them for future actions - **Code Injection** * **Run-time injection:** Only .so injection is supported for now. In Memory View window, click Tools->Inject .so file to select the .so file. An example for creating .so file can be found in "libpince/Injection/". PINCE will be able to inject single line instructions or code caves in near future diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 7d1ff93b..40e6f4e1 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -113,7 +113,7 @@ # Return value of the current send_command call will be an empty string cancel_send_command = False -# A boolean value. Used by state_observe_thread to check if a tracing session is active +# A boolean value. Used by state_observe_thread to check if a trace session is active active_trace = False #:tag:GDBInformation @@ -1893,8 +1893,8 @@ def get_track_breakpoint_info(breakpoint): class Tracer: def __init__(self) -> None: - """Use tracer_loop after init, then set_breakpoint. There can be only one trace at a time - Don't create a new trace object before finishing the last one""" + """Use set_breakpoint after init and if it succeeds, use tracer_loop within a thread + There can be only one trace session at a time. Don't create new trace sessions before finishing the last one""" self.expression = "" self.max_trace_count = 1000 self.stop_condition = "" @@ -1955,6 +1955,7 @@ def set_breakpoint( return breakpoint def tracer_loop(self): + """The main tracer loop, call within a thread""" global active_trace active_trace = True self.current_trace_count = 0 @@ -2021,6 +2022,7 @@ def tracer_loop(self): continue_inferior() def cancel_trace(self): + """Prematurely ends the trace session, trace data will still be collected""" self.cancel = True From 298c43200d604cb849b67d203219b79a61c3c0d7 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Tue, 21 May 2024 17:32:24 +0100 Subject: [PATCH 433/487] Pointer scanner overhaul. Add pointer scan 'filtering' --- GUI/PointerScanFilterDialog.py | 68 +++++++ GUI/PointerScanFilterDialog.ui | 136 ++++++++++++++ ...anDialog.py => PointerScanSearchDialog.py} | 4 +- ...anDialog.ui => PointerScanSearchDialog.ui} | 2 +- ...rScannerWindow.py => PointerScanWindow.py} | 26 ++- ...rScannerWindow.ui => PointerScanWindow.ui} | 25 ++- PINCE.py | 175 ++++++++++++++---- tr/tr.py | 3 +- 8 files changed, 385 insertions(+), 54 deletions(-) create mode 100644 GUI/PointerScanFilterDialog.py create mode 100644 GUI/PointerScanFilterDialog.ui rename GUI/{PointerScanDialog.py => PointerScanSearchDialog.py} (99%) rename GUI/{PointerScanDialog.ui => PointerScanSearchDialog.ui} (99%) rename GUI/{PointerScannerWindow.py => PointerScanWindow.py} (80%) rename GUI/{PointerScannerWindow.ui => PointerScanWindow.ui} (85%) diff --git a/GUI/PointerScanFilterDialog.py b/GUI/PointerScanFilterDialog.py new file mode 100644 index 00000000..f3bbcfd8 --- /dev/null +++ b/GUI/PointerScanFilterDialog.py @@ -0,0 +1,68 @@ +# Form implementation generated from reading ui file 'PointerScanFilterDialog.ui' +# +# Created by: PyQt6 UI code generator 6.7.0 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 129) + Dialog.setMinimumSize(QtCore.QSize(400, 129)) + Dialog.setMaximumSize(QtCore.QSize(400, 129)) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setContentsMargins(0, -1, -1, -1) + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(parent=Dialog) + self.label.setScaledContents(False) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.lineEdit_File1Path = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_File1Path.setReadOnly(True) + self.lineEdit_File1Path.setObjectName("lineEdit_File1Path") + self.horizontalLayout.addWidget(self.lineEdit_File1Path) + self.pushButton_File1Browse = QtWidgets.QPushButton(parent=Dialog) + self.pushButton_File1Browse.setObjectName("pushButton_File1Browse") + self.horizontalLayout.addWidget(self.pushButton_File1Browse) + self.verticalLayout.addLayout(self.horizontalLayout) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_2 = QtWidgets.QLabel(parent=Dialog) + self.label_2.setObjectName("label_2") + self.horizontalLayout_2.addWidget(self.label_2) + self.lineEdit_File2Path = QtWidgets.QLineEdit(parent=Dialog) + self.lineEdit_File2Path.setReadOnly(True) + self.lineEdit_File2Path.setObjectName("lineEdit_File2Path") + self.horizontalLayout_2.addWidget(self.lineEdit_File2Path) + self.pushButton_File2Browse = QtWidgets.QPushButton(parent=Dialog) + self.pushButton_File2Browse.setObjectName("pushButton_File2Browse") + self.horizontalLayout_2.addWidget(self.pushButton_File2Browse) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Filter Pointers")) + self.label.setText(_translate("Dialog", "File 1:")) + self.pushButton_File1Browse.setText(_translate("Dialog", "Browse")) + self.label_2.setText(_translate("Dialog", "File 2:")) + self.pushButton_File2Browse.setText(_translate("Dialog", "Browse")) diff --git a/GUI/PointerScanFilterDialog.ui b/GUI/PointerScanFilterDialog.ui new file mode 100644 index 00000000..fb7dbc0a --- /dev/null +++ b/GUI/PointerScanFilterDialog.ui @@ -0,0 +1,136 @@ + + + Dialog + + + + 0 + 0 + 400 + 129 + + + + + 400 + 129 + + + + + 400 + 129 + + + + Filter Pointers + + + + + + 0 + + + + + + + File 1: + + + false + + + + + + + true + + + + + + + Browse + + + + + + + + + + + File 2: + + + + + + + true + + + + + + + Browse + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/GUI/PointerScanDialog.py b/GUI/PointerScanSearchDialog.py similarity index 99% rename from GUI/PointerScanDialog.py rename to GUI/PointerScanSearchDialog.py index fa517221..85aea9f6 100644 --- a/GUI/PointerScanDialog.py +++ b/GUI/PointerScanSearchDialog.py @@ -1,4 +1,4 @@ -# Form implementation generated from reading ui file 'PointerScanDialog.ui' +# Form implementation generated from reading ui file 'PointerScanSearchDialog.ui' # # Created by: PyQt6 UI code generator 6.7.0 # @@ -167,7 +167,7 @@ def setupUi(self, Dialog): def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate - Dialog.setWindowTitle(_translate("Dialog", "Pointer Scan")) + Dialog.setWindowTitle(_translate("Dialog", "Scan for Pointers")) self.label.setText(_translate("Dialog", "Address")) self.label_2.setText(_translate("Dialog", "Depth")) self.label_3.setText(_translate("Dialog", "Scan Range")) diff --git a/GUI/PointerScanDialog.ui b/GUI/PointerScanSearchDialog.ui similarity index 99% rename from GUI/PointerScanDialog.ui rename to GUI/PointerScanSearchDialog.ui index c42fc3f6..e3795ada 100644 --- a/GUI/PointerScanDialog.ui +++ b/GUI/PointerScanSearchDialog.ui @@ -11,7 +11,7 @@ - Pointer Scan + Scan for Pointers diff --git a/GUI/PointerScannerWindow.py b/GUI/PointerScanWindow.py similarity index 80% rename from GUI/PointerScannerWindow.py rename to GUI/PointerScanWindow.py index d2a2fced..e8f1bdb1 100644 --- a/GUI/PointerScannerWindow.py +++ b/GUI/PointerScanWindow.py @@ -1,4 +1,4 @@ -# Form implementation generated from reading ui file 'PointerScannerWindow.ui' +# Form implementation generated from reading ui file 'PointerScanWindow.ui' # # Created by: PyQt6 UI code generator 6.7.0 # @@ -34,6 +34,9 @@ def setupUi(self, MainWindow): self.gridLayout.addWidget(self.tableWidget_ScanResult, 2, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") + self.pushButton_Sort = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton_Sort.setObjectName("pushButton_Sort") + self.horizontalLayout.addWidget(self.pushButton_Sort) self.pushButton_Clear = QtWidgets.QPushButton(parent=self.centralwidget) self.pushButton_Clear.setObjectName("pushButton_Clear") self.horizontalLayout.addWidget(self.pushButton_Clear) @@ -49,8 +52,8 @@ def setupUi(self, MainWindow): self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(parent=self.menubar) self.menuFile.setObjectName("menuFile") - self.menuRe_scan = QtWidgets.QMenu(parent=self.menubar) - self.menuRe_scan.setObjectName("menuRe_scan") + self.menuActions = QtWidgets.QMenu(parent=self.menubar) + self.menuActions.setObjectName("menuActions") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) self.statusbar.setObjectName("statusbar") @@ -59,13 +62,16 @@ def setupUi(self, MainWindow): self.actionOpen.setObjectName("actionOpen") self.actionSaveAs = QtGui.QAction(parent=MainWindow) self.actionSaveAs.setObjectName("actionSaveAs") - self.actionRescan_memory = QtGui.QAction(parent=MainWindow) - self.actionRescan_memory.setObjectName("actionRescan_memory") + self.actionScan = QtGui.QAction(parent=MainWindow) + self.actionScan.setObjectName("actionScan") + self.actionFilter = QtGui.QAction(parent=MainWindow) + self.actionFilter.setObjectName("actionFilter") self.menuFile.addAction(self.actionOpen) self.menuFile.addAction(self.actionSaveAs) - self.menuRe_scan.addAction(self.actionRescan_memory) + self.menuActions.addAction(self.actionScan) + self.menuActions.addAction(self.actionFilter) self.menubar.addAction(self.menuFile.menuAction()) - self.menubar.addAction(self.menuRe_scan.menuAction()) + self.menubar.addAction(self.menuActions.menuAction()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -74,9 +80,11 @@ def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Pointer Scanner")) self.tableWidget_ScanResult.setSortingEnabled(True) + self.pushButton_Sort.setText(_translate("MainWindow", "Sort")) self.pushButton_Clear.setText(_translate("MainWindow", "Clear")) self.menuFile.setTitle(_translate("MainWindow", "Fi&le")) - self.menuRe_scan.setTitle(_translate("MainWindow", "Poi&nter Scanner")) + self.menuActions.setTitle(_translate("MainWindow", "Actio&ns")) self.actionOpen.setText(_translate("MainWindow", "&Open")) self.actionSaveAs.setText(_translate("MainWindow", "&Save As...")) - self.actionRescan_memory.setText(_translate("MainWindow", "&Rescan memory")) + self.actionScan.setText(_translate("MainWindow", "&Scan")) + self.actionFilter.setText(_translate("MainWindow", "&Filter")) diff --git a/GUI/PointerScannerWindow.ui b/GUI/PointerScanWindow.ui similarity index 85% rename from GUI/PointerScannerWindow.ui rename to GUI/PointerScanWindow.ui index 5f6d7d32..2e1bedee 100644 --- a/GUI/PointerScannerWindow.ui +++ b/GUI/PointerScanWindow.ui @@ -50,6 +50,13 @@ + + + + Sort + + + @@ -93,14 +100,15 @@ - + - Poi&nter Scanner + Actio&ns - + + - + @@ -113,9 +121,14 @@ &Save As... - + + + &Scan + + + - &Rescan memory + &Filter diff --git a/PINCE.py b/PINCE.py index f2316590..15b3118f 100755 --- a/PINCE.py +++ b/PINCE.py @@ -68,6 +68,7 @@ QDialogButtonBox, QCheckBox, QHBoxLayout, + QPushButton, ) from PyQt6.QtCore import ( Qt, @@ -135,8 +136,9 @@ from GUI.ReferencedCallsWidget import Ui_Form as ReferencedCallsWidget from GUI.ExamineReferrersWidget import Ui_Form as ExamineReferrersWidget from GUI.RestoreInstructionsWidget import Ui_Form as RestoreInstructionsWidget -from GUI.PointerScanDialog import Ui_Dialog as PointerScanDialog -from GUI.PointerScannerWindow import Ui_MainWindow as PointerScannerWindow +from GUI.PointerScanSearchDialog import Ui_Dialog as PointerScanSearchDialog +from GUI.PointerScanFilterDialog import Ui_Dialog as PointerScanFilterDialog +from GUI.PointerScanWindow import Ui_MainWindow as PointerScanWindow from GUI.AbstractTableModels.HexModel import QHexModel from GUI.AbstractTableModels.AsciiModel import QAsciiModel @@ -289,6 +291,14 @@ threadpool.setMaxThreadCount(10) +class ProcessSignals(QObject): + attach = pyqtSignal() + exit = pyqtSignal() + + +process_signals = ProcessSignals() + + class WorkerSignals(QObject): finished = pyqtSignal() @@ -749,6 +759,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): browse_region = menu.addAction(f"{tr.BROWSE_MEMORY_REGION}[Ctrl+B]") disassemble = menu.addAction(f"{tr.DISASSEMBLE_ADDRESS}[Ctrl+D]") menu.addSeparator() + pointer_scanner = menu.addAction(tr.POINTER_SCANNER) pointer_scan = menu.addAction(tr.POINTER_SCAN) menu.addSeparator() what_writes = menu.addAction(tr.WHAT_WRITES) @@ -802,6 +813,9 @@ def treeWidget_AddressTable_context_menu_event(self, event): ) if current_row.childCount() == 0: guiutils.delete_menu_entries(menu, [toggle_children]) + guiutils.delete_menu_entries(menu, [pointer_scanner]) + if debugcore.currentpid == -1: + pointer_scan.setEnabled(False) font_size = self.treeWidget_AddressTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) @@ -822,7 +836,8 @@ def treeWidget_AddressTable_context_menu_event(self, event): freeze_dec: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DECREMENT), browse_region: self.browse_region_for_selected_row, disassemble: self.disassemble_selected_row, - pointer_scan: self.exec_pointer_scan_dialog, + pointer_scanner: self.exec_pointer_scanner, + pointer_scan: self.exec_pointer_scan, what_writes: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.WRITE_ONLY), what_reads: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.READ_ONLY), what_accesses: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.BOTH), @@ -838,15 +853,19 @@ def treeWidget_AddressTable_context_menu_event(self, event): except KeyError: pass - def exec_pointer_scan_dialog(self): + def exec_pointer_scanner(self): + pointer_window = PointerScanWindowForm(self) + pointer_window.show() + + def exec_pointer_scan(self): selected_row = guiutils.get_current_item(self.treeWidget_AddressTable) if not selected_row: return address = selected_row.text(ADDR_COL).strip("P->") - dialog = PointerScanDialogForm(self, address) - if dialog.exec(): - pointer_window = PointerScannerWindowForm(self) - pointer_window.show() + pointer_window = PointerScanWindowForm(self) + pointer_window.show() + dialog = PointerScanSearchDialogForm(pointer_window, address) + dialog.exec() def exec_track_watchpoint_widget(self, watchpoint_type): selected_row = guiutils.get_current_item(self.treeWidget_AddressTable) @@ -1516,6 +1535,7 @@ def attach_to_pid(self, pid: int): scanmem.pid(pid) ptrscan.set_process(pid) self.on_new_process() + process_signals.attach.emit() # TODO: This makes PINCE call on_process_stop twice when attaching # TODO: Signal design might have to change to something like mutexes eventually @@ -1607,6 +1627,7 @@ def on_inferior_exit(self): gdb_path = utils.get_default_gdb_path() debugcore.init_gdb(gdb_path) self.apply_after_init() + process_signals.exit.emit() def on_status_detached(self): self.label_SelectedProcess.setStyleSheet("color: blue") @@ -6298,21 +6319,21 @@ def copy_to_clipboard(row): pass -class PointerScanDialogForm(QDialog, PointerScanDialog): - def __init__(self, parent, address): +class PointerScanSearchDialogForm(QDialog, PointerScanSearchDialog): + def __init__(self, parent, address) -> None: super().__init__(parent) self.setupUi(self) self.lineEdit_Address.setText(address) guiutils.center_to_parent(self) self.checkBox_Path.stateChanged.connect(self.checkBox_Path_stateChanged) self.pushButton_PathBrowse.clicked.connect(self.pushButton_PathBrowse_clicked) - self.scan_button = self.buttonBox.addButton("Scan", QDialogButtonBox.ButtonRole.ActionRole) + self.scan_button: QPushButton | None = self.buttonBox.addButton("Scan", QDialogButtonBox.ButtonRole.ActionRole) if self.scan_button: self.scan_button.clicked.connect(self.scan_button_clicked) self.ptrscan_thread: InterruptableWorker | None = None self.ptrmap_filename: str | None = None - def checkBox_Path_stateChanged(self, state: Qt.CheckState): + def checkBox_Path_stateChanged(self, state: Qt.CheckState) -> None: if Qt.CheckState(state) == Qt.CheckState.Checked: self.pushButton_PathBrowse.setEnabled(True) self.ptrmap_filename = f"{utils.get_process_name(debugcore.currentpid)}.scandata" @@ -6322,8 +6343,9 @@ def checkBox_Path_stateChanged(self, state: Qt.CheckState): self.ptrmap_filename = None self.lineEdit_Path.clear() - def pushButton_PathBrowse_clicked(self): - scan_filter = "Pointer Scan Data (*.scandata)" + def pushButton_PathBrowse_clicked(self) -> None: + scan_filter: str = "Pointer Scan Data (*.scandata)" + filename: str filename, _ = QFileDialog.getSaveFileName( parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter ) @@ -6333,13 +6355,13 @@ def pushButton_PathBrowse_clicked(self): self.ptrmap_filename = filename self.lineEdit_Path.setText(filename) - def reject(self): + def reject(self) -> None: if self.ptrscan_thread: self.ptrscan_thread.stop() return super().reject() - def scan_button_clicked(self): - if debugcore.currentpid == -1: + def scan_button_clicked(self) -> None: + if debugcore.currentpid == -1 or self.scan_button == None: return self.scan_button.setText("Scanning") self.scan_button.setEnabled(False) @@ -6353,8 +6375,8 @@ def scan_button_clicked(self): params.addr(addr_val) params.depth(self.spinBox_Depth.value()) params.srange(FFIRange(self.spinBox_ScanRangeStart.value(), self.spinBox_ScanRangeEnd.value())) - lrange_start = self.spinBox_ScanLRangeStart.value() - lrange_end = self.spinBox_ScanLRangeEnd.value() + lrange_start: int = self.spinBox_ScanLRangeStart.value() + lrange_end: int = self.spinBox_ScanLRangeEnd.value() if lrange_start == 0 and lrange_end == 0: lrange_val = None else: @@ -6368,8 +6390,7 @@ def scan_button_clicked(self): params.last(last_val) params.max(utils.return_optional_int(self.spinBox_Max.value())) params.cycle(self.checkBox_Cycle.isChecked()) - modules = ptrscan.list_modules_pince() # TODO: maybe cache this and let user refresh with a button - ptrscan.set_modules(modules) # TODO: maybe cache this and let user refresh with a button + ptrscan.set_modules(ptrscan.list_modules_pince()) # TODO: maybe cache this and let user refresh with a button ptrscan.create_pointer_map() # TODO: maybe cache this and let user refresh with a button if self.ptrmap_filename and os.path.isfile(self.ptrmap_filename): os.remove(self.ptrmap_filename) @@ -6377,38 +6398,113 @@ def scan_button_clicked(self): self.ptrscan_thread.signals.finished.connect(self.ptrscan_callback) self.ptrscan_thread.start() - def ptrscan_callback(self): + def ptrscan_callback(self) -> None: self.accept() -class PointerScannerWindowForm(QMainWindow, PointerScannerWindow): - def __init__(self, parent): +class PointerScanFilterDialogForm(QDialog, PointerScanFilterDialog): + def __init__(self, parent) -> None: + super().__init__(parent) + self.setupUi(self) + guiutils.center_to_parent(self) + self.pushButton_File1Browse.clicked.connect(self.pushButton_File1Browse_clicked) + self.pushButton_File2Browse.clicked.connect(self.pushButton_File2Browse_clicked) + self.filter_button: QPushButton | None = self.buttonBox.addButton( + "Filter", QDialogButtonBox.ButtonRole.ActionRole + ) + if self.filter_button: + self.filter_button.clicked.connect(self.filter_button_clicked) + self.filter_button.setEnabled(False) + self.filter_result: list[str] | None = None + + def browse_scandata_file(self, file_path_field: QLineEdit) -> None: + scan_filter: str = "Pointer Scan Data (*.scandata)" + filename: str + filename, _ = QFileDialog.getOpenFileName( + parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter + ) + if filename != "": + file_path_field.setText(filename) + self.check_filterable_state() + + def check_filterable_state(self) -> None: + if self.lineEdit_File1Path.text() != "" and self.lineEdit_File2Path.text() != "" and self.filter_button: + self.filter_button.setEnabled(True) + + def pushButton_File1Browse_clicked(self) -> None: + self.browse_scandata_file(self.lineEdit_File1Path) + + def pushButton_File2Browse_clicked(self) -> None: + self.browse_scandata_file(self.lineEdit_File2Path) + + def filter_button_clicked(self) -> None: + if self.lineEdit_File1Path.text() == "" or self.lineEdit_File2Path.text() == "" or self.filter_button == None: + return + self.filter_button.setEnabled(False) + self.filter_button.setText("Filtering") + lines: list[str] + with open(self.lineEdit_File1Path.text()) as file: + lines = file.read().split(os.linesep) + with open(self.lineEdit_File2Path.text()) as file: + lines.extend(file.read().split(os.linesep)) + counts = collections.Counter(lines) + self.filter_result = list(set([line for line in lines if counts[line] > 1 and line != ""])) + self.accept() + + def get_filter_result(self) -> list[str] | None: + return self.filter_result + + +class PointerScanWindowForm(QMainWindow, PointerScanWindow): + def __init__(self, parent) -> None: super().__init__(parent) self.setupUi(self) self.tableWidget_ScanResult.hide() + process_signals.attach.connect(self.on_process_changed) + process_signals.exit.connect(self.on_process_changed) self.pushButton_Clear.pressed.connect(self.pushButton_Clear_pressed) + self.pushButton_Sort.pressed.connect(self.pushButton_Sort_pressed) self.actionOpen.triggered.connect(self.actionOpen_triggered) self.actionSaveAs.triggered.connect(self.actionSaveAs_triggered) - self.actionRescan_memory.triggered.connect(self.rescan) + self.actionScan.triggered.connect(self.scan_triggered) + self.actionFilter.triggered.connect(self.filter_triggered) + if debugcore.currentpid == -1: + self.actionScan.setEnabled(False) guiutils.center_to_parent(self) - def pushButton_Clear_pressed(self): + def on_process_changed(self) -> None: + val: bool = False if debugcore.currentpid == -1 else True + self.actionScan.setEnabled(val) + + def pushButton_Clear_pressed(self) -> None: self.textEdit.clear() - def actionOpen_triggered(self): - scan_filter = "Pointer Scan Data (*.scandata)" + def pushButton_Sort_pressed(self) -> None: + text: str = self.textEdit.toPlainText() + if text == "": + return + text_list: list[str] = text.split(os.linesep) + # Sometimes files will have ending newlines. + # We want to get rid of them otherwise they'll be at top. + if text_list[-1] == "": + del text_list[-1] + text_list.sort() + self.textEdit.setText(os.linesep.join(text_list)) + + def actionOpen_triggered(self) -> None: + scan_filter: str = "Pointer Scan Data (*.scandata)" + filename: str filename, _ = QFileDialog.getOpenFileName( parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter ) if filename != "": self.textEdit.clear() with open(filename) as file: - lines = file.read().split(os.linesep) - for line in lines: - self.textEdit.append(line) + self.textEdit.setText(file.read()) - def actionSaveAs_triggered(self): - scan_filter = "Pointer Scan Data (*.scandata)" + def actionSaveAs_triggered(self) -> None: + scan_filter: str = "Pointer Scan Data (*.scandata)" + filename: str filename, _ = QFileDialog.getSaveFileName( parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter ) @@ -6418,10 +6514,19 @@ def actionSaveAs_triggered(self): with open(filename, "w") as file: file.write(self.textEdit.toPlainText()) - def rescan(self): - dialog = PointerScanDialogForm(self, "0x0") + def scan_triggered(self) -> None: + dialog = PointerScanSearchDialogForm(self, "0x0") dialog.exec() + def filter_triggered(self) -> None: + dialog = PointerScanFilterDialogForm(self) + if dialog.exec(): + filter_result: list[str] | None = dialog.get_filter_result() + if filter_result == None: + return + self.textEdit.clear() + self.textEdit.setText(os.linesep.join(filter_result)) + def handle_exit(): global exiting diff --git a/tr/tr.py b/tr/tr.py index 95058a33..17f446c3 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -75,7 +75,8 @@ def translate(): COPY = QT_TR_NOOP("Copy") PASTE = QT_TR_NOOP("Paste") PASTE_INSIDE = QT_TR_NOOP("Paste inside") - POINTER_SCAN = QT_TR_NOOP("Pointer scan for this address (WIP)") + POINTER_SCAN = QT_TR_NOOP("Pointer scan for this address") + POINTER_SCANNER = QT_TR_NOOP("Open pointer scanner") WHAT_WRITES = QT_TR_NOOP("Find out what writes to this address") WHAT_READS = QT_TR_NOOP("Find out what reads this address") WHAT_ACCESSES = QT_TR_NOOP("Find out what accesses this address") From 4308870fb2b5d6cb3a301c2fb32b2056baa0838a Mon Sep 17 00:00:00 2001 From: brkzlr Date: Tue, 21 May 2024 17:48:01 +0100 Subject: [PATCH 434/487] Prevent certain operations on addresses when detached/process dead --- PINCE.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PINCE.py b/PINCE.py index 15b3118f..a32418da 100755 --- a/PINCE.py +++ b/PINCE.py @@ -815,7 +815,13 @@ def treeWidget_AddressTable_context_menu_event(self, event): guiutils.delete_menu_entries(menu, [toggle_children]) guiutils.delete_menu_entries(menu, [pointer_scanner]) if debugcore.currentpid == -1: + browse_region.setEnabled(False) + disassemble.setEnabled(False) pointer_scan.setEnabled(False) + if not debugcore.is_attached(): + what_writes.setEnabled(False) + what_reads.setEnabled(False) + what_accesses.setEnabled(False) font_size = self.treeWidget_AddressTable.font().pointSize() menu.setStyleSheet("font-size: " + str(font_size) + "pt;") action = menu.exec(event.globalPos()) From 04eb2a93b7a743388d4955352cae0d30b6ba0bd9 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Wed, 22 May 2024 01:33:31 +0100 Subject: [PATCH 435/487] Force file requirement for pointer scanning --- GUI/PointerScanSearchDialog.py | 36 +++---- GUI/PointerScanSearchDialog.ui | 33 +++---- PINCE.py | 24 ++--- i18n/ts/it_IT.ts | 173 +++++++++++++++++++++++++++----- i18n/ts/zh_CN.ts | 175 ++++++++++++++++++++++++++++----- 5 files changed, 335 insertions(+), 106 deletions(-) diff --git a/GUI/PointerScanSearchDialog.py b/GUI/PointerScanSearchDialog.py index 85aea9f6..ffe2e479 100644 --- a/GUI/PointerScanSearchDialog.py +++ b/GUI/PointerScanSearchDialog.py @@ -12,7 +12,9 @@ class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(386, 390) + Dialog.resize(404, 390) + Dialog.setMinimumSize(QtCore.QSize(404, 390)) + Dialog.setMaximumSize(QtCore.QSize(404, 390)) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.verticalLayout = QtWidgets.QVBoxLayout() @@ -63,9 +65,9 @@ def setupUi(self, Dialog): self.verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout_7 = QtWidgets.QHBoxLayout() self.horizontalLayout_7.setObjectName("horizontalLayout_7") - self.checkBox_Path = QtWidgets.QCheckBox(parent=Dialog) - self.checkBox_Path.setObjectName("checkBox_Path") - self.horizontalLayout_7.addWidget(self.checkBox_Path) + self.label_10 = QtWidgets.QLabel(parent=Dialog) + self.label_10.setObjectName("label_10") + self.horizontalLayout_7.addWidget(self.label_10) self.lineEdit_Path = QtWidgets.QLineEdit(parent=Dialog) self.lineEdit_Path.setEnabled(True) self.lineEdit_Path.setText("") @@ -75,11 +77,9 @@ def setupUi(self, Dialog): self.lineEdit_Path.setObjectName("lineEdit_Path") self.horizontalLayout_7.addWidget(self.lineEdit_Path) self.pushButton_PathBrowse = QtWidgets.QPushButton(parent=Dialog) - self.pushButton_PathBrowse.setEnabled(False) + self.pushButton_PathBrowse.setEnabled(True) self.pushButton_PathBrowse.setObjectName("pushButton_PathBrowse") self.horizontalLayout_7.addWidget(self.pushButton_PathBrowse) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_7.addItem(spacerItem3) self.verticalLayout.addLayout(self.horizontalLayout_7) self.horizontalLayout_8 = QtWidgets.QHBoxLayout() self.horizontalLayout_8.setObjectName("horizontalLayout_8") @@ -108,8 +108,8 @@ def setupUi(self, Dialog): self.spinBox_ScanLRangeEnd.setDisplayIntegerBase(16) self.spinBox_ScanLRangeEnd.setObjectName("spinBox_ScanLRangeEnd") self.horizontalLayout_3.addWidget(self.spinBox_ScanLRangeEnd) - spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_3.addItem(spacerItem4) + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_3.addItem(spacerItem3) self.verticalLayout.addLayout(self.horizontalLayout_3) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") @@ -121,8 +121,8 @@ def setupUi(self, Dialog): self.spinBox_Node.setProperty("value", 0) self.spinBox_Node.setObjectName("spinBox_Node") self.horizontalLayout_4.addWidget(self.spinBox_Node) - spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem5) + spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_4.addItem(spacerItem4) self.verticalLayout.addLayout(self.horizontalLayout_4) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") @@ -132,8 +132,8 @@ def setupUi(self, Dialog): self.lineEdit_Last = QtWidgets.QLineEdit(parent=Dialog) self.lineEdit_Last.setObjectName("lineEdit_Last") self.horizontalLayout_5.addWidget(self.lineEdit_Last) - spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_5.addItem(spacerItem6) + spacerItem5 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_5.addItem(spacerItem5) self.verticalLayout.addLayout(self.horizontalLayout_5) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") @@ -145,14 +145,14 @@ def setupUi(self, Dialog): self.spinBox_Max.setProperty("value", 0) self.spinBox_Max.setObjectName("spinBox_Max") self.horizontalLayout_6.addWidget(self.spinBox_Max) - spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_6.addItem(spacerItem7) + spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout_6.addItem(spacerItem6) self.verticalLayout.addLayout(self.horizontalLayout_6) self.checkBox_Cycle = QtWidgets.QCheckBox(parent=Dialog) self.checkBox_Cycle.setObjectName("checkBox_Cycle") self.verticalLayout.addWidget(self.checkBox_Cycle) - spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout.addItem(spacerItem8) + spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout.addItem(spacerItem7) self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel) @@ -174,7 +174,7 @@ def retranslateUi(self, Dialog): self.spinBox_ScanRangeStart.setPrefix(_translate("Dialog", "0x")) self.label_4.setText(_translate("Dialog", "<->")) self.spinBox_ScanRangeEnd.setPrefix(_translate("Dialog", "0x")) - self.checkBox_Path.setText(_translate("Dialog", "Save Results To File")) + self.label_10.setText(_translate("Dialog", "File Path:")) self.pushButton_PathBrowse.setText(_translate("Dialog", "Browse")) self.label_11.setText(_translate("Dialog", "Optional Parameters (0 or empty will use defaults)")) self.label_5.setText(_translate("Dialog", "Last Offset Scan Range")) diff --git a/GUI/PointerScanSearchDialog.ui b/GUI/PointerScanSearchDialog.ui index e3795ada..41d36e4b 100644 --- a/GUI/PointerScanSearchDialog.ui +++ b/GUI/PointerScanSearchDialog.ui @@ -6,10 +6,22 @@ 0 0 - 386 + 404 390 + + + 404 + 390 + + + + + 404 + 390 + + Scan for Pointers @@ -139,9 +151,9 @@ - + - Save Results To File + File Path: @@ -167,26 +179,13 @@ - false + true Browse - - - - Qt::Orientation::Horizontal - - - - 40 - 20 - - - - diff --git a/PINCE.py b/PINCE.py index a32418da..0942b758 100755 --- a/PINCE.py +++ b/PINCE.py @@ -6329,25 +6329,14 @@ class PointerScanSearchDialogForm(QDialog, PointerScanSearchDialog): def __init__(self, parent, address) -> None: super().__init__(parent) self.setupUi(self) - self.lineEdit_Address.setText(address) guiutils.center_to_parent(self) - self.checkBox_Path.stateChanged.connect(self.checkBox_Path_stateChanged) + self.lineEdit_Address.setText(address) + self.lineEdit_Path.setText(os.getcwd() + f"/{utils.get_process_name(debugcore.currentpid)}.scandata") self.pushButton_PathBrowse.clicked.connect(self.pushButton_PathBrowse_clicked) self.scan_button: QPushButton | None = self.buttonBox.addButton("Scan", QDialogButtonBox.ButtonRole.ActionRole) if self.scan_button: self.scan_button.clicked.connect(self.scan_button_clicked) self.ptrscan_thread: InterruptableWorker | None = None - self.ptrmap_filename: str | None = None - - def checkBox_Path_stateChanged(self, state: Qt.CheckState) -> None: - if Qt.CheckState(state) == Qt.CheckState.Checked: - self.pushButton_PathBrowse.setEnabled(True) - self.ptrmap_filename = f"{utils.get_process_name(debugcore.currentpid)}.scandata" - self.lineEdit_Path.setText(os.getcwd() + f"/{self.ptrmap_filename}") - else: - self.pushButton_PathBrowse.setEnabled(False) - self.ptrmap_filename = None - self.lineEdit_Path.clear() def pushButton_PathBrowse_clicked(self) -> None: scan_filter: str = "Pointer Scan Data (*.scandata)" @@ -6358,7 +6347,6 @@ def pushButton_PathBrowse_clicked(self) -> None: if filename != "": if not re.search(r"\.scandata$", filename): filename = filename + ".scandata" - self.ptrmap_filename = filename self.lineEdit_Path.setText(filename) def reject(self) -> None: @@ -6372,7 +6360,6 @@ def scan_button_clicked(self) -> None: self.scan_button.setText("Scanning") self.scan_button.setEnabled(False) self.pushButton_PathBrowse.setEnabled(False) - self.checkBox_Path.setEnabled(False) params: FFIParam = FFIParam() try: addr_val = int(self.lineEdit_Address.text(), 16) @@ -6398,9 +6385,10 @@ def scan_button_clicked(self) -> None: params.cycle(self.checkBox_Cycle.isChecked()) ptrscan.set_modules(ptrscan.list_modules_pince()) # TODO: maybe cache this and let user refresh with a button ptrscan.create_pointer_map() # TODO: maybe cache this and let user refresh with a button - if self.ptrmap_filename and os.path.isfile(self.ptrmap_filename): - os.remove(self.ptrmap_filename) - self.ptrscan_thread = InterruptableWorker(ptrscan.scan_pointer_chain, params, self.ptrmap_filename) + ptrmap_file_path = self.lineEdit_Path.text() + if os.path.isfile(ptrmap_file_path): + os.remove(ptrmap_file_path) + self.ptrscan_thread = InterruptableWorker(ptrscan.scan_pointer_chain, params, ptrmap_file_path) self.ptrscan_thread.signals.finished.connect(self.ptrscan_callback) self.ptrscan_thread.start() diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 92a5053e..dca01652 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -198,6 +198,97 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Cancel Annulla + + + Filter Pointers + + + + + File 1: + + + + + + + Browse + + + + + File 2: + + + + + Scan for Pointers + + + + + Address + Indirizzo + + + + Depth + + + + + Scan Range + + + + + + + + 0x + + + + + + <-> + + + + + File Path: + + + + + Optional Parameters (0 or empty will use defaults) + + + + + Last Offset Scan Range + + + + + Minimum Chain Length + + + + + Last Offset Value + + + + + Max Results + + + + + Solve Circular References + + Settings @@ -431,22 +522,7 @@ Patterns at former positions have higher priority if regex is off - Collect general registers - - - - - Collect flag registers - - - - - Collect segment registers - - - - - Collect float registers + Collect registers @@ -918,6 +994,51 @@ Patterns at former positions have higher priority if regex is off Endianness: + + + Pointer Scanner + + + + + Sort + + + + + Clear + + + + + Fi&le + + + + + Actio&ns + + + + + &Open + + + + + &Save As... + + + + + &Scan + + + + + &Filter + + Please select a Process @@ -1552,6 +1673,16 @@ To change the current GDB path, check Settings->Debug Paste inside + + + Pointer scan for this address + + + + + Open pointer scanner + + Find out what writes to this address @@ -2296,11 +2427,6 @@ You can use the assigned variable from the GDB Console Max trace count must be greater than or equal to {} - - - Processing the collected data - - Save trace file @@ -2474,11 +2600,6 @@ Proceed? Waiting for breakpoint to trigger - - - Tracing has been canceled - - Tracing has been completed diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index d1868c32..be785c07 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -199,6 +199,97 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Cancel 取消 + + + Filter Pointers + + + + + File 1: + + + + + + + Browse + + + + + File 2: + + + + + Scan for Pointers + + + + + Address + 地址 + + + + Depth + + + + + Scan Range + + + + + + + + 0x + + + + + + <-> + + + + + File Path: + + + + + Optional Parameters (0 or empty will use defaults) + + + + + Last Offset Scan Range + + + + + Minimum Chain Length + + + + + Last Offset Value + + + + + Max Results + + + + + Solve Circular References + + Settings @@ -433,23 +524,8 @@ Patterns at former positions have higher priority if regex is off - Collect general registers - 收集通用(general)寄存器 - - - - Collect flag registers - 收集标志(flag)寄存器 - - - - Collect segment registers - 收集段(segment)寄存器 - - - - Collect float registers - 收集浮点(float)寄存器 + Collect registers + @@ -920,6 +996,51 @@ Patterns at former positions have higher priority if regex is off Endianness: 字节序: + + + Pointer Scanner + + + + + Sort + + + + + Clear + 清除 + + + + Fi&le + 文件[&l] + + + + Actio&ns + + + + + &Open + 打开[&O] + + + + &Save As... + + + + + &Scan + + + + + &Filter + + Please select a Process @@ -1556,6 +1677,16 @@ To change the current GDB path, check Settings->Debug Paste inside 粘贴在里 + + + Pointer scan for this address + + + + + Open pointer scanner + + Find out what writes to this address @@ -2349,11 +2480,6 @@ $28 是分配的便利变量 Max trace count must be greater than or equal to {} 最大追踪次数必须大或等于 {} - - - Processing the collected data - 处理收集的数据 - Save trace file @@ -2545,11 +2671,6 @@ Proceed? Waiting for breakpoint to trigger 等待断点被触发 - - - Tracing has been canceled - 追踪已取消 - Tracing has been completed From 15efe7aafc10c823fa58414eaa9f5577a74d6918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 22 May 2024 12:35:11 +0300 Subject: [PATCH 436/487] Remove redundant code and fix docstrings --- libpince/debugcore.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 40e6f4e1..73e229d9 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -178,15 +178,15 @@ def cancel_last_command(): 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 + """Issues the command sent, raises an exception if gdb isn't initiated Args: command (str): The command that'll be sent control (bool): This param should be True if the command sent is ctrl+key instead of the regular command - cli_output (bool): If True, returns the readable parsed cli output instead of gdb/mi garbage + cli_output (bool): If True, returns a readable cli output instead of gdb/mi output send_with_file (bool): Custom commands declared in gdbextensions.py requires file communication. If called command has any parameters, pass this as True - file_contents_send (any type that pickle.dump supports): Arguments for the called custom gdb command + file_contents_send (any): Arguments for the custom gdb command called recv_with_file (bool): Pass this as True if the called custom gdb command returns something Examples: @@ -1281,9 +1281,6 @@ def set_register_flag(flag, value): 2, ) ) - a = 5 - b = 3 - set_convenience_variable("eflags", eflags_hex_value) From bf8bde2dbd187ae1bb526283bac119edc2a6d0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 22 May 2024 14:09:07 +0300 Subject: [PATCH 437/487] Fix tracer crash when process exits --- libpince/debugcore.py | 77 ++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 73e229d9..b00600ef 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -18,7 +18,7 @@ from threading import Lock, Thread, Condition from time import sleep, time from collections import OrderedDict, defaultdict -import pexpect, os, sys, ctypes, pickle, shelve, re, struct, io +import pexpect, os, sys, ctypes, pickle, shelve, re, struct, io, traceback from . import utils, typedefs, regexes self_pid = os.getpid() @@ -1957,7 +1957,7 @@ def tracer_loop(self): active_trace = True self.current_trace_count = 0 trace_status_file = utils.get_trace_status_file(currentpid) - while self.trace_status == typedefs.TRACE_STATUS.IDLE and not self.cancel: + while not (self.trace_status != typedefs.TRACE_STATUS.IDLE or self.cancel or currentpid == -1): try: with open(trace_status_file, "r") as trace_file: self.trace_status = int(trace_file.read()) @@ -1977,41 +1977,44 @@ def tracer_loop(self): # Root always be an empty node, it's up to you to use or delete it tree.append([("", None), None, []]) - for x in range(self.max_trace_count): - if self.cancel: - break - line_info = send_command("x/i $pc", cli_output=True).splitlines()[0].split(maxsplit=1)[1] - collect_dict = OrderedDict() - if self.collect_registers: - collect_dict.update(read_registers()) - collect_dict.update(read_float_registers()) - current_index += 1 - tree.append([(line_info, collect_dict), current_root_index, []]) - tree[current_root_index][2].append(current_index) # Add a child - self.current_trace_count = x + 1 - if regexes.trace_instructions_ret.search(line_info): - if tree[current_root_index][1] is None: # If no parents exist - current_index += 1 - tree.append([("", None), None, [current_root_index]]) - tree[current_root_index][1] = current_index # Set new parent - current_root_index = current_index # current_node=current_node.parent - root_index = current_root_index # set new root - else: - current_root_index = tree[current_root_index][1] # current_node=current_node.parent - elif self.step_mode == typedefs.STEP_MODE.SINGLE_STEP: - if regexes.trace_instructions_call.search(line_info): - current_root_index = current_index - if self.stop_condition: - try: - if str(parse_and_eval(self.stop_condition)) == "1": - break - except: - pass - if self.step_mode == typedefs.STEP_MODE.SINGLE_STEP: - step_instruction() - elif self.step_mode == typedefs.STEP_MODE.STEP_OVER: - step_over_instruction() - wait_for_stop() + try: # In case process exits during the trace session + for x in range(self.max_trace_count): + if self.cancel or currentpid == -1: + break + line_info = send_command("x/i $pc", cli_output=True).splitlines()[0].split(maxsplit=1)[1] + collect_dict = OrderedDict() + if self.collect_registers: + collect_dict.update(read_registers()) + collect_dict.update(read_float_registers()) + current_index += 1 + tree.append([(line_info, collect_dict), current_root_index, []]) + tree[current_root_index][2].append(current_index) # Add a child + self.current_trace_count = x + 1 + if regexes.trace_instructions_ret.search(line_info): + if tree[current_root_index][1] is None: # If no parents exist + current_index += 1 + tree.append([("", None), None, [current_root_index]]) + tree[current_root_index][1] = current_index # Set new parent + current_root_index = current_index # current_node=current_node.parent + root_index = current_root_index # set new root + else: + current_root_index = tree[current_root_index][1] # current_node=current_node.parent + elif self.step_mode == typedefs.STEP_MODE.SINGLE_STEP: + if regexes.trace_instructions_call.search(line_info): + current_root_index = current_index + if self.stop_condition: + try: + if str(parse_and_eval(self.stop_condition)) == "1": + break + except: + pass + if self.step_mode == typedefs.STEP_MODE.SINGLE_STEP: + step_instruction() + elif self.step_mode == typedefs.STEP_MODE.STEP_OVER: + step_over_instruction() + wait_for_stop() + except: + traceback.print_exc() self.trace_data = (tree, root_index) self.trace_status = typedefs.TRACE_STATUS.FINISHED active_trace = False From 44f63de25252c41b0f79e7b4dfc1ac83e6d600d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 22 May 2024 15:06:26 +0300 Subject: [PATCH 438/487] Fix where active_trace starts --- libpince/debugcore.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index b00600ef..2534d745 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1852,6 +1852,7 @@ def track_breakpoint(expression, register_expressions): breakpoint = add_breakpoint(expression, on_hit=typedefs.BREAKPOINT_ON_HIT.FIND_ADDR) if not breakpoint: return + # TODO: When we switch to LLDB, remove c& and only continue if there isn't an active trace, same for track_watchpoint send_command( "commands " + breakpoint @@ -1953,8 +1954,6 @@ def set_breakpoint( def tracer_loop(self): """The main tracer loop, call within a thread""" - global active_trace - active_trace = True self.current_trace_count = 0 trace_status_file = utils.get_trace_status_file(currentpid) while not (self.trace_status != typedefs.TRACE_STATUS.IDLE or self.cancel or currentpid == -1): @@ -1964,6 +1963,8 @@ def tracer_loop(self): except (ValueError, FileNotFoundError): pass sleep(0.1) + global active_trace + active_trace = True delete_breakpoint(self.expression) self.trace_status = typedefs.TRACE_STATUS.TRACING From abe15d2b5e906f940acf0eb29157b8af47ca4fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 22 May 2024 16:22:22 +0300 Subject: [PATCH 439/487] Fix tracer visibility issues and update docs --- CONTRIBUTING.md | 20 -------------------- GUI/TraceInstructionsWaitWidget.py | 13 ++++++------- GUI/TraceInstructionsWaitWidget.ui | 7 ++----- PINCE.py | 3 +-- README.md | 15 +++++---------- libpince/debugcore.py | 5 +++-- 6 files changed, 17 insertions(+), 46 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 008376a3..4e920ff7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,25 +119,6 @@ and adjust manually. This also helps functions like `guiutils.center_to_parent` - 13/05/2024 - Monospace font and `utils.upper_hex` function greatly improve readability if the text area includes hex data, consider using those when creating new text areas. Memory Viewer is a good example for this -- 02/09/2018 - All functions with docstrings should have their subfunctions written after their docstrings. For instance: -```python - def test(): - """documentation for test""" - def subtest(): - return - return -``` -If test is declared like above, `test.__doc__` will return "documentation for test" correctly. This is the correct documentation -```python - def test(): - def subtest(): - return - """documentation for test""" - return -``` -If test is declared like above, `test.__doc__` will return a null string because subtest blocks the docstring. This is the wrong documentation -All functions that has a subfunction can be found with the regex `def.*:.*\s+def` - - 2/9/2018 - Seek methods of all file handles that read directly from the memory(/proc/pid/mem etc.) should be wrapped in a try/except block that catches both OSError and ValueError exceptions. For instance: ```python @@ -171,7 +152,6 @@ These tasks are ordered by importance but feel free to pick any of them. Further - Consider implementing a GUI for catchpoints. This is currently done via GDB Console - Implement speedhack - Implement unrandomizer -- Implement pointer-scan - Automatic function bypassing(make it return the desired value, hook specific parts etc.) - Implement auto-ESP&aimbot - Implement thread info widget diff --git a/GUI/TraceInstructionsWaitWidget.py b/GUI/TraceInstructionsWaitWidget.py index 36e20d81..d379c367 100644 --- a/GUI/TraceInstructionsWaitWidget.py +++ b/GUI/TraceInstructionsWaitWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'TraceInstructionsWaitWidget.ui' # -# Created by: PyQt6 UI code generator 6.3.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,25 +12,24 @@ class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") - Form.resize(194, 91) + Form.resize(194, 93) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setObjectName("gridLayout") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") - self.label_Animated = QtWidgets.QLabel(Form) + self.label_Animated = QtWidgets.QLabel(parent=Form) self.label_Animated.setText("") self.label_Animated.setObjectName("label_Animated") self.verticalLayout.addWidget(self.label_Animated) - self.label_StatusText = QtWidgets.QLabel(Form) + self.label_StatusText = QtWidgets.QLabel(parent=Form) self.label_StatusText.setText("") - self.label_StatusText.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_StatusText.setObjectName("label_StatusText") self.verticalLayout.addWidget(self.label_StatusText) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) - self.pushButton_Cancel = QtWidgets.QPushButton(Form) + self.pushButton_Cancel = QtWidgets.QPushButton(parent=Form) self.pushButton_Cancel.setObjectName("pushButton_Cancel") self.horizontalLayout.addWidget(self.pushButton_Cancel) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) @@ -43,5 +42,5 @@ def setupUi(self, Form): def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate - Form.setWindowTitle(_translate("Form", "Form")) + Form.setWindowTitle(_translate("Form", "Tracer Status")) self.pushButton_Cancel.setText(_translate("Form", "Cancel")) diff --git a/GUI/TraceInstructionsWaitWidget.ui b/GUI/TraceInstructionsWaitWidget.ui index 775bd110..c07e5474 100644 --- a/GUI/TraceInstructionsWaitWidget.ui +++ b/GUI/TraceInstructionsWaitWidget.ui @@ -7,11 +7,11 @@ 0 0 194 - 91 + 93 - Form + Tracer Status @@ -28,9 +28,6 @@ - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - diff --git a/PINCE.py b/PINCE.py index 0942b758..6ec6688e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -5005,14 +5005,13 @@ def __init__(self, parent, address: str, tracer: debugcore.Tracer): typedefs.TRACE_STATUS.IDLE: tr.WAITING_FOR_BREAKPOINT, typedefs.TRACE_STATUS.FINISHED: tr.TRACING_COMPLETED, } - self.setWindowFlags(self.windowFlags() | Qt.WindowType.Window) + self.setWindowFlags(Qt.WindowType.Window) self.address = address self.tracer = tracer media_directory = utils.get_media_directory() self.movie = QMovie(media_directory + "/TraceInstructionsWaitWidget/ajax-loader.gif", QByteArray()) self.label_Animated.setMovie(self.movie) self.movie.setScaledSize(QSize(215, 100)) - self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.movie.setCacheMode(QMovie.CacheMode.CacheAll) self.movie.setSpeed(100) self.movie.start() diff --git a/README.md b/README.md index 9acc0b3c..f96d4071 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,8 @@ Pre-release screenshots: ![pince9](https://user-images.githubusercontent.com/5638719/219640522-85cac1a9-e425-4b4f-abeb-a61104caa618.png) # Features -- **Memory searching:** PINCE uses a specialized fork of [libscanmem](https://github.com/brkzlr/scanmem-PINCE) to search the memory efficiently +- **Memory scanning:** PINCE uses a specialized fork of [libscanmem](https://github.com/brkzlr/scanmem-PINCE) to scan the memory efficiently +- **Pointer scanning:** PINCE uses [PointerScanner-X](https://github.com/kekeimiku/PointerSearcher-X/) to scan pointers efficiently - **Background Execution:** PINCE uses background execution by default, allowing users to run GDB commands while process is running - **Variable Inspection&Modification** * **CheatEngine-like value type support:** Currently supports all types of CE and scanmem along with extended strings(utf-8, utf-16, utf-32) @@ -49,15 +50,9 @@ Pre-release screenshots: * **Collision Detection:** GDB normally permits setting unlimited watchpoints next to each other. But this behaviour leads to unexpected outcomes such as causing GDB or the inferior become completely inoperable. GDB also doesn't care about the number(max 4) or the size(x86->max 4, x64->max 8) of hardware breakpoints. Fortunately, PINCE checks for these problems whenever you set a new breakpoint and detects them before they happen and then inhibits them in a smart way. Lets say you want to set a breakpoint in the size of 32 bytes. But the maximum size for a breakpoint is 8! So, PINCE creates 4 different breakpoints with the size of 8 bytes and then chains them for future actions - **Code Injection** * **Run-time injection:** Only .so injection is supported for now. In Memory View window, click Tools->Inject .so file to select the .so file. An example for creating .so file can be found in "libpince/Injection/". PINCE will be able to inject single line instructions or code caves in near future -- **GDB Console** - * Is the power of PINCE not enough for you? Then you can use the gdb console provided by PINCE, it's on the top right in main window -- **Simplified/Optimized gdb command alternatives** - * Custom scripts instead of using gdb's x command for reading memory - * Custom scripts instead of using gdb's set command for modifying memory -- **libpince - A reusable python library** - * PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget is automatically generated by looking at the docstrings of the source files. PINCE has a unique parsing technique that allows parsing variables. Check the function get_variable_comments in utils for the details. This feature might be replaced with Sphinx in the future -- **Extendable with .so files at runtime** - * See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) +- **GDB Console:** You can use the GDB Console to interact with GDB, it's on the top right in main window +- **libpince:** PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget are automatically generated by looking at the docstrings of the source files. This feature will be replaced with Sphinx in the near future +- **Extendable with .so files at runtime:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) # Installing and running PINCE ### Users: diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 2534d745..7d1e5045 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1852,7 +1852,8 @@ def track_breakpoint(expression, register_expressions): breakpoint = add_breakpoint(expression, on_hit=typedefs.BREAKPOINT_ON_HIT.FIND_ADDR) if not breakpoint: return - # TODO: When we switch to LLDB, remove c& and only continue if there isn't an active trace, same for track_watchpoint + # TODO (lldb): When we switch to LLDB, remove c& and only continue if there isn't an active trace + # Apply the same for track_watchpoint send_command( "commands " + breakpoint @@ -1901,7 +1902,7 @@ def __init__(self) -> None: self.collect_registers = True self.trace_status = typedefs.TRACE_STATUS.IDLE self.current_trace_count = 0 - self.trace_data = [] + self.trace_data = ([], None) self.cancel = False utils.change_trace_status(currentpid, self.trace_status) From 3fc50b14d5b4578c918c8ec75595cbbcbfe8a5db Mon Sep 17 00:00:00 2001 From: brkzlr Date: Wed, 22 May 2024 23:07:07 +0100 Subject: [PATCH 440/487] Change PINCE.sh script to be runnable from anywhere --- PINCE.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/PINCE.sh b/PINCE.sh index 23800f79..579042b3 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -21,13 +21,14 @@ if [ "$(id -u)" = "0" ]; then exit 1 fi -if [ ! -d ".venv/PINCE" ]; then +SCRIPTDIR=$(cd -- "$(dirname -- "$0")" && pwd -P) +if [ ! -d "${SCRIPTDIR}/.venv/PINCE" ]; then echo "Please run \"sh install_pince.sh\" first!" exit 1 fi -. .venv/PINCE/bin/activate +. ${SCRIPTDIR}/.venv/PINCE/bin/activate # Preserve env vars to keep settings like theme preferences. # Debian/Ubuntu does not preserve PATH through sudo even with -E for security reasons # so we need to force PATH preservation with venv activated user's PATH. -sudo -E --preserve-env=PATH PYTHONDONTWRITEBYTECODE=1 .venv/PINCE/bin/python3 PINCE.py +sudo -E --preserve-env=PATH PYTHONDONTWRITEBYTECODE=1 ${SCRIPTDIR}/.venv/PINCE/bin/python3 ${SCRIPTDIR}/PINCE.py From fabd1dac9140703053dda6ba073728c2a550dc79 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Wed, 22 May 2024 23:37:00 +0100 Subject: [PATCH 441/487] Change installer names and make install.sh location independent --- CONTRIBUTING.md | 6 +++--- PINCE.sh | 2 +- README.md | 5 ++--- install_gdb.sh => compile_gdb.sh | 0 install_pince.sh => install.sh | 6 ++---- 5 files changed, 8 insertions(+), 11 deletions(-) rename install_gdb.sh => compile_gdb.sh (100%) rename install_pince.sh => install.sh (94%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e920ff7..20b21b29 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,14 @@ # Code Structure - [PINCE.py](./PINCE.py) - The main file, it contains everything from GUI logic to libpince communication. A chonky boi, will be trimmed in the future - [PINCE.sh](./PINCE.sh) - Launch script -- [install_pince.sh](./install_pince.sh) - Installation script +- [install.sh](./install.sh) - Installation script - [compile_ts.sh](./compile_ts.sh) - Gathers translation information from various sources and compiles them into ts files - [fix_ts.py](./fix_ts.py) - Fixes line information issue, used within [compile_ts.sh](./compile_ts.sh) - [install_gdb.sh](./install_gdb.sh) - PINCE normally uses system GDB but in cases where system GDB is unavailable, this script is used to compile GDB locally - [GUI](./GUI) - Contains Qt Designer forms and their respective codes along with utility functions and custom Qt classes - [media](./media) - Contains media files such as logos and icons - [tr](./tr) - Contains translation constants -- [i18n](./i18n) - Contains translation files. `ts` files are created with Qt Linguist and [compile_ts.sh](./compile_ts.sh), `qm` files are created within the last section of [install_pince.sh](./install_pince.sh) +- [i18n](./i18n) - Contains translation files. `ts` files are created with Qt Linguist and [compile_ts.sh](./compile_ts.sh), `qm` files are created within the last section of [install.sh](./install.sh) - ### **[libpince](./libpince)** - [debugcore.py](./libpince/debugcore.py) - Everything related to communicating with GDB and debugging - [utils.py](./libpince/utils.py) - Contains generic utility functions such as parsing, file creation, documentation etc @@ -75,7 +75,7 @@ Follow the steps below: You can skip this step if you only want to edit already existing files - Edit ts files in [/i18n/ts](./i18n/ts) with the linguist and then save them. After saving the files, run the [compile_ts.sh](./compile_ts.sh) script. This script fixes inconsistencies between Qt6 Linguist and pylupdate6, also removes line information so the git history stays cleaner -- To test your translations, use [install_pince.sh](./install_pince.sh). The last part of the installation script also compiles ts files to qm files so PINCE can process them. +- To test your translations, use [install.sh](./install.sh). The last part of the installation script also compiles ts files to qm files so PINCE can process them. When asked to recompile libscanmem, enter no Make sure that you read the comments in [tr.py](./tr/tr.py). Some of the translations have caveats that might interest you diff --git a/PINCE.sh b/PINCE.sh index 579042b3..c6f4cdde 100755 --- a/PINCE.sh +++ b/PINCE.sh @@ -23,7 +23,7 @@ fi SCRIPTDIR=$(cd -- "$(dirname -- "$0")" && pwd -P) if [ ! -d "${SCRIPTDIR}/.venv/PINCE" ]; then - echo "Please run \"sh install_pince.sh\" first!" + echo "Please run \"sh install.sh\" first!" exit 1 fi . ${SCRIPTDIR}/.venv/PINCE/bin/activate diff --git a/README.md b/README.md index f96d4071..939016cc 100644 --- a/README.md +++ b/README.md @@ -70,11 +70,10 @@ sudo -E ./PINCE-x86_64.AppImage - To install local dev environment, run the following commands in a terminal anywhere you'd like to have the PINCE folder: ```bash git clone --recursive https://github.com/korcankaraokcu/PINCE -cd PINCE -sh install_pince.sh +sh PINCE/install.sh ``` - Make sure to check our [Officially supported platforms](#officially-supported-platforms) section below. Our installer might not work on distros that are not listed there, but it will still try to install using packages from supported distros, just follow the on-screen instructions. -- If installer fails trying to install on an unsupported distro, you're on your own on trying to get the local dev environment up and running. Check `install_pince.sh` to get an idea about what you might need. +- If installer fails trying to install on an unsupported distro, you're on your own on trying to get the local dev environment up and running. Check `install.sh` to get an idea about what you might need. - If you'd like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them as well if you want. ***Notes:*** diff --git a/install_gdb.sh b/compile_gdb.sh similarity index 100% rename from install_gdb.sh rename to compile_gdb.sh diff --git a/install_pince.sh b/install.sh similarity index 94% rename from install_pince.sh rename to install.sh index 80ef65cb..830feb24 100755 --- a/install_pince.sh +++ b/install.sh @@ -16,15 +16,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ' -# this file cannot (or any file) be named `install.sh` since libtoolize(automake) will not work properly if it does -# it will create the necessary files in PINCEs directory instead of libscanmem's, which will result in having to run `sh autogen.sh` -# twice, see this link https://github.com/protocolbuffers/protobuf/issues/149#issuecomment-473092810 - if [ "$(id -u)" = "0" ]; then echo "Please do not run this script as root!" exit 1 fi +SCRIPTDIR=$(cd -- "$(dirname -- "$0")" && pwd -P) +cd $SCRIPTDIR if [ ! -d ".git" ]; then echo "Error! Could not find \".git\" folder!" echo "This can happen if you downloaded the ZIP file instead of cloning through git." From de9c64a32825bc24ac7bdff9a80cca34c58ca0cc Mon Sep 17 00:00:00 2001 From: brkzlr Date: Wed, 22 May 2024 23:41:59 +0100 Subject: [PATCH 442/487] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 939016cc..20ef8c4c 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ sudo -E ./PINCE-x86_64.AppImage git clone --recursive https://github.com/korcankaraokcu/PINCE sh PINCE/install.sh ``` +- You can run PINCE afterwards by typing `sh PINCE.sh` inside PINCE folder or `sh (PINCE folder location)/PINCE.sh` from anywhere else. - Make sure to check our [Officially supported platforms](#officially-supported-platforms) section below. Our installer might not work on distros that are not listed there, but it will still try to install using packages from supported distros, just follow the on-screen instructions. - If installer fails trying to install on an unsupported distro, you're on your own on trying to get the local dev environment up and running. Check `install.sh` to get an idea about what you might need. - If you'd like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them as well if you want. From 065a797f4265a22ca7aeb2d77ea6466964e95d94 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Wed, 22 May 2024 23:51:48 +0100 Subject: [PATCH 443/487] Change install_gdb references to compile_gdb --- CONTRIBUTING.md | 2 +- README.md | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20b21b29..ccf1192f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ - [install.sh](./install.sh) - Installation script - [compile_ts.sh](./compile_ts.sh) - Gathers translation information from various sources and compiles them into ts files - [fix_ts.py](./fix_ts.py) - Fixes line information issue, used within [compile_ts.sh](./compile_ts.sh) -- [install_gdb.sh](./install_gdb.sh) - PINCE normally uses system GDB but in cases where system GDB is unavailable, this script is used to compile GDB locally +- [compile_gdb.sh](./compile_gdb.sh) - PINCE normally uses system GDB but in cases where system GDB is unavailable, this script is used to compile GDB locally - [GUI](./GUI) - Contains Qt Designer forms and their respective codes along with utility functions and custom Qt classes - [media](./media) - Contains media files such as logos and icons - [tr](./tr) - Contains translation constants diff --git a/README.md b/README.md index 20ef8c4c..1dec2604 100644 --- a/README.md +++ b/README.md @@ -72,13 +72,12 @@ sudo -E ./PINCE-x86_64.AppImage git clone --recursive https://github.com/korcankaraokcu/PINCE sh PINCE/install.sh ``` -- You can run PINCE afterwards by typing `sh PINCE.sh` inside PINCE folder or `sh (PINCE folder location)/PINCE.sh` from anywhere else. - Make sure to check our [Officially supported platforms](#officially-supported-platforms) section below. Our installer might not work on distros that are not listed there, but it will still try to install using packages from supported distros, just follow the on-screen instructions. - If installer fails trying to install on an unsupported distro, you're on your own on trying to get the local dev environment up and running. Check `install.sh` to get an idea about what you might need. - If you'd like to uninstall PINCE, just delete this folder, almost everything is installed locally. Config and user files of PINCE can be found in "~/.config/PINCE", you can manually delete them as well if you want. ***Notes:*** -- If you are having problems with your default gdb version, you can use the `install_gdb.sh` script to install another version locally. Read the comments in it for more information +- If you are having problems with your default gdb version, you can use the `compile_gdb.sh` script to compile another version locally. Read the comments in it for more information - Check https://github.com/korcankaraokcu/PINCE/issues/116 for a possible fix if you encounter `'GtkSettings' has no property named 'gtk-fallback-icon-theme'` # Officially supported platforms From c89ff42b5f68b20b2be35ab08328e12deb12abd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 23 May 2024 15:50:45 +0300 Subject: [PATCH 444/487] Fix wait_for_stop --- libpince/debugcore.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 7d1e5045..8e0a6989 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -398,10 +398,10 @@ def wait_for_stop(timeout=0): """ remaining_time = timeout while inferior_status == typedefs.INFERIOR_STATUS.RUNNING: - sleep(typedefs.CONST_TIME.GDB_INPUT_SLEEP) + sleep(0.0001) if timeout == 0: continue - remaining_time -= typedefs.CONST_TIME.GDB_INPUT_SLEEP + remaining_time -= 0.0001 if remaining_time < 0: break @@ -424,7 +424,7 @@ def interrupt_inferior(interrupt_reason=typedefs.STOP_REASON.DEBUG): os.system(f"kill -{sig_num} {currentpid}") else: os.system(f"kill -s {interrupt_signal} {currentpid}") - wait_for_stop() + wait_for_stop(1) stop_reason = interrupt_reason From b9939fe88431507ad8b898cabc592e9da6d822d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 24 May 2024 18:42:12 +0300 Subject: [PATCH 445/487] Fix file locations and pointer translations --- PINCE.py | 52 ++++++++++++---------------------------- i18n/ts/it_IT.ts | 54 ++++++++++++++++++++++++++++++++++-------- i18n/ts/zh_CN.ts | 56 +++++++++++++++++++++++++++++++++++--------- libpince/typedefs.py | 8 +------ libpince/utils.py | 6 ++--- tr/tr.py | 15 +++++++----- 6 files changed, 116 insertions(+), 75 deletions(-) diff --git a/PINCE.py b/PINCE.py index 6ec6688e..9cbd9f09 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1504,8 +1504,7 @@ def pushButton_AttachProcess_clicked(self): self.processwindow.show() def pushButton_Open_clicked(self): - pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES) - file_paths = QFileDialog.getOpenFileNames(self, tr.OPEN_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] + file_paths, _ = QFileDialog.getOpenFileNames(self, tr.OPEN_PCT_FILE, None, tr.FILE_TYPES_PCT) if not file_paths: return self.clear_address_table() @@ -1521,8 +1520,7 @@ def pushButton_Open_clicked(self): ) def pushButton_Save_clicked(self): - pct_file_path = utils.get_user_path(typedefs.USER_PATHS.CHEAT_TABLES) - file_path = QFileDialog.getSaveFileName(self, tr.SAVE_PCT_FILE, pct_file_path, tr.FILE_TYPES_PCT)[0] + file_path, _ = QFileDialog.getSaveFileName(self, tr.SAVE_PCT_FILE, None, tr.FILE_TYPES_PCT) if not file_path: return content = [ @@ -1964,7 +1962,7 @@ def pushButton_Open_clicked(self): self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) def pushButton_CreateProcess_clicked(self): - file_path = QFileDialog.getOpenFileName(self, tr.SELECT_BINARY)[0] + file_path, _ = QFileDialog.getOpenFileName(self, tr.SELECT_BINARY) if file_path: items = [(tr.ENTER_OPTIONAL_ARGS, ""), (tr.LD_PRELOAD_OPTIONAL, "")] arg_dialog = InputDialogForm(self, items) @@ -2678,7 +2676,7 @@ def comboBox_Theme_current_index_changed(self): def pushButton_GDBPath_clicked(self): current_path = self.lineEdit_GDBPath.text() - file_path = QFileDialog.getOpenFileName(self, tr.SELECT_GDB_BINARY, os.path.dirname(current_path))[0] + file_path, _ = QFileDialog.getOpenFileName(self, tr.SELECT_GDB_BINARY, os.path.dirname(current_path)) if file_path: self.lineEdit_GDBPath.setText(file_path) @@ -4363,7 +4361,7 @@ def actionReferenced_Calls_triggered(self): def actionInject_so_file_triggered(self): if debugcore.currentpid == -1: return - file_path = QFileDialog.getOpenFileName(self, tr.SELECT_SO_FILE, "", tr.SHARED_OBJECT_TYPE)[0] + file_path, _ = QFileDialog.getOpenFileName(self, tr.SELECT_SO_FILE, "", tr.SHARED_OBJECT_TYPE) if file_path: if debugcore.inject_with_dlopen_call(file_path): QMessageBox.information(self, tr.SUCCESS, tr.FILE_INJECTED) @@ -5111,16 +5109,14 @@ def show_trace_info(self): self.treeWidget_InstructionInfo.expandAll() def save_file(self): - trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS) - file_path = QFileDialog.getSaveFileName(self, tr.SAVE_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] + file_path, _ = QFileDialog.getSaveFileName(self, tr.SAVE_TRACE_FILE, None, tr.FILE_TYPES_TRACE) if file_path: file_path = utils.append_file_extension(file_path, "trace") if not utils.save_file(self.tracer.trace_data, file_path): QMessageBox.information(self, tr.ERROR, tr.FILE_SAVE_ERROR) def load_file(self): - trace_file_path = utils.get_user_path(typedefs.USER_PATHS.TRACE_INSTRUCTIONS) - file_path = QFileDialog.getOpenFileName(self, tr.OPEN_TRACE_FILE, trace_file_path, tr.FILE_TYPES_TRACE)[0] + file_path, _ = QFileDialog.getOpenFileName(self, tr.OPEN_TRACE_FILE, None, tr.FILE_TYPES_TRACE) if file_path: content = utils.load_file(file_path) if content is None: @@ -6332,17 +6328,13 @@ def __init__(self, parent, address) -> None: self.lineEdit_Address.setText(address) self.lineEdit_Path.setText(os.getcwd() + f"/{utils.get_process_name(debugcore.currentpid)}.scandata") self.pushButton_PathBrowse.clicked.connect(self.pushButton_PathBrowse_clicked) - self.scan_button: QPushButton | None = self.buttonBox.addButton("Scan", QDialogButtonBox.ButtonRole.ActionRole) + self.scan_button = self.buttonBox.addButton(tr.SCAN, QDialogButtonBox.ButtonRole.ActionRole) if self.scan_button: self.scan_button.clicked.connect(self.scan_button_clicked) self.ptrscan_thread: InterruptableWorker | None = None def pushButton_PathBrowse_clicked(self) -> None: - scan_filter: str = "Pointer Scan Data (*.scandata)" - filename: str - filename, _ = QFileDialog.getSaveFileName( - parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter - ) + filename, _ = QFileDialog.getSaveFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) if filename != "": if not re.search(r"\.scandata$", filename): filename = filename + ".scandata" @@ -6356,7 +6348,7 @@ def reject(self) -> None: def scan_button_clicked(self) -> None: if debugcore.currentpid == -1 or self.scan_button == None: return - self.scan_button.setText("Scanning") + self.scan_button.setText(tr.SCANNING) self.scan_button.setEnabled(False) self.pushButton_PathBrowse.setEnabled(False) params: FFIParam = FFIParam() @@ -6402,20 +6394,14 @@ def __init__(self, parent) -> None: guiutils.center_to_parent(self) self.pushButton_File1Browse.clicked.connect(self.pushButton_File1Browse_clicked) self.pushButton_File2Browse.clicked.connect(self.pushButton_File2Browse_clicked) - self.filter_button: QPushButton | None = self.buttonBox.addButton( - "Filter", QDialogButtonBox.ButtonRole.ActionRole - ) + self.filter_button = self.buttonBox.addButton(tr.FILTER, QDialogButtonBox.ButtonRole.ActionRole) if self.filter_button: self.filter_button.clicked.connect(self.filter_button_clicked) self.filter_button.setEnabled(False) self.filter_result: list[str] | None = None def browse_scandata_file(self, file_path_field: QLineEdit) -> None: - scan_filter: str = "Pointer Scan Data (*.scandata)" - filename: str - filename, _ = QFileDialog.getOpenFileName( - parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter - ) + filename, _ = QFileDialog.getOpenFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) if filename != "": file_path_field.setText(filename) self.check_filterable_state() @@ -6434,7 +6420,7 @@ def filter_button_clicked(self) -> None: if self.lineEdit_File1Path.text() == "" or self.lineEdit_File2Path.text() == "" or self.filter_button == None: return self.filter_button.setEnabled(False) - self.filter_button.setText("Filtering") + self.filter_button.setText(tr.FILTERING) lines: list[str] with open(self.lineEdit_File1Path.text()) as file: lines = file.read().split(os.linesep) @@ -6485,22 +6471,14 @@ def pushButton_Sort_pressed(self) -> None: self.textEdit.setText(os.linesep.join(text_list)) def actionOpen_triggered(self) -> None: - scan_filter: str = "Pointer Scan Data (*.scandata)" - filename: str - filename, _ = QFileDialog.getOpenFileName( - parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter - ) + filename, _ = QFileDialog.getOpenFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) if filename != "": self.textEdit.clear() with open(filename) as file: self.textEdit.setText(file.read()) def actionSaveAs_triggered(self) -> None: - scan_filter: str = "Pointer Scan Data (*.scandata)" - filename: str - filename, _ = QFileDialog.getSaveFileName( - parent=self, caption="Select a pointer map file", filter=scan_filter, initialFilter=scan_filter - ) + filename, _ = QFileDialog.getSaveFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) if filename != "": if not re.search(r"\.scandata$", filename): filename = filename + ".scandata" diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index dca01652..51a9c612 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -710,7 +710,6 @@ Patterns at former positions have higher priority if regex is off - Form @@ -807,6 +806,11 @@ Patterns at former positions have higher priority if regex is off Return Address + + + Tracer Status + + Cancel @@ -1748,6 +1752,21 @@ To change the current GDB path, check Settings->Debug PINCE Cheat Table (*.pct);;All files (*) + + + Shared object library (*.so) + + + + + Trace File (*.trace);;All Files (*) + + + + + Pointer Scan Data (*.scandata);;All files (*) + + Clear address table? @@ -2262,11 +2281,6 @@ PINCE will track down addresses [rax],[rbx*rcx+4] and [rbp] Select the .so file - - - Shared object library (*.so) - - The file has been injected @@ -2434,22 +2448,42 @@ You can use the assigned variable from the GDB Console - Trace File (*.trace);;All Files (*) + Open trace file - Open trace file + Expand All - Expand All + Collapse All - Collapse All + Select a pointer map file + + + + + Scan + + + + + Scanning + + + + + Filter + + + + + Filtering diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index be785c07..9a08dc70 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -712,7 +712,6 @@ Patterns at former positions have higher priority if regex is off - Form 表格 @@ -809,6 +808,11 @@ Patterns at former positions have higher priority if regex is off Return Address 返回地址 + + + Tracer Status + + Cancel @@ -1752,6 +1756,21 @@ To change the current GDB path, check Settings->Debug PINCE Cheat Table (*.pct);;All files (*) PINCE 作弊表 (*.pct);;所有文件 (*) + + + Shared object library (*.so) + 共享对象库 (*.so) + + + + Trace File (*.trace);;All Files (*) + 追踪文件 (*.trace);;所有文件 (*) + + + + Pointer Scan Data (*.scandata);;All files (*) + + Clear address table? @@ -2305,11 +2324,6 @@ PINCE 将追踪地址 [rax],[rbx*rcx+4] 和 [rbp] Select the .so file 选择 .so 文件 - - - Shared object library (*.so) - 共享对象库 (*.so) - The file has been injected @@ -2485,11 +2499,6 @@ $28 是分配的便利变量 Save trace file 保存追踪文件 - - - Trace File (*.trace);;All Files (*) - 追踪文件 (*.trace);;所有文件 (*) - Open trace file @@ -2505,6 +2514,31 @@ $28 是分配的便利变量 Collapse All 收起全部 + + + Select a pointer map file + + + + + Scan + + + + + Scanning + + + + + Filter + + + + + Filtering + + DEFINED diff --git a/libpince/typedefs.py b/libpince/typedefs.py index 7980c6bf..910e7d6a 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -36,18 +36,12 @@ class PATHS: class USER_PATHS: # Use utils.get_user_path() to make use of these CONFIG = ".config/" - ROOT = CONFIG + "PINCE/PINCE_USER_FILES/" - TRACE_INSTRUCTIONS = ROOT + "TraceInstructions/" - CHEAT_TABLES = ROOT + "CheatTables/" + ROOT = CONFIG + "PINCE/" GDBINIT = ROOT + "gdbinit" GDBINIT_AA = ROOT + "gdbinit_after_attach" PINCEINIT = ROOT + "pinceinit.py" PINCEINIT_AA = ROOT + "pinceinit_after_attach.py" - @staticmethod - def get_init_directories(): - return USER_PATHS.ROOT, USER_PATHS.TRACE_INSTRUCTIONS, USER_PATHS.CHEAT_TABLES - @staticmethod def get_init_files(): return ( diff --git a/libpince/utils.py b/libpince/utils.py index 94eb894b..cba1cfb2 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -1045,10 +1045,8 @@ def get_module_name(module): #:tag:Utilities def init_user_files(): """Initializes user files""" - for directory in typedefs.USER_PATHS.get_init_directories(): - path = get_user_path(directory) - if not os.path.exists(path): - os.makedirs(path) + if not os.path.exists(typedefs.USER_PATHS.ROOT): + os.makedirs(typedefs.USER_PATHS.ROOT) for file in typedefs.USER_PATHS.get_init_files(): file = get_user_path(file) try: diff --git a/tr/tr.py b/tr/tr.py index 17f446c3..3be85ea4 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -93,7 +93,11 @@ def translate(): # Keep (*.pct) and (*) while translating, it doesn't matter where it stays within the sentence # For instance, you can keep (*) in the beginning of the sentence for right-to-left languages like arabic # All entries are separated by ;; Please try to respect the original order of the file types + # Apply the same to similar entries below FILE_TYPES_PCT = QT_TR_NOOP("PINCE Cheat Table (*.pct);;All files (*)") + SHARED_OBJECT_TYPE = QT_TR_NOOP("Shared object library (*.so)") + FILE_TYPES_TRACE = QT_TR_NOOP("Trace File (*.trace);;All Files (*)") + FILE_TYPES_SCANDATA = QT_TR_NOOP("Pointer Scan Data (*.scandata);;All files (*)") CLEAR_TABLE = QT_TR_NOOP("Clear address table?") FILE_LOAD_ERROR = QT_TR_NOOP("File {} is inaccessible or contains invalid content") SAVE_PCT_FILE = QT_TR_NOOP("Save PCT file") @@ -236,9 +240,6 @@ def translate(): ALREADY_BOOKMARKED = QT_TR_NOOP("This address has already been bookmarked") ENTER_BOOKMARK_COMMENT = QT_TR_NOOP("Enter the comment for bookmarked address") SELECT_SO_FILE = QT_TR_NOOP("Select the .so file") - - # Same applies here, keep (*.so) - SHARED_OBJECT_TYPE = QT_TR_NOOP("Shared object library (*.so)") FILE_INJECTED = QT_TR_NOOP("The file has been injected") FILE_INJECT_FAILED = QT_TR_NOOP("Failed to inject the .so file") ENTER_CALL_EXPRESSION = QT_TR_NOOP( @@ -280,12 +281,14 @@ def translate(): DELETE_BREAKPOINT_FAILED = QT_TR_NOOP("Unable to delete breakpoint at expression {}") MAX_TRACE_COUNT_ASSERT_GT = QT_TR_NOOP("Max trace count must be greater than or equal to {}") SAVE_TRACE_FILE = QT_TR_NOOP("Save trace file") - - # Same applies here, keep (*.trace) and (*) - FILE_TYPES_TRACE = QT_TR_NOOP("Trace File (*.trace);;All Files (*)") OPEN_TRACE_FILE = QT_TR_NOOP("Open trace file") EXPAND_ALL = QT_TR_NOOP("Expand All") COLLAPSE_ALL = QT_TR_NOOP("Collapse All") + SELECT_POINTER_MAP = QT_TR_NOOP("Select a pointer map file") + SCAN = QT_TR_NOOP("Scan") + SCANNING = QT_TR_NOOP("Scanning") + FILTER = QT_TR_NOOP("Filter") + FILTERING = QT_TR_NOOP("Filtering") DEFINED = QT_TR_NOOP("DEFINED") DEFINED_SYMBOL = QT_TR_NOOP( "This symbol is defined. You can use its body as a gdb expression. For instance:\n\n" From e6bbd184e8c144a62fadc8ad2a964126c99d4099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 25 May 2024 16:29:58 +0300 Subject: [PATCH 446/487] Fix file extension translations, variable names and type hints --- PINCE.py | 36 ++++++++++++++++++------------------ i18n/ts/it_IT.ts | 6 +++--- i18n/ts/zh_CN.ts | 10 +++++----- tr/tr.py | 6 +++--- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/PINCE.py b/PINCE.py index 9cbd9f09..f3b39aed 100755 --- a/PINCE.py +++ b/PINCE.py @@ -6328,17 +6328,16 @@ def __init__(self, parent, address) -> None: self.lineEdit_Address.setText(address) self.lineEdit_Path.setText(os.getcwd() + f"/{utils.get_process_name(debugcore.currentpid)}.scandata") self.pushButton_PathBrowse.clicked.connect(self.pushButton_PathBrowse_clicked) - self.scan_button = self.buttonBox.addButton(tr.SCAN, QDialogButtonBox.ButtonRole.ActionRole) + self.scan_button: QPushButton | None = self.buttonBox.addButton(tr.SCAN, QDialogButtonBox.ButtonRole.ActionRole) if self.scan_button: self.scan_button.clicked.connect(self.scan_button_clicked) self.ptrscan_thread: InterruptableWorker | None = None def pushButton_PathBrowse_clicked(self) -> None: - filename, _ = QFileDialog.getSaveFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) - if filename != "": - if not re.search(r"\.scandata$", filename): - filename = filename + ".scandata" - self.lineEdit_Path.setText(filename) + file_path, _ = QFileDialog.getSaveFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) + if file_path != "": + file_path = utils.append_file_extension(file_path, "scandata") + self.lineEdit_Path.setText(file_path) def reject(self) -> None: if self.ptrscan_thread: @@ -6394,16 +6393,18 @@ def __init__(self, parent) -> None: guiutils.center_to_parent(self) self.pushButton_File1Browse.clicked.connect(self.pushButton_File1Browse_clicked) self.pushButton_File2Browse.clicked.connect(self.pushButton_File2Browse_clicked) - self.filter_button = self.buttonBox.addButton(tr.FILTER, QDialogButtonBox.ButtonRole.ActionRole) + self.filter_button: QPushButton | None = self.buttonBox.addButton( + tr.FILTER, QDialogButtonBox.ButtonRole.ActionRole + ) if self.filter_button: self.filter_button.clicked.connect(self.filter_button_clicked) self.filter_button.setEnabled(False) self.filter_result: list[str] | None = None def browse_scandata_file(self, file_path_field: QLineEdit) -> None: - filename, _ = QFileDialog.getOpenFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) - if filename != "": - file_path_field.setText(filename) + file_path, _ = QFileDialog.getOpenFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) + if file_path != "": + file_path_field.setText(file_path) self.check_filterable_state() def check_filterable_state(self) -> None: @@ -6471,18 +6472,17 @@ def pushButton_Sort_pressed(self) -> None: self.textEdit.setText(os.linesep.join(text_list)) def actionOpen_triggered(self) -> None: - filename, _ = QFileDialog.getOpenFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) - if filename != "": + file_path, _ = QFileDialog.getOpenFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) + if file_path != "": self.textEdit.clear() - with open(filename) as file: + with open(file_path) as file: self.textEdit.setText(file.read()) def actionSaveAs_triggered(self) -> None: - filename, _ = QFileDialog.getSaveFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) - if filename != "": - if not re.search(r"\.scandata$", filename): - filename = filename + ".scandata" - with open(filename, "w") as file: + file_path, _ = QFileDialog.getSaveFileName(self, tr.SELECT_POINTER_MAP, None, tr.FILE_TYPES_SCANDATA) + if file_path != "": + file_path = utils.append_file_extension(file_path, "scandata") + with open(file_path, "w") as file: file.write(self.textEdit.toPlainText()) def scan_triggered(self) -> None: diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 51a9c612..1e05c766 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1749,7 +1749,7 @@ To change the current GDB path, check Settings->Debug - PINCE Cheat Table (*.pct);;All files (*) + PINCE Cheat Table (*.pct) @@ -1759,12 +1759,12 @@ To change the current GDB path, check Settings->Debug - Trace File (*.trace);;All Files (*) + Trace File (*.trace) - Pointer Scan Data (*.scandata);;All files (*) + Pointer Scan Data (*.scandata) diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 9a08dc70..55aa37c9 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1753,8 +1753,8 @@ To change the current GDB path, check Settings->Debug - PINCE Cheat Table (*.pct);;All files (*) - PINCE 作弊表 (*.pct);;所有文件 (*) + PINCE Cheat Table (*.pct) + PINCE 作弊表 (*.pct) @@ -1763,12 +1763,12 @@ To change the current GDB path, check Settings->Debug - Trace File (*.trace);;All Files (*) - 追踪文件 (*.trace);;所有文件 (*) + Trace File (*.trace) + 追踪文件 (*.trace) - Pointer Scan Data (*.scandata);;All files (*) + Pointer Scan Data (*.scandata) diff --git a/tr/tr.py b/tr/tr.py index 3be85ea4..6c9d7d9e 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -94,10 +94,10 @@ def translate(): # For instance, you can keep (*) in the beginning of the sentence for right-to-left languages like arabic # All entries are separated by ;; Please try to respect the original order of the file types # Apply the same to similar entries below - FILE_TYPES_PCT = QT_TR_NOOP("PINCE Cheat Table (*.pct);;All files (*)") + FILE_TYPES_PCT = QT_TR_NOOP("PINCE Cheat Table (*.pct)") SHARED_OBJECT_TYPE = QT_TR_NOOP("Shared object library (*.so)") - FILE_TYPES_TRACE = QT_TR_NOOP("Trace File (*.trace);;All Files (*)") - FILE_TYPES_SCANDATA = QT_TR_NOOP("Pointer Scan Data (*.scandata);;All files (*)") + FILE_TYPES_TRACE = QT_TR_NOOP("Trace File (*.trace)") + FILE_TYPES_SCANDATA = QT_TR_NOOP("Pointer Scan Data (*.scandata)") CLEAR_TABLE = QT_TR_NOOP("Clear address table?") FILE_LOAD_ERROR = QT_TR_NOOP("File {} is inaccessible or contains invalid content") SAVE_PCT_FILE = QT_TR_NOOP("Save PCT file") From 823b213c531d9ffda1aa2b6504bc8a9eefc0c27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 25 May 2024 16:38:07 +0300 Subject: [PATCH 447/487] Update translation docs --- tr/tr.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tr/tr.py b/tr/tr.py index 6c9d7d9e..01f1de77 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -90,9 +90,8 @@ def translate(): NO_DESCRIPTION = QT_TR_NOOP("No Description") OPEN_PCT_FILE = QT_TR_NOOP("Open PCT file(s)") - # Keep (*.pct) and (*) while translating, it doesn't matter where it stays within the sentence - # For instance, you can keep (*) in the beginning of the sentence for right-to-left languages like arabic - # All entries are separated by ;; Please try to respect the original order of the file types + # Keep file extensions such as (*.pct) while translating, it doesn't matter where it stays within the sentence + # For instance, you can keep (*.pct) in the beginning of the sentence for right-to-left languages like arabic # Apply the same to similar entries below FILE_TYPES_PCT = QT_TR_NOOP("PINCE Cheat Table (*.pct)") SHARED_OBJECT_TYPE = QT_TR_NOOP("Shared object library (*.so)") From d98701d89243fcf070ee33b6f851a8e7c3200639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 28 May 2024 20:30:36 +0300 Subject: [PATCH 448/487] Disable gdb path setting for AppImage builds --- GUI/SettingsDialog.py | 8 ++++---- GUI/SettingsDialog.ui | 2 +- PINCE.py | 20 ++++++++++++++------ i18n/ts/it_IT.ts | 5 +++++ i18n/ts/zh_CN.ts | 5 +++++ tr/tr.py | 1 + 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/GUI/SettingsDialog.py b/GUI/SettingsDialog.py index 180a41ad..9060a85a 100644 --- a/GUI/SettingsDialog.py +++ b/GUI/SettingsDialog.py @@ -298,9 +298,9 @@ def setupUi(self, Dialog): self.horizontalLayout_11.setObjectName("horizontalLayout_11") self.horizontalLayout_101 = QtWidgets.QHBoxLayout() self.horizontalLayout_101.setObjectName("horizontalLayout_101") - self.label_7 = QtWidgets.QLabel(parent=self.page_5) - self.label_7.setObjectName("label_7") - self.horizontalLayout_101.addWidget(self.label_7) + self.label_GDBPath = QtWidgets.QLabel(parent=self.page_5) + self.label_GDBPath.setObjectName("label_GDBPath") + self.horizontalLayout_101.addWidget(self.label_GDBPath) self.lineEdit_GDBPath = QtWidgets.QLineEdit(parent=self.page_5) self.lineEdit_GDBPath.setObjectName("lineEdit_GDBPath") self.horizontalLayout_101.addWidget(self.lineEdit_GDBPath) @@ -411,7 +411,7 @@ def retranslateUi(self, Dialog): self.checkBox_ShowMemoryViewOnStop.setText(_translate("Dialog", "Bring Memory View to front when the inferior is stopped")) self.label_6.setText(_translate("Dialog", "Instructions shown per scroll in Disassembly View")) self.label_16.setText(_translate("Dialog", "Bytes shown per scroll in Hex View")) - self.label_7.setText(_translate("Dialog", "GDB Path")) + self.label_GDBPath.setText(_translate("Dialog", "GDB Path")) self.checkBox_GDBLogging.setText(_translate("Dialog", "GDB Logging")) self.label_15.setText(_translate("Dialog", "Interruption signal")) self.pushButton_HandleSignals.setText(_translate("Dialog", "Handle Signals")) diff --git a/GUI/SettingsDialog.ui b/GUI/SettingsDialog.ui index ab0c5bc5..2b067680 100644 --- a/GUI/SettingsDialog.ui +++ b/GUI/SettingsDialog.ui @@ -641,7 +641,7 @@ Patterns at former positions have higher priority if regex is off - + GDB Path diff --git a/PINCE.py b/PINCE.py index f3b39aed..1715d8ed 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2575,12 +2575,13 @@ def accept(self): self.settings.setValue("MemoryView/show_memory_view_on_stop", self.checkBox_ShowMemoryViewOnStop.isChecked()) self.settings.setValue("MemoryView/instructions_per_scroll", self.spinBox_InstructionsPerScroll.value()) self.settings.setValue("MemoryView/bytes_per_scroll", self.spinBox_BytesPerScroll.value()) - selected_gdb_path = self.lineEdit_GDBPath.text() - current_gdb_path = self.settings.value("Debug/gdb_path", type=str) - if selected_gdb_path != current_gdb_path: - if InputDialogForm(self, [(tr.GDB_RESET,)]).exec(): - debugcore.init_gdb(selected_gdb_path) - self.settings.setValue("Debug/gdb_path", selected_gdb_path) + if not os.environ.get("APPDIR"): + selected_gdb_path = self.lineEdit_GDBPath.text() + current_gdb_path = self.settings.value("Debug/gdb_path", type=str) + if selected_gdb_path != current_gdb_path: + if InputDialogForm(self, [(tr.GDB_RESET,)]).exec(): + debugcore.init_gdb(selected_gdb_path) + self.settings.setValue("Debug/gdb_path", selected_gdb_path) self.settings.setValue("Debug/gdb_logging", self.checkBox_GDBLogging.isChecked()) self.settings.setValue("Debug/interrupt_signal", self.comboBox_InterruptSignal.currentText()) self.settings.setValue("Java/ignore_segfault", self.checkBox_JavaSegfault.isChecked()) @@ -2630,6 +2631,13 @@ def config_gui(self): self.spinBox_InstructionsPerScroll.setValue(self.settings.value("MemoryView/instructions_per_scroll", type=int)) self.spinBox_BytesPerScroll.setValue(self.settings.value("MemoryView/bytes_per_scroll", type=int)) self.lineEdit_GDBPath.setText(str(self.settings.value("Debug/gdb_path", type=str))) + if os.environ.get("APPDIR"): + self.label_GDBPath.setDisabled(True) + self.label_GDBPath.setToolTip(tr.APPIMAGE_SETTING_GDB) + self.lineEdit_GDBPath.setDisabled(True) + self.lineEdit_GDBPath.setToolTip(tr.APPIMAGE_SETTING_GDB) + self.pushButton_GDBPath.setDisabled(True) + self.pushButton_GDBPath.setToolTip(tr.APPIMAGE_SETTING_GDB) self.checkBox_GDBLogging.setChecked(self.settings.value("Debug/gdb_logging", type=bool)) self.comboBox_InterruptSignal.setCurrentText(self.settings.value("Debug/interrupt_signal", type=str)) self.checkBox_JavaSegfault.setChecked(self.settings.value("Java/ignore_segfault", type=bool)) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 1e05c766..c7991ad0 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1941,6 +1941,11 @@ Use the char \ to escape special chars such as [ Separate processes with {} + + + This setting is unused in AppImage builds + + Select the gdb binary diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 55aa37c9..ea2f413d 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1949,6 +1949,11 @@ Use the char \ to escape special chars such as [ Separate processes with {} 使用 {} 分隔进程 + + + This setting is unused in AppImage builds + + Select the gdb binary diff --git a/tr/tr.py b/tr/tr.py index 01f1de77..82049e55 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -136,6 +136,7 @@ def translate(): r"\[asdf\] --> search for opcodes that contain [asdf]" ) SEPARATE_PROCESSES_WITH = QT_TR_NOOP("Separate processes with {}") + APPIMAGE_SETTING_GDB = QT_TR_NOOP("This setting is unused in AppImage builds") SELECT_GDB_BINARY = QT_TR_NOOP("Select the gdb binary") QUIT_SESSION_CRASH = QT_TR_NOOP("Quitting current session will crash PINCE") CONT_SESSION_CRASH = QT_TR_NOOP("Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior") From 4c0faea01fedd70bb2f2f9de5a6ebcb7d231824d Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 1 Jun 2024 21:40:06 +0100 Subject: [PATCH 449/487] Update package.sh to include libxcb-cursor --- ci/package.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/package.sh b/ci/package.sh index 6d31577e..7b237d08 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -81,7 +81,8 @@ exit_on_failure() { # Create AppImage's AppDir with a Conda environment pre-baked # containing our required pip packages export PIP_REQUIREMENTS="-r ../requirements.txt" -export CONDA_PACKAGES="libstdcxx-ng" # Need this to get libstdc++ higher than 6.0.29 +# Need this to get libstdc++ higher than default 6.0.29 and libxcb-cursor for Debian family +export CONDA_PACKAGES="libstdcxx-ng xcb-util-cursor" $DEPLOYTOOL --appdir AppDir -pconda || exit_on_failure # Create PINCE directory From f3cbbab9c947cf0776d253227ecfd18d448bff82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 1 Jun 2024 23:51:10 +0300 Subject: [PATCH 450/487] Append 0x to hex expressions if missing --- PINCE.py | 14 ++++++++------ libpince/debugcore.py | 19 ++++++++++++++++++- libpince/regexes.py | 4 ++++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/PINCE.py b/PINCE.py index 1715d8ed..23357391 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2095,9 +2095,8 @@ def caps_hex_or_error_indicator(self, address: int): def update_value(self): if self.checkBox_IsPointer.isChecked(): - pointer_chain_req = typedefs.PointerChainRequest( - self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list() - ) + hex_converted_expr = debugcore.convert_to_hex(self.lineEdit_PtrStartAddress.text()) + pointer_chain_req = typedefs.PointerChainRequest(hex_converted_expr, self.get_offsets_int_list()) pointer_chain_result = debugcore.read_pointer_chain(pointer_chain_req) address = None if pointer_chain_result != None: @@ -2108,7 +2107,8 @@ def update_value(self): self.lineEdit_Address.setText(address_text) self.update_deref_labels(pointer_chain_result) else: - address = debugcore.examine_expression(self.lineEdit_Address.text()).address + hex_converted_expr = debugcore.convert_to_hex(self.lineEdit_Address.text()) + address = debugcore.examine_expression(hex_converted_expr).address if self.checkBox_Hex.isChecked(): value_repr = typedefs.VALUE_REPR.HEX elif self.checkBox_Signed.isChecked(): @@ -2176,7 +2176,6 @@ def accept(self): def get_values(self): description = self.lineEdit_Description.text() - address = self.lineEdit_Address.text() length = self.lineEdit_Length.text() try: length = int(length, 0) @@ -2193,7 +2192,10 @@ def get_values(self): endian = self.comboBox_Endianness.currentData(Qt.ItemDataRole.UserRole) vt = typedefs.ValueType(value_index, length, zero_terminate, value_repr, endian) if self.checkBox_IsPointer.isChecked(): - address = typedefs.PointerChainRequest(self.lineEdit_PtrStartAddress.text(), self.get_offsets_int_list()) + base_expression = debugcore.convert_to_hex(self.lineEdit_PtrStartAddress.text()) + address = typedefs.PointerChainRequest(base_expression, self.get_offsets_int_list()) + else: + address = debugcore.convert_to_hex(self.lineEdit_Address.text()) return description, address, vt def get_offsets_int_list(self): diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 8e0a6989..4f9e1d42 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1018,7 +1018,24 @@ def disassemble(expression, offset_or_address): return disas_data -#:tag:GDBExpressions +def convert_to_hex(expression): + """Converts numeric values in the expression into their hex equivalents + Respects edge cases like indexed maps and keeps indexes as decimals + + Args: + expression (str): Any gdb expression + + Returns: + str: Converted str + """ + # TODO (lldb): We'll most likely write our own expression parser once we switch to lldb + # Merge this function with examine_expression and gdbutils.examine_expression once that happens + return regexes.expression_with_hex.sub( + lambda m: "0x" + m.group(1) if m.group(1) and not examine_expression(m.group(1)).symbol else m.group(0), + expression, + ) + + def examine_expression(expression): """Evaluates the given expression and returns evaluated value, address and symbol diff --git a/libpince/regexes.py b/libpince/regexes.py index 673835b2..d1cb2cb5 100644 --- a/libpince/regexes.py +++ b/libpince/regexes.py @@ -37,6 +37,10 @@ entry_point = compile(r"Entry\s+point:\s+" + hex_number_grouped.pattern) # The command will always start with the word "source", check debugcore.send_command function for the cause gdb_command_source = lambda command_file: compile(r"&\".*source\s" + command_file + r"\\n\"") # &"command\n" +# This will only match hex patterns without 0x and ignore the ones below: +# Hex patterns with 0x such as 0x5123 +# Map symbols of PINCE, such as kmines[2] +expression_with_hex = compile(r"\b0x[0-9a-fA-F]+|[a-zA-Z_]\w*\[\d+\]|\b([0-9a-fA-F]+)\b") # 0x00007fd81d4c7400 <__printf+0>:\t48 81 ec d8 00 00 00\tsub rsp,0xd8\n disassemble_output = compile( r""" From 4a4e1de6fcb3aa0cd6def268ea83e181de3c405a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 1 Jun 2024 23:53:58 +0300 Subject: [PATCH 451/487] Change variable name to UNUSED_APPIMAGE_SETTING --- PINCE.py | 6 +++--- tr/tr.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PINCE.py b/PINCE.py index 23357391..57a9daff 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2635,11 +2635,11 @@ def config_gui(self): self.lineEdit_GDBPath.setText(str(self.settings.value("Debug/gdb_path", type=str))) if os.environ.get("APPDIR"): self.label_GDBPath.setDisabled(True) - self.label_GDBPath.setToolTip(tr.APPIMAGE_SETTING_GDB) + self.label_GDBPath.setToolTip(tr.UNUSED_APPIMAGE_SETTING) self.lineEdit_GDBPath.setDisabled(True) - self.lineEdit_GDBPath.setToolTip(tr.APPIMAGE_SETTING_GDB) + self.lineEdit_GDBPath.setToolTip(tr.UNUSED_APPIMAGE_SETTING) self.pushButton_GDBPath.setDisabled(True) - self.pushButton_GDBPath.setToolTip(tr.APPIMAGE_SETTING_GDB) + self.pushButton_GDBPath.setToolTip(tr.UNUSED_APPIMAGE_SETTING) self.checkBox_GDBLogging.setChecked(self.settings.value("Debug/gdb_logging", type=bool)) self.comboBox_InterruptSignal.setCurrentText(self.settings.value("Debug/interrupt_signal", type=str)) self.checkBox_JavaSegfault.setChecked(self.settings.value("Java/ignore_segfault", type=bool)) diff --git a/tr/tr.py b/tr/tr.py index 82049e55..71350e82 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -136,7 +136,7 @@ def translate(): r"\[asdf\] --> search for opcodes that contain [asdf]" ) SEPARATE_PROCESSES_WITH = QT_TR_NOOP("Separate processes with {}") - APPIMAGE_SETTING_GDB = QT_TR_NOOP("This setting is unused in AppImage builds") + UNUSED_APPIMAGE_SETTING = QT_TR_NOOP("This setting is unused in AppImage builds") SELECT_GDB_BINARY = QT_TR_NOOP("Select the gdb binary") QUIT_SESSION_CRASH = QT_TR_NOOP("Quitting current session will crash PINCE") CONT_SESSION_CRASH = QT_TR_NOOP("Use global hotkeys or the commands 'interrupt' and 'c&' to stop/run the inferior") From 55be1841ec51cb4e4edaa9c2a055146d28708d43 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 1 Jun 2024 23:27:29 +0100 Subject: [PATCH 452/487] Fix AppImage packager mistake --- ci/package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/package.sh b/ci/package.sh index 7b237d08..39f9e8a5 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -82,7 +82,7 @@ exit_on_failure() { # containing our required pip packages export PIP_REQUIREMENTS="-r ../requirements.txt" # Need this to get libstdc++ higher than default 6.0.29 and libxcb-cursor for Debian family -export CONDA_PACKAGES="libstdcxx-ng xcb-util-cursor" +export CONDA_PACKAGES="libstdcxx-ng;xcb-util-cursor" $DEPLOYTOOL --appdir AppDir -pconda || exit_on_failure # Create PINCE directory From 9990849fd5cde82411b6a0ff9935a2806cbbfd7c Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sun, 2 Jun 2024 01:32:46 +0100 Subject: [PATCH 453/487] Fix AppImage libxcb-cursor loading --- ci/package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/package.sh b/ci/package.sh index 39f9e8a5..c5737fca 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -185,7 +185,7 @@ if [ "$(id -u)" != "0" ]; then fi export APPDIR="$(dirname "$0")" export PYTHONHOME=$APPDIR/usr/conda -$APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py +LD_LIBRARY_PATH=$PYTHONHOME/lib $APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py EOF chmod +x AppRun.sh From 013cd341eaf6ab3828ca877018977b9d532d56db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 2 Jun 2024 22:40:50 +0300 Subject: [PATCH 454/487] Fix init_user_files config file location --- libpince/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libpince/utils.py b/libpince/utils.py index cba1cfb2..daed9e18 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -1045,8 +1045,9 @@ def get_module_name(module): #:tag:Utilities def init_user_files(): """Initializes user files""" - if not os.path.exists(typedefs.USER_PATHS.ROOT): - os.makedirs(typedefs.USER_PATHS.ROOT) + root_path = get_user_path(typedefs.USER_PATHS.ROOT) + if not os.path.exists(root_path): + os.makedirs(root_path) for file in typedefs.USER_PATHS.get_init_files(): file = get_user_path(file) try: From ba0744f0e3f9e3f964a9034eacb5b53e1552532f Mon Sep 17 00:00:00 2001 From: brkzlr Date: Mon, 3 Jun 2024 18:31:19 +0100 Subject: [PATCH 455/487] Change AppImage packager to patch libqxcb.so's runpath instead of LD_LIBRARY_PATH workaround --- .github/workflows/release_appimage.yml | 2 +- ci/package.sh | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release_appimage.yml b/.github/workflows/release_appimage.yml index fc2eba80..f7f2a1bc 100644 --- a/.github/workflows/release_appimage.yml +++ b/.github/workflows/release_appimage.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Install Dependencies - run: sudo apt install libfuse2 libmpc-dev libmpfr-dev gmpc-dev appstream qt6-l10n-tools libcairo2-dev libgirepository1.0-dev + run: sudo apt install libfuse2 libmpc-dev libmpfr-dev gmpc-dev appstream qt6-l10n-tools libcairo2-dev libgirepository1.0-dev patchelf - name: Build run: | export ARCH=x86_64 diff --git a/ci/package.sh b/ci/package.sh index c5737fca..f590ce43 100755 --- a/ci/package.sh +++ b/ci/package.sh @@ -185,10 +185,13 @@ if [ "$(id -u)" != "0" ]; then fi export APPDIR="$(dirname "$0")" export PYTHONHOME=$APPDIR/usr/conda -LD_LIBRARY_PATH=$PYTHONHOME/lib $APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py +$APPDIR/usr/bin/python3 $APPDIR/opt/PINCE/PINCE.py EOF chmod +x AppRun.sh +# Patch libqxcb's runpath (not rpath) to point to our packaged libxcb-cursor to fix X11 issues +patchelf --add-rpath "\$ORIGIN/../../../../../../" AppDir/usr/conda/lib/python3.12/site-packages/PyQt6/Qt6/plugins/platforms/libqxcb.so + # Package AppDir into AppImage export LD_LIBRARY_PATH="$(readlink -f ./AppDir/usr/conda/lib)" $DEPLOYTOOL --appdir AppDir/ --output appimage --custom-apprun AppRun.sh || exit_on_failure From e54b1eb265cd645bf4d3f660e7b7c47e43c70567 Mon Sep 17 00:00:00 2001 From: OpenNetSurfer <168825895+OpenNetSurfer@users.noreply.github.com> Date: Mon, 10 Jun 2024 09:31:42 +0000 Subject: [PATCH 456/487] Added option to show the full stack from `Base Pointer` (#263) --- PINCE.py | 11 ++++++++++- i18n/ts/it_IT.ts | 5 +++++ i18n/ts/zh_CN.ts | 5 +++++ libpince/debugcore.py | 8 ++++++-- libpince/gdb_python_scripts/gdbextensions.py | 19 ++++++++++++++----- tr/tr.py | 1 + 6 files changed, 41 insertions(+), 8 deletions(-) diff --git a/PINCE.py b/PINCE.py index 57a9daff..f4f9e3b5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -2932,6 +2932,7 @@ class MemoryViewWindowForm(QMainWindow, MemoryViewWindow): show_memory_view_on_stop: bool = False instructions_per_scroll: int = 3 bytes_per_scroll: int = 0x40 + stack_from_base_pointer: bool = False def set_dynamic_debug_hotkeys(self): self.actionBreak.setText(tr.BREAK.format(hotkeys.break_hotkey.get_active_key())) @@ -3822,7 +3823,7 @@ def copy_to_clipboard(row, column): def update_stack(self): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: return - stack_info = debugcore.get_stack_info() + stack_info: list[str] = debugcore.get_stack_info(from_base_pointer=self.stack_from_base_pointer) self.tableWidget_Stack.setRowCount(0) self.tableWidget_Stack.setRowCount(len(stack_info)) for row, item in enumerate(stack_info): @@ -3832,6 +3833,10 @@ def update_stack(self): self.tableWidget_Stack.resizeColumnToContents(STACK_POINTER_ADDRESS_COL) self.tableWidget_Stack.resizeColumnToContents(STACK_VALUE_COL) + def toggle_stack_from_sp_bp(self): + self.stack_from_base_pointer = not self.stack_from_base_pointer + self.update_stack() + def tableWidget_Stack_key_press_event(self, event): if debugcore.currentpid == -1: return @@ -3875,6 +3880,9 @@ def copy_to_clipboard(row, column): current_address = utils.extract_address(current_address_text) menu = QMenu() switch_to_stacktrace = menu.addAction(tr.STACKTRACE) + toggle_stack_pointer = menu.addAction(tr.TOGGLE_STACK_FROM_SP_BP) + if debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + toggle_stack_pointer.setEnabled(False) menu.addSeparator() clipboard_menu = menu.addMenu(tr.COPY_CLIPBOARD) copy_address = clipboard_menu.addAction(tr.COPY_ADDRESS) @@ -3894,6 +3902,7 @@ def copy_to_clipboard(row, column): action = menu.exec(event.globalPos()) actions = { switch_to_stacktrace: lambda: self.set_stack_widget(self.StackTrace), + toggle_stack_pointer: self.toggle_stack_from_sp_bp, copy_address: lambda: copy_to_clipboard(selected_row, STACK_POINTER_ADDRESS_COL), copy_value: lambda: copy_to_clipboard(selected_row, STACK_VALUE_COL), copy_points_to: lambda: copy_to_clipboard(selected_row, STACK_POINTS_TO_COL), diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index c7991ad0..0e487227 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -2140,6 +2140,11 @@ Check terminal for details Stacktrace + + + Toggle stack from BP/SP register + + Copy Address diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index ea2f413d..4089bfbb 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -2172,6 +2172,11 @@ Check terminal for details Stacktrace 堆栈跟踪 + + + Toggle stack from BP/SP register + + Copy Address diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 4f9e1d42..d53017d8 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1315,8 +1315,9 @@ def get_stacktrace_info(): #:tag:Stack -def get_stack_info(): +def get_stack_info(from_base_pointer: bool = False) -> list[str]: """Returns information about current stack + Also can view stack from EBP or RBP register Returns: list: A list of str values in this format--▼ @@ -1329,7 +1330,10 @@ def get_stack_info(): if points to a symbol-->(ptr) pointer_info becomes a null string if pointer isn't valid """ - return send_command("pince-get-stack-info", recv_with_file=True) + if from_base_pointer: + return send_command("pince-get-stack-info from-base-pointer", recv_with_file=True) + else: + return send_command("pince-get-stack-info", recv_with_file=True) #:tag:Stack diff --git a/libpince/gdb_python_scripts/gdbextensions.py b/libpince/gdb_python_scripts/gdbextensions.py index d481162a..9a89444a 100644 --- a/libpince/gdb_python_scripts/gdbextensions.py +++ b/libpince/gdb_python_scripts/gdbextensions.py @@ -175,14 +175,23 @@ def invoke(self, arg, from_tty): if gdbutils.current_arch == typedefs.INFERIOR_ARCH.ARCH_64: chunk_size = 8 int_format = "Q" - sp_register = "rsp" + + if arg == "from-base-pointer": + stack_register = "rbp" + else: + stack_register = "rsp" else: chunk_size = 4 int_format = "I" - sp_register = "esp" - sp_address = gdbutils.examine_expression(f"${sp_register}").address + + if arg == "from-base-pointer": + stack_register = "ebp" + else: + stack_register = "esp" + + sp_address = gdbutils.examine_expression(f"${stack_register}").address if not sp_address: - print(f"Cannot get the value of ${sp_register}") + print(f"Cannot get the value of ${stack_register}") send_to_pince(stack_info_list) return sp_address = int(sp_address, 16) @@ -195,7 +204,7 @@ def invoke(self, arg, from_tty): return for index in range(int(4096 / chunk_size)): current_offset = chunk_size * index - stack_indicator = hex(sp_address + current_offset) + "(" + sp_register + "+" + hex(current_offset) + ")" + stack_indicator = hex(sp_address + current_offset) + "(" + stack_register + "+" + hex(current_offset) + ")" try: FILE.seek(old_position) read = FILE.read(chunk_size) diff --git a/tr/tr.py b/tr/tr.py index 71350e82..ac34af68 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -202,6 +202,7 @@ def translate(): COPY_RETURN_ADDRESS = QT_TR_NOOP("Copy Return Address") COPY_FRAME_ADDRESS = QT_TR_NOOP("Copy Frame Address") STACKTRACE = QT_TR_NOOP("Stacktrace") + TOGGLE_STACK_FROM_SP_BP = QT_TR_NOOP("Toggle stack from BP/SP register") COPY_ADDRESS = QT_TR_NOOP("Copy Address") COPY_VALUE = QT_TR_NOOP("Copy Value") COPY_POINTS_TO = QT_TR_NOOP("Copy Points to") From bd48824e9e3e092aca9d59666ceb4403f68ae116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 25 Jun 2024 22:07:59 +0300 Subject: [PATCH 457/487] Handle pexpect.EOF --- PINCE.py | 20 +++++++++----------- libpince/debugcore.py | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/PINCE.py b/PINCE.py index f4f9e3b5..b06c6753 100755 --- a/PINCE.py +++ b/PINCE.py @@ -91,7 +91,7 @@ QItemSelection, ) from time import sleep, time -import os, sys, traceback, signal, re, copy, io, queue, collections, ast, pexpect, json, select +import os, sys, traceback, signal, re, copy, io, queue, collections, ast, json, select from libpince import utils, debugcore, typedefs from libpince.libscanmem.scanmem import Scanmem @@ -477,15 +477,13 @@ def __init__(self): print("An exception occurred while loading settings, rolling back to the default configuration\n", e) self.settings.clear() self.set_default_settings() - try: - gdb_path = settings.gdb_path - if os.environ.get("APPDIR"): - gdb_path = utils.get_default_gdb_path() - debugcore.init_gdb(gdb_path) - except pexpect.EOF: - InputDialogForm(self, [(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() - else: + gdb_path = settings.gdb_path + if os.environ.get("APPDIR"): + gdb_path = utils.get_default_gdb_path() + if debugcore.init_gdb(gdb_path): self.apply_after_init() + else: + InputDialogForm(self, [(tr.GDB_INIT_ERROR, None)], buttons=[QDialogButtonBox.StandardButton.Ok]).exec() self.await_exit_thread.process_exited.connect(self.on_inferior_exit) self.await_exit_thread.start() self.check_status_thread = CheckInferiorStatus() @@ -3834,8 +3832,8 @@ def update_stack(self): self.tableWidget_Stack.resizeColumnToContents(STACK_VALUE_COL) def toggle_stack_from_sp_bp(self): - self.stack_from_base_pointer = not self.stack_from_base_pointer - self.update_stack() + self.stack_from_base_pointer = not self.stack_from_base_pointer + self.update_stack() def tableWidget_Stack_key_press_event(self, event): if debugcore.currentpid == -1: diff --git a/libpince/debugcore.py b/libpince/debugcore.py index d53017d8..7b523411 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -332,7 +332,9 @@ def check_inferior_status(): if gdb_output_mode.async_output: print(child.before) gdb_async_output.broadcast_message(child.before) - except (OSError, ValueError): + except (OSError, ValueError, pexpect.EOF) as e: + if isinstance(e, pexpect.EOF): + print("\nEOF exception caught within pexpect, here's the contents of child.before:\n" + child.before) print("Exiting state_observe_thread") @@ -496,6 +498,9 @@ def init_gdb(gdb_path=utils.get_default_gdb_path()): Args: gdb_path (str): Path of the gdb binary + Returns: + bool: True if initialization is successful, False otherwise + Note: Calling init_gdb() will reset the current session """ @@ -531,7 +536,11 @@ def init_gdb(gdb_path=utils.get_default_gdb_path()): child.setecho(False) child.delaybeforesend = 0 child.timeout = None - child.expect_exact("(gdb)") + try: + child.expect_exact("(gdb)") + except pexpect.EOF: + print("\nEOF exception caught within pexpect, here's the contents of child.before:\n" + child.before) + return False status_thread = Thread(target=state_observe_thread) status_thread.daemon = True status_thread.start() @@ -542,6 +551,7 @@ def init_gdb(gdb_path=utils.get_default_gdb_path()): set_pince_paths() send_command("source " + utils.get_user_path(typedefs.USER_PATHS.GDBINIT)) utils.execute_script(utils.get_user_path(typedefs.USER_PATHS.PINCEINIT)) + return True #:tag:GDBCommunication From adc58d738ad742c19f79c9d0c94e4b06643ded12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 17 Jul 2024 17:09:25 +0300 Subject: [PATCH 458/487] Disable word wrap for hex view --- GUI/MemoryViewerWindow.py | 1 + GUI/MemoryViewerWindow.ui | 3 +++ GUI/TableViews/HexView.py | 1 + 3 files changed, 5 insertions(+) diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index f850565f..0698ec09 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -705,6 +705,7 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_HexView_Address.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.tableWidget_HexView_Address.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_HexView_Address.setShowGrid(False) + self.tableWidget_HexView_Address.setWordWrap(False) self.tableWidget_HexView_Address.setObjectName("tableWidget_HexView_Address") self.tableWidget_HexView_Address.setColumnCount(1) self.tableWidget_HexView_Address.setRowCount(0) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 3a8c1538..7db3c098 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -1369,6 +1369,9 @@ false + + false + false diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index b4b8a46d..5e950f46 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -26,6 +26,7 @@ class QHexView(QTableView): def __init__(self, parent=None): super().__init__(parent) + self.setWordWrap(False) self.horizontalHeader().setVisible(False) self.verticalHeader().setVisible(False) self.verticalHeader().setMinimumSectionSize(21) From 924a03b283aecaaecbe2de6de6d7488cd2b14989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 18 Jul 2024 22:15:02 +0300 Subject: [PATCH 459/487] Fix misalignment and sizing issues in HexView --- GUI/TableViews/AsciiView.py | 4 ---- GUI/TableViews/HexView.py | 17 +++++++++++------ PINCE.py | 6 ++++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/GUI/TableViews/AsciiView.py b/GUI/TableViews/AsciiView.py index 291c58bc..fd572c13 100644 --- a/GUI/TableViews/AsciiView.py +++ b/GUI/TableViews/AsciiView.py @@ -23,10 +23,6 @@ class QAsciiView(QHexView): def __init__(self, parent=None): super().__init__(parent) - # 12 is minimum size with current font, otherwise it will be cut off - self.horizontalHeader().setMinimumSectionSize(12) - self.horizontalHeader().setDefaultSectionSize(12) - self.horizontalHeader().setMaximumSectionSize(12) self.write_type = typedefs.VALUE_INDEX.STRING_UTF8 self.delegate = QHexDelegate(1, ".+") self.delegate.closeEditor.connect(self.on_editor_close) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index 5e950f46..6edbd116 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -29,12 +29,6 @@ def __init__(self, parent=None): self.setWordWrap(False) self.horizontalHeader().setVisible(False) self.verticalHeader().setVisible(False) - self.verticalHeader().setMinimumSectionSize(21) - self.verticalHeader().setDefaultSectionSize(21) - self.verticalHeader().setMaximumSectionSize(21) - self.horizontalHeader().setMinimumSectionSize(25) - self.horizontalHeader().setDefaultSectionSize(25) - self.horizontalHeader().setMaximumSectionSize(25) self.setStyleSheet("QTableView {background-color: transparent;}") self.setShowGrid(False) self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked) @@ -46,6 +40,17 @@ def __init__(self, parent=None): self.delegate.closeEditor.connect(self.on_editor_close) self.setItemDelegate(self.delegate) + def adjust_cell_size(self, char_count: int): + font_metrics = self.fontMetrics() + col_width = font_metrics.horizontalAdvance("F" * char_count) + 4 * char_count + row_height = font_metrics.height() + self.horizontalHeader().setMinimumSectionSize(col_width) + self.horizontalHeader().setDefaultSectionSize(col_width) + self.horizontalHeader().setMaximumSectionSize(col_width) + self.verticalHeader().setMinimumSectionSize(row_height) + self.verticalHeader().setDefaultSectionSize(row_height) + self.verticalHeader().setMaximumSectionSize(row_height) + def wheelEvent(self, event: QWheelEvent): event.ignore() diff --git a/PINCE.py b/PINCE.py index b06c6753..abf3553e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3073,6 +3073,9 @@ def initialize_hex_view(self): self.ascii_model = QAsciiModel(HEX_VIEW_ROW_COUNT, HEX_VIEW_COL_COUNT) self.tableView_HexView_Hex.setModel(self.hex_model) self.tableView_HexView_Ascii.setModel(self.ascii_model) + # Adjust cell sizes after setting model to ensure correct size + self.tableView_HexView_Hex.adjust_cell_size(2) + self.tableView_HexView_Ascii.adjust_cell_size(1) self.widget_HexView.wheelEvent = self.widget_HexView_wheel_event # Saving the original function because super() doesn't work when we override functions like this @@ -3099,6 +3102,9 @@ def initialize_hex_view(self): self.scrollArea_Hex.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_HexView_Address.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_HexView_Address.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.tableWidget_HexView_Address.verticalHeader().setMinimumSectionSize( + self.tableView_HexView_Hex.verticalHeader().minimumSectionSize() + ) self.tableWidget_HexView_Address.verticalHeader().setDefaultSectionSize( self.tableView_HexView_Hex.verticalHeader().defaultSectionSize() ) From d8af858fd5ba1837e2eddfe6466bb2f03e79b0e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 19 Jul 2024 13:38:08 +0300 Subject: [PATCH 460/487] Fix upper case write bug for AsciiView --- GUI/TableViews/HexView.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GUI/TableViews/HexView.py b/GUI/TableViews/HexView.py index 6edbd116..fedc9ec9 100644 --- a/GUI/TableViews/HexView.py +++ b/GUI/TableViews/HexView.py @@ -79,6 +79,8 @@ def on_editor_close(self): cell = self.currentIndex() index = cell.row() * model.columnCount() + cell.column() address = utils.modulo_address(model.current_address + index, debugcore.inferior_arch) - data = self.delegate.editor.text().upper() + data = self.delegate.editor.text() + if self.write_type == typedefs.VALUE_INDEX.AOB: + data = data.upper() debugcore.write_memory(address, self.write_type, data, False) model.update_index(index, data) From 39a42b27061f541a832c5344e71ce39c6ca31c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 19 Jul 2024 17:19:12 +0300 Subject: [PATCH 461/487] Enable sorting for address table --- GUI/MainWindow.py | 3 ++- GUI/MainWindow.ui | 5 ++++- PINCE.py | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 68ba25b1..8fa76457 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -271,7 +271,7 @@ def setupUi(self, MainWindow): self.gridLayout.addLayout(self.horizontalLayout_9, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(parent=MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 22)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 678, 23)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) @@ -280,6 +280,7 @@ def setupUi(self, MainWindow): def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate + self.treeWidget_AddressTable.setSortingEnabled(True) self.treeWidget_AddressTable.headerItem().setText(0, _translate("MainWindow", "Freeze")) self.treeWidget_AddressTable.headerItem().setToolTip(0, _translate("MainWindow", "Freeze the value")) self.treeWidget_AddressTable.headerItem().setText(1, _translate("MainWindow", "Description")) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 5582b4ea..f5475fb5 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -32,6 +32,9 @@ 12 + + true + false @@ -613,7 +616,7 @@ 0 0 678 - 22 + 23 diff --git a/PINCE.py b/PINCE.py index abf3553e..9d81289b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -548,6 +548,7 @@ def __init__(self): self.treeWidget_AddressTable.itemDoubleClicked.connect(self.treeWidget_AddressTable_item_double_clicked) self.treeWidget_AddressTable.expanded.connect(self.resize_address_table) self.treeWidget_AddressTable.collapsed.connect(self.resize_address_table) + self.treeWidget_AddressTable.header().setSortIndicatorClearable(True) icons_directory = guiutils.get_icons_directory() self.pushButton_AttachProcess.setIcon(QIcon(QPixmap(icons_directory + "/monitor.png"))) self.pushButton_Open.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) From f819edfcd3f5a432df17eece19066be699444798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 20 Jul 2024 15:40:38 +0300 Subject: [PATCH 462/487] Remove unused bits radiobutton --- GUI/MainWindow.py | 27 +++--------------------- GUI/MainWindow.ui | 53 +++-------------------------------------------- i18n/ts/it_IT.ts | 10 --------- i18n/ts/zh_CN.ts | 10 --------- 4 files changed, 6 insertions(+), 94 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 8fa76457..cb39340a 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -174,30 +174,11 @@ def setupUi(self, MainWindow): self.widget_Scan = QtWidgets.QWidget(parent=self.QWidget_Toolbox) self.widget_Scan.setObjectName("widget_Scan") self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.widget_Scan) - self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_7.setContentsMargins(0, -1, 0, 0) self.horizontalLayout_7.setObjectName("horizontalLayout_7") - self.widget_3 = QtWidgets.QWidget(parent=self.widget_Scan) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.widget_3.sizePolicy().hasHeightForWidth()) - self.widget_3.setSizePolicy(sizePolicy) - self.widget_3.setObjectName("widget_3") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget_3) - self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_2.setSpacing(0) - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.radioButton_Bits = QtWidgets.QRadioButton(parent=self.widget_3) - self.radioButton_Bits.setObjectName("radioButton_Bits") - self.verticalLayout_2.addWidget(self.radioButton_Bits) - self.radioButton_Decimal = QtWidgets.QRadioButton(parent=self.widget_3) - self.radioButton_Decimal.setChecked(True) - self.radioButton_Decimal.setObjectName("radioButton_Decimal") - self.verticalLayout_2.addWidget(self.radioButton_Decimal) - self.checkBox_Hex = QtWidgets.QCheckBox(parent=self.widget_3) + self.checkBox_Hex = QtWidgets.QCheckBox(parent=self.widget_Scan) self.checkBox_Hex.setObjectName("checkBox_Hex") - self.verticalLayout_2.addWidget(self.checkBox_Hex) - self.horizontalLayout_7.addWidget(self.widget_3) + self.horizontalLayout_7.addWidget(self.checkBox_Hex) self.lineEdit_Scan = QtWidgets.QLineEdit(parent=self.widget_Scan) self.lineEdit_Scan.setObjectName("lineEdit_Scan") self.horizontalLayout_7.addWidget(self.lineEdit_Scan) @@ -310,8 +291,6 @@ def retranslateUi(self, MainWindow): self.pushButton_NewFirstScan.setText(_translate("MainWindow", "First Scan")) self.pushButton_NextScan.setText(_translate("MainWindow", "Next Scan")) self.pushButton_UndoScan.setText(_translate("MainWindow", "Undo Scan")) - self.radioButton_Bits.setText(_translate("MainWindow", "B&its")) - self.radioButton_Decimal.setText(_translate("MainWindow", "&Decimal")) self.checkBox_Hex.setText(_translate("MainWindow", "Hex")) self.label.setText(_translate("MainWindow", "Scan Type:")) self.label_2.setText(_translate("MainWindow", "Value Type:")) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index f5475fb5..0be8dca7 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -410,9 +410,6 @@ 0 - - 0 - 0 @@ -420,54 +417,10 @@ 0 - - - - 0 - 0 - + + + Hex - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - B&its - - - - - - - &Decimal - - - true - - - - - - - Hex - - - - diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 0e487227..fd39b650 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -963,16 +963,6 @@ Patterns at former positions have higher priority if regex is off Undo Scan - - - B&its - - - - - &Decimal - &Decimale - Hex diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 4089bfbb..7f808eeb 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -965,16 +965,6 @@ Patterns at former positions have higher priority if regex is off Undo Scan 撤销扫描 - - - B&its - 比特[&i] - - - - &Decimal - 数字[&D] - Hex From 0bcce05c56d666064693b2f2a6252969c1d4e7f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 22 Jul 2024 14:22:28 +0300 Subject: [PATCH 463/487] Migrate to Sphinx (#265) --- .github/workflows/build_docs.yml | 46 ++++++++++++++++++++++++++++++++ .gitignore | 1 + docs/Makefile | 20 ++++++++++++++ docs/build_html.sh | 3 +++ docs/install_sphinx.sh | 3 +++ docs/source/conf.py | 38 ++++++++++++++++++++++++++ docs/source/index.rst | 19 +++++++++++++ docs/source/libpince.rst | 45 +++++++++++++++++++++++++++++++ docs/source/modules.rst | 7 +++++ libpince/debugcore.py | 10 ++++--- 10 files changed, 188 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/build_docs.yml create mode 100644 docs/Makefile create mode 100755 docs/build_html.sh create mode 100755 docs/install_sphinx.sh create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst create mode 100644 docs/source/libpince.rst create mode 100644 docs/source/modules.rst diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml new file mode 100644 index 00000000..d6135df4 --- /dev/null +++ b/.github/workflows/build_docs.yml @@ -0,0 +1,46 @@ +name: Deploy Sphinx Docs to GitHub Pages + +on: + push: + tags: + - "v*.*" + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + sudo apt install libgirepository1.0-dev + python3 -m venv .venv/PINCE + . .venv/PINCE/bin/activate + pip3 install --upgrade pip + pip3 install -r requirements.txt + + - name: Install Sphinx + run: | + cd docs + ./install_sphinx.sh + + - name: Build docs + run: | + cd docs + ./build_html.sh + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/build/html + publish_branch: gh-pages + force_orphan: true + keep_files: false diff --git a/.gitignore b/.gitignore index dbd87125..1e453ceb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ __pycache__/ !.vscode/settings.json libpince/libscanmem/* libpince/libptrscan/* +docs/build/* *.directory *.lprof *.qm diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/build_html.sh b/docs/build_html.sh new file mode 100755 index 00000000..e5b8c739 --- /dev/null +++ b/docs/build_html.sh @@ -0,0 +1,3 @@ +. ../.venv/PINCE/bin/activate +make clean +make html diff --git a/docs/install_sphinx.sh b/docs/install_sphinx.sh new file mode 100755 index 00000000..59456245 --- /dev/null +++ b/docs/install_sphinx.sh @@ -0,0 +1,3 @@ +. ../.venv/PINCE/bin/activate +pip install sphinx +pip install sphinx-autodoc-typehints diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..14164f62 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,38 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +import os +import sys + +sys.path.insert(0, os.path.abspath(os.path.join("..", ".."))) + +project = "PINCE" +copyright = "2024, PINCE Contributors" +author = "PINCE Contributors" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "sphinx.ext.intersphinx", + "sphinx_autodoc_typehints", +] + +templates_path = ["_templates"] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "alabaster" +html_static_path = ["_static"] diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..37ff02b7 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,19 @@ +.. PINCE documentation master file, created by sphinx-quickstart + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to PINCE's documentation! +================================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + modules + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/libpince.rst b/docs/source/libpince.rst new file mode 100644 index 00000000..74b57ad6 --- /dev/null +++ b/docs/source/libpince.rst @@ -0,0 +1,45 @@ +libpince package +================ + +Submodules +---------- + +libpince.debugcore module +------------------------- + +.. automodule:: libpince.debugcore + :members: + :undoc-members: + :show-inheritance: + +libpince.regexes module +----------------------- + +.. automodule:: libpince.regexes + :members: + :undoc-members: + :show-inheritance: + +libpince.typedefs module +------------------------ + +.. automodule:: libpince.typedefs + :members: + :undoc-members: + :show-inheritance: + +libpince.utils module +--------------------- + +.. automodule:: libpince.utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: libpince + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 00000000..185c8b0f --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,7 @@ +libpince +======== + +.. toctree:: + :maxdepth: 4 + + libpince diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 7b523411..413421b5 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1087,9 +1087,10 @@ def parse_and_eval(expression, cast=str): Use examine_expression if your data can be expressed as an address or a symbol, use this function otherwise Unlike examine_expression, this function can read data that has void type or multiple type representations For instance: - $eflags has both str and int reprs - $_siginfo is a struct with many fields - x64 register convenience vars such as $rax are void if the process is x86 + + - $eflags has both str and int reprs + - $_siginfo is a struct with many fields + - x64 register convenience vars such as $rax are void if the process is x86 Args: expression (str): Any gdb expression @@ -1366,7 +1367,8 @@ def get_stack_frame_info(index): index (int,str): Index of the frame Returns: - str: Information that looks like this--▼ + str: Information that looks like this:: + Stack level 0, frame at 0x7ffc5f87f6a0: rip = 0x7fd1d639412d in poll (../sysdeps/unix/syscall-template.S:81); saved rip = 0x7fd1d27fcfe4 called by frame at 0x7ffc5f87f700 From 8173a56216749a2d47bdc52618be05378721cb6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Mon, 22 Jul 2024 14:33:20 +0300 Subject: [PATCH 464/487] Add workflow_dispatch to build_docs --- .github/workflows/build_docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index d6135df4..f2614a43 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -4,6 +4,7 @@ on: push: tags: - "v*.*" + workflow_dispatch: jobs: deploy: From af3951caaf6ab9c00694ebf6e6b9873946b88eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 23 Jul 2024 13:16:42 +0300 Subject: [PATCH 465/487] Remove LibpinceReferenceWidget and tagging system --- GUI/LibpinceReferenceWidget.py | 161 ------------------ GUI/LibpinceReferenceWidget.ui | 292 --------------------------------- GUI/Utils/guiutils.py | 15 -- PINCE.py | 249 +--------------------------- i18n/ts/it_IT.ts | 50 +----- i18n/ts/zh_CN.ts | 50 +----- libpince/debugcore.py | 109 ------------ libpince/utils.py | 228 ------------------------- 8 files changed, 13 insertions(+), 1141 deletions(-) delete mode 100644 GUI/LibpinceReferenceWidget.py delete mode 100644 GUI/LibpinceReferenceWidget.ui diff --git a/GUI/LibpinceReferenceWidget.py b/GUI/LibpinceReferenceWidget.py deleted file mode 100644 index e3048e40..00000000 --- a/GUI/LibpinceReferenceWidget.py +++ /dev/null @@ -1,161 +0,0 @@ -# Form implementation generated from reading ui file 'LibpinceReferenceWidget.ui' -# -# Created by: PyQt6 UI code generator 6.5.1 -# -# WARNING: Any manual changes made to this file will be lost when pyuic6 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt6 import QtCore, QtGui, QtWidgets - - -class Ui_Form(object): - def setupUi(self, Form): - Form.setObjectName("Form") - Form.resize(887, 569) - self.gridLayout_2 = QtWidgets.QGridLayout(Form) - self.gridLayout_2.setContentsMargins(0, 0, 0, 0) - self.gridLayout_2.setSpacing(0) - self.gridLayout_2.setObjectName("gridLayout_2") - self.splitter = QtWidgets.QSplitter(parent=Form) - self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal) - self.splitter.setHandleWidth(10) - self.splitter.setObjectName("splitter") - self.widget_TypeDefs = QtWidgets.QWidget(parent=self.splitter) - self.widget_TypeDefs.setObjectName("widget_TypeDefs") - self.gridLayout = QtWidgets.QGridLayout(self.widget_TypeDefs) - self.gridLayout.setContentsMargins(0, 0, 0, 0) - self.gridLayout.setObjectName("gridLayout") - self.horizontalLayout_4 = QtWidgets.QHBoxLayout() - self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.label_5 = QtWidgets.QLabel(parent=self.widget_TypeDefs) - self.label_5.setObjectName("label_5") - self.horizontalLayout_4.addWidget(self.label_5) - self.line = QtWidgets.QFrame(parent=self.widget_TypeDefs) - self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line.setObjectName("line") - self.horizontalLayout_4.addWidget(self.line) - self.label_3 = QtWidgets.QLabel(parent=self.widget_TypeDefs) - self.label_3.setObjectName("label_3") - self.horizontalLayout_4.addWidget(self.label_3) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_4.addItem(spacerItem) - self.gridLayout.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) - self.horizontalLayout_2 = QtWidgets.QHBoxLayout() - self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.lineEdit_SearchText = QtWidgets.QLineEdit(parent=self.widget_TypeDefs) - self.lineEdit_SearchText.setObjectName("lineEdit_SearchText") - self.horizontalLayout_2.addWidget(self.lineEdit_SearchText) - self.pushButton_TextUp = QtWidgets.QPushButton(parent=self.widget_TypeDefs) - self.pushButton_TextUp.setText("") - self.pushButton_TextUp.setObjectName("pushButton_TextUp") - self.horizontalLayout_2.addWidget(self.pushButton_TextUp) - self.pushButton_TextDown = QtWidgets.QPushButton(parent=self.widget_TypeDefs) - self.pushButton_TextDown.setText("") - self.pushButton_TextDown.setObjectName("pushButton_TextDown") - self.horizontalLayout_2.addWidget(self.pushButton_TextDown) - self.label_FoundCount = QtWidgets.QLabel(parent=self.widget_TypeDefs) - self.label_FoundCount.setText("0/0") - self.label_FoundCount.setObjectName("label_FoundCount") - self.horizontalLayout_2.addWidget(self.label_FoundCount) - self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1) - self.textBrowser_TypeDefs = QtWidgets.QTextBrowser(parent=self.widget_TypeDefs) - self.textBrowser_TypeDefs.setObjectName("textBrowser_TypeDefs") - self.gridLayout.addWidget(self.textBrowser_TypeDefs, 2, 0, 1, 1) - self.widget_Resources = QtWidgets.QWidget(parent=self.splitter) - self.widget_Resources.setObjectName("widget_Resources") - self.gridLayout_3 = QtWidgets.QGridLayout(self.widget_Resources) - self.gridLayout_3.setContentsMargins(0, 0, 0, 0) - self.gridLayout_3.setObjectName("gridLayout_3") - self.stackedWidget_Resources = QtWidgets.QStackedWidget(parent=self.widget_Resources) - self.stackedWidget_Resources.setObjectName("stackedWidget_Resources") - self.page = QtWidgets.QWidget() - self.page.setObjectName("page") - self.gridLayout_4 = QtWidgets.QGridLayout(self.page) - self.gridLayout_4.setContentsMargins(0, 0, 0, 0) - self.gridLayout_4.setSpacing(0) - self.gridLayout_4.setObjectName("gridLayout_4") - self.treeWidget_ResourceTree = QtWidgets.QTreeWidget(parent=self.page) - self.treeWidget_ResourceTree.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) - self.treeWidget_ResourceTree.setObjectName("treeWidget_ResourceTree") - self.treeWidget_ResourceTree.headerItem().setText(0, "Item Name") - self.gridLayout_4.addWidget(self.treeWidget_ResourceTree, 0, 0, 1, 1) - self.stackedWidget_Resources.addWidget(self.page) - self.page_2 = QtWidgets.QWidget() - self.page_2.setObjectName("page_2") - self.gridLayout_5 = QtWidgets.QGridLayout(self.page_2) - self.gridLayout_5.setContentsMargins(0, 0, 0, 0) - self.gridLayout_5.setSpacing(0) - self.gridLayout_5.setObjectName("gridLayout_5") - self.tableWidget_ResourceTable = QtWidgets.QTableWidget(parent=self.page_2) - self.tableWidget_ResourceTable.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) - self.tableWidget_ResourceTable.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection) - self.tableWidget_ResourceTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) - self.tableWidget_ResourceTable.setObjectName("tableWidget_ResourceTable") - self.tableWidget_ResourceTable.setColumnCount(2) - self.tableWidget_ResourceTable.setRowCount(0) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_ResourceTable.setHorizontalHeaderItem(0, item) - item = QtWidgets.QTableWidgetItem() - self.tableWidget_ResourceTable.setHorizontalHeaderItem(1, item) - self.tableWidget_ResourceTable.horizontalHeader().setStretchLastSection(True) - self.tableWidget_ResourceTable.verticalHeader().setVisible(False) - self.tableWidget_ResourceTable.verticalHeader().setDefaultSectionSize(16) - self.tableWidget_ResourceTable.verticalHeader().setMinimumSectionSize(16) - self.gridLayout_5.addWidget(self.tableWidget_ResourceTable, 0, 0, 1, 1) - self.stackedWidget_Resources.addWidget(self.page_2) - self.gridLayout_3.addWidget(self.stackedWidget_Resources, 2, 0, 1, 1) - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - self.verticalLayout_2 = QtWidgets.QVBoxLayout() - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.label_4 = QtWidgets.QLabel(parent=self.widget_Resources) - self.label_4.setObjectName("label_4") - self.verticalLayout_2.addWidget(self.label_4) - self.lineEdit_Search = QtWidgets.QLineEdit(parent=self.widget_Resources) - self.lineEdit_Search.setObjectName("lineEdit_Search") - self.verticalLayout_2.addWidget(self.lineEdit_Search) - self.horizontalLayout.addLayout(self.verticalLayout_2) - self.verticalLayout = QtWidgets.QVBoxLayout() - self.verticalLayout.setObjectName("verticalLayout") - self.label = QtWidgets.QLabel(parent=self.widget_Resources) - self.label.setObjectName("label") - self.verticalLayout.addWidget(self.label) - self.comboBox_SourceFile = QtWidgets.QComboBox(parent=self.widget_Resources) - self.comboBox_SourceFile.setObjectName("comboBox_SourceFile") - self.verticalLayout.addWidget(self.comboBox_SourceFile) - self.horizontalLayout.addLayout(self.verticalLayout) - self.gridLayout_3.addLayout(self.horizontalLayout, 0, 0, 1, 1) - self.horizontalLayout_3 = QtWidgets.QHBoxLayout() - self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.label_2 = QtWidgets.QLabel(parent=self.widget_Resources) - self.label_2.setObjectName("label_2") - self.horizontalLayout_3.addWidget(self.label_2) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_3.addItem(spacerItem1) - self.pushButton_ShowTypeDefs = QtWidgets.QPushButton(parent=self.widget_Resources) - self.pushButton_ShowTypeDefs.setObjectName("pushButton_ShowTypeDefs") - self.horizontalLayout_3.addWidget(self.pushButton_ShowTypeDefs) - self.gridLayout_3.addLayout(self.horizontalLayout_3, 1, 0, 1, 1) - self.gridLayout_2.addWidget(self.splitter, 0, 0, 1, 1) - - self.retranslateUi(Form) - self.stackedWidget_Resources.setCurrentIndex(0) - QtCore.QMetaObject.connectSlotsByName(Form) - - def retranslateUi(self, Form): - _translate = QtCore.QCoreApplication.translate - Form.setWindowTitle(_translate("Form", "libpince Reference")) - self.label_5.setText(_translate("Form", "Search")) - self.label_3.setText(_translate("Form", "typedefs(Type Definitions)")) - self.treeWidget_ResourceTree.headerItem().setText(1, _translate("Form", "Value")) - self.tableWidget_ResourceTable.setSortingEnabled(True) - item = self.tableWidget_ResourceTable.horizontalHeaderItem(0) - item.setText(_translate("Form", "Item Name")) - item = self.tableWidget_ResourceTable.horizontalHeaderItem(1) - item.setText(_translate("Form", "Value")) - self.label_4.setText(_translate("Form", "Search")) - self.label.setText(_translate("Form", "Source File")) - self.label_2.setText(_translate("Form", "Resources(Mouse-over items to see docstrings)")) - self.pushButton_ShowTypeDefs.setText(_translate("Form", "Hide typedefs")) diff --git a/GUI/LibpinceReferenceWidget.ui b/GUI/LibpinceReferenceWidget.ui deleted file mode 100644 index 60275013..00000000 --- a/GUI/LibpinceReferenceWidget.ui +++ /dev/null @@ -1,292 +0,0 @@ - - - Form - - - - 0 - 0 - 887 - 569 - - - - libpince Reference - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - 10 - - - - - 0 - - - - - - - Search - - - - - - - Qt::Vertical - - - - - - - typedefs(Type Definitions) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0/0 - - - - - - - - - - - - - - 0 - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::NoEditTriggers - - - - Item Name - - - - - Value - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - true - - - true - - - false - - - 16 - - - 16 - - - - Item Name - - - - - Value - - - - - - - - - - - - - - - - Search - - - - - - - - - - - - - - Source File - - - - - - - - - - - - - - - - Resources(Mouse-over items to see docstrings) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Hide typedefs - - - - - - - - - - - - - - diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index 4a40ab58..b3b619dd 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -21,7 +21,6 @@ from libpince import utils, typedefs, regexes from tr.tr import TranslationConstants as tr -#:tag:GUI validator_map: dict[str, QRegularExpressionValidator | None] = { "int": QRegularExpressionValidator(QRegularExpression(regexes.decimal_number.pattern)), # integers "int_hex": QRegularExpressionValidator(QRegularExpression(regexes.hex_number_gui.pattern)), # hexadecimals @@ -31,7 +30,6 @@ } -#:tag:GUI def get_icons_directory(): """Gets the directory of the icons @@ -41,7 +39,6 @@ def get_icons_directory(): return utils.get_script_directory() + "/media/icons" -#:tag:GUI def center(window: QWidget): """Center the given window to desktop @@ -51,7 +48,6 @@ def center(window: QWidget): window.frameGeometry().moveCenter(window.screen().availableGeometry().center()) -#:tag:GUI def center_to_parent(window: QWidget): """Center the given window to its parent @@ -62,7 +58,6 @@ def center_to_parent(window: QWidget): window.move(parent.frameGeometry().center() - window.rect().center()) -#:tag:GUI def center_scroll_bar(scrollbar: QScrollBar): """Center the given scrollbar @@ -74,7 +69,6 @@ def center_scroll_bar(scrollbar: QScrollBar): scrollbar.setValue((maximum + minimum) // 2) -#:tag:GUI def resize_to_contents(tablewidget: QTableWidget): """Resizes the columns of the given QTableWidget to its contents This also fixes the stretch problem of the last column @@ -87,7 +81,6 @@ def resize_to_contents(tablewidget: QTableWidget): tablewidget.horizontalHeader().resizeSection(tablewidget.columnCount() - 1, default_size) -#:tag:GUI def fill_value_combobox(combobox: QComboBox, current_index: int = typedefs.VALUE_INDEX.INT32): """Fills the given QComboBox with value_index strings @@ -100,7 +93,6 @@ def fill_value_combobox(combobox: QComboBox, current_index: int = typedefs.VALUE combobox.setCurrentIndex(current_index) -#:tag:GUI def fill_endianness_combobox(combobox: QComboBox, current_index: int = typedefs.ENDIANNESS.HOST): """Fills the given QComboBox with endianness strings @@ -118,7 +110,6 @@ def fill_endianness_combobox(combobox: QComboBox, current_index: int = typedefs. combobox.setCurrentIndex(current_index) -#:tag:GUI def get_current_row(tablewidget: QTableWidget): r"""Returns the currently selected row index for the given QTableWidget If you try to use only selectionModel().currentIndex().row() for this purpose, you'll get the last selected row even @@ -144,7 +135,6 @@ def get_current_row(tablewidget: QTableWidget): return -1 -#:tag:GUI def get_current_item(tablewidget: QTableWidget): r"""Returns the currently selected item for the given QTableWidget If you try to use only selectionModel().currentItem() for this purpose, you'll get the last selected item even @@ -169,7 +159,6 @@ def get_current_item(tablewidget: QTableWidget): return tablewidget.currentItem() -#:tag:GUI def delete_menu_entries(menu: QMenu, QAction_list: list): """Deletes given QActions from the QMenu recursively and cleans up the remaining redundant separators and menus Doesn't support menus that includes types other than actions, separators and menus @@ -206,7 +195,6 @@ def clean_entries(menu: QMenu): # TODO: This is a really bad design pattern, remove this function after moving classes to their own files -#:tag:GUI def search_parents_by_function(qt_object: QObject, func_name: str): """Search for func_name in the parents of given QObject. Once function is found, parent that possesses func_name is returned @@ -221,7 +209,6 @@ def search_parents_by_function(qt_object: QObject, func_name: str): return qt_object -#:tag:GUI def get_layout_widgets(layout: QLayout): """Returns the widgets of a QLayout as a list @@ -234,7 +221,6 @@ def get_layout_widgets(layout: QLayout): return [layout.itemAt(x).widget() for x in range(layout.count())] -#:tag:GUI def contains_reference_mark(string: str): """Checks if given string contains the reference mark @@ -247,7 +233,6 @@ def contains_reference_mark(string: str): return True if regexes.reference_mark.search(string) else False -#:tag:GUI def append_shortcut_to_tooltip(qt_object: QObject, shortcut: QShortcut): """Appends key string of the given QShortcut to the toolTip of the given QObject diff --git a/PINCE.py b/PINCE.py index 9d81289b..4352a4fc 100755 --- a/PINCE.py +++ b/PINCE.py @@ -127,7 +127,6 @@ from GUI.FunctionsInfoWidget import Ui_Form as FunctionsInfoWidget from GUI.HexEditDialog import Ui_Dialog as HexEditDialog from GUI.EditInstructionDialog import Ui_Dialog as EditInstructionDialog -from GUI.LibpinceReferenceWidget import Ui_Form as LibpinceReferenceWidget from GUI.LogFileWidget import Ui_Form as LogFileWidget from GUI.SearchOpcodeWidget import Ui_Form as SearchOpcodeWidget from GUI.MemoryRegionsWidget import Ui_Form as MemoryRegionsWidget @@ -1339,7 +1338,6 @@ def comboBox_ValueType_init(self): self.comboBox_ValueType.setCurrentIndex(typedefs.SCAN_INDEX.INT32) self.comboBox_ValueType_current_index_changed() - # :doc: # adds things like 0x when searching for etc, basically just makes the line valid for scanmem # this should cover most things, more things might be added later if need be def validate_search(self, search_for: str, search_for2: str): @@ -4419,8 +4417,7 @@ def actionDissect_Code_triggered(self): self.refresh_disassemble_view() def actionlibpince_triggered(self): - libpince_widget = LibpinceReferenceWidgetForm(self) - libpince_widget.showMaximized() + utils.execute_command_as_user('python3 -m webbrowser "https://korcankaraokcu.github.io/PINCE/"') def pushButton_ShowFloatRegisters_clicked(self): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: @@ -5420,250 +5417,6 @@ def accept(self): super().accept() -# This widget will be replaced with auto-generated documentation in the future, no need to translate -class LibpinceReferenceWidgetForm(QWidget, LibpinceReferenceWidget): - def convert_to_modules(self, module_strings): - return [eval(item) for item in module_strings] - - def __init__(self, parent): - super().__init__(parent) - self.setupUi(self) - self.found_count = 0 - self.current_found = 0 - self.setWindowFlags(Qt.WindowType.Window) - self.show_typedefs() - self.splitter.setStretchFactor(0, 1) - self.widget_Resources.resize(700, self.widget_Resources.height()) - libpince_directory = utils.get_libpince_directory() - self.textBrowser_TypeDefs.setText(open(libpince_directory + "/typedefs.py").read()) - source_menu_items = ["(Tagged only)", "(All)"] - self.source_files = ["debugcore", "utils", "guiutils"] - source_menu_items.extend(self.source_files) - self.comboBox_SourceFile.addItems(source_menu_items) - self.comboBox_SourceFile.setCurrentIndex(0) - self.fill_resource_tree() - icons_directory = guiutils.get_icons_directory() - self.pushButton_TextUp.setIcon(QIcon(QPixmap(icons_directory + "/bullet_arrow_up.png"))) - self.pushButton_TextDown.setIcon(QIcon(QPixmap(icons_directory + "/bullet_arrow_down.png"))) - self.comboBox_SourceFile.currentIndexChanged.connect(self.comboBox_SourceFile_current_index_changed) - self.pushButton_ShowTypeDefs.clicked.connect(self.toggle_typedefs) - self.lineEdit_SearchText.textChanged.connect(self.highlight_text) - self.pushButton_TextDown.clicked.connect(self.pushButton_TextDown_clicked) - self.pushButton_TextUp.clicked.connect(self.pushButton_TextUp_clicked) - self.lineEdit_Search.textChanged.connect(self.comboBox_SourceFile_current_index_changed) - self.tableWidget_ResourceTable.contextMenuEvent = self.tableWidget_ResourceTable_context_menu_event - self.treeWidget_ResourceTree.contextMenuEvent = self.treeWidget_ResourceTree_context_menu_event - self.treeWidget_ResourceTree.expanded.connect(self.resize_resource_tree) - self.treeWidget_ResourceTree.collapsed.connect(self.resize_resource_tree) - guiutils.center_to_parent(self) - - def tableWidget_ResourceTable_context_menu_event(self, event): - def copy_to_clipboard(row, column): - app.clipboard().setText(self.tableWidget_ResourceTable.item(row, column).text()) - - selected_row = guiutils.get_current_row(self.tableWidget_ResourceTable) - - menu = QMenu() - refresh = menu.addAction("Refresh") - menu.addSeparator() - copy_item = menu.addAction("Copy Item") - copy_value = menu.addAction("Copy Value") - if selected_row == -1: - guiutils.delete_menu_entries(menu, [copy_item, copy_value]) - font_size = self.tableWidget_ResourceTable.font().pointSize() - menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec(event.globalPos()) - actions = { - refresh: self.fill_resource_table, - copy_item: lambda: copy_to_clipboard(selected_row, LIBPINCE_REFERENCE_ITEM_COL), - copy_value: lambda: copy_to_clipboard(selected_row, LIBPINCE_REFERENCE_VALUE_COL), - } - try: - actions[action]() - except KeyError: - pass - - def treeWidget_ResourceTree_context_menu_event(self, event): - def copy_to_clipboard(column): - current_item = guiutils.get_current_item(self.treeWidget_ResourceTree) - if current_item: - app.clipboard().setText(current_item.text(column)) - - def expand_all(): - self.treeWidget_ResourceTree.expandAll() - self.resize_resource_tree() - - def collapse_all(): - self.treeWidget_ResourceTree.collapseAll() - self.resize_resource_tree() - - selected_row = guiutils.get_current_row(self.treeWidget_ResourceTree) - - menu = QMenu() - refresh = menu.addAction("Refresh") - menu.addSeparator() - copy_item = menu.addAction("Copy Item") - copy_value = menu.addAction("Copy Value") - if selected_row == -1: - guiutils.delete_menu_entries(menu, [copy_item, copy_value]) - menu.addSeparator() - expand_all_items = menu.addAction("Expand All") - collapse_all_items = menu.addAction("Collapse All") - font_size = self.treeWidget_ResourceTree.font().pointSize() - menu.setStyleSheet("font-size: " + str(font_size) + "pt;") - action = menu.exec(event.globalPos()) - actions = { - refresh: self.fill_resource_tree, - copy_item: lambda: copy_to_clipboard(LIBPINCE_REFERENCE_ITEM_COL), - copy_value: lambda: copy_to_clipboard(LIBPINCE_REFERENCE_VALUE_COL), - expand_all_items: expand_all, - collapse_all_items: collapse_all, - } - - # Thanks QT, for this unexplainable, mind blowing bug of yours - self.treeWidget_ResourceTree.blockSignals(True) - try: - actions[action]() - except KeyError: - pass - self.treeWidget_ResourceTree.blockSignals(False) - - def comboBox_SourceFile_current_index_changed(self): - if self.comboBox_SourceFile.currentIndex() == 0: # (Tagged only) - self.fill_resource_tree() - else: - self.fill_resource_table() - - def resize_resource_tree(self): - self.treeWidget_ResourceTree.resizeColumnToContents(LIBPINCE_REFERENCE_ITEM_COL) - - def fill_resource_tree(self): - self.treeWidget_ResourceTree.setStyleSheet("QTreeWidget::item{ height: 16px; }") - self.stackedWidget_Resources.setCurrentIndex(0) - self.treeWidget_ResourceTree.clear() - parent = self.treeWidget_ResourceTree - checked_source_files = self.convert_to_modules(self.source_files) - tag_dict = utils.get_tags(checked_source_files, typedefs.tag_to_string, self.lineEdit_Search.text()) - docstring_dict = utils.get_docstrings(checked_source_files, self.lineEdit_Search.text()) - for tag in tag_dict: - child = QTreeWidgetItem(parent) - child.setText(0, tag) - for item in tag_dict[tag]: - docstring = docstring_dict.get(item) - docstr_child = QTreeWidgetItem(child) - docstr_child.setText(LIBPINCE_REFERENCE_ITEM_COL, item) - docstr_child.setText(LIBPINCE_REFERENCE_VALUE_COL, str(eval(item))) - docstr_child.setToolTip(LIBPINCE_REFERENCE_ITEM_COL, docstring) - docstr_child.setToolTip(LIBPINCE_REFERENCE_VALUE_COL, docstring) - - # Magic and mystery - self.treeWidget_ResourceTree.blockSignals(True) - if self.lineEdit_Search.text(): - self.treeWidget_ResourceTree.expandAll() - self.resize_resource_tree() - self.treeWidget_ResourceTree.blockSignals(False) - - def fill_resource_table(self): - self.stackedWidget_Resources.setCurrentIndex(1) - self.tableWidget_ResourceTable.setSortingEnabled(False) - self.tableWidget_ResourceTable.setRowCount(0) - if self.comboBox_SourceFile.currentIndex() == 1: # (All) - checked_source_files = self.source_files - else: - checked_source_files = [self.comboBox_SourceFile.currentText()] - checked_source_files = self.convert_to_modules(checked_source_files) - element_dict = utils.get_docstrings(checked_source_files, self.lineEdit_Search.text()) - self.tableWidget_ResourceTable.setRowCount(len(element_dict)) - for row, item in enumerate(element_dict): - docstring = element_dict.get(item) - table_widget_item = QTableWidgetItem(item) - table_widget_item_value = QTableWidgetItem(str(eval(item))) - table_widget_item.setToolTip(docstring) - table_widget_item_value.setToolTip(docstring) - self.tableWidget_ResourceTable.setItem(row, LIBPINCE_REFERENCE_ITEM_COL, table_widget_item) - self.tableWidget_ResourceTable.setItem(row, LIBPINCE_REFERENCE_VALUE_COL, table_widget_item_value) - self.tableWidget_ResourceTable.setSortingEnabled(True) - self.tableWidget_ResourceTable.sortByColumn(LIBPINCE_REFERENCE_ITEM_COL, Qt.SortOrder.AscendingOrder) - guiutils.resize_to_contents(self.tableWidget_ResourceTable) - - def pushButton_TextDown_clicked(self): - if self.found_count == 0: - return - cursor = self.textBrowser_TypeDefs.textCursor() - cursor.clearSelection() - cursor.movePosition(QTextCursor.MoveOperation.Start) - self.textBrowser_TypeDefs.setTextCursor(cursor) - if self.current_found == self.found_count: - self.current_found = 1 - else: - self.current_found += 1 - pattern = self.lineEdit_SearchText.text() - for x in range(self.current_found): - self.textBrowser_TypeDefs.find(pattern) - self.label_FoundCount.setText(str(self.current_found) + "/" + str(self.found_count)) - - def pushButton_TextUp_clicked(self): - if self.found_count == 0: - return - cursor = self.textBrowser_TypeDefs.textCursor() - cursor.clearSelection() - cursor.movePosition(QTextCursor.MoveOperation.Start) - self.textBrowser_TypeDefs.setTextCursor(cursor) - if self.current_found == 1: - self.current_found = self.found_count - else: - self.current_found -= 1 - pattern = self.lineEdit_SearchText.text() - for x in range(self.current_found): - self.textBrowser_TypeDefs.find(pattern) - self.label_FoundCount.setText(str(self.current_found) + "/" + str(self.found_count)) - - def highlight_text(self): - cursor = self.textBrowser_TypeDefs.textCursor() - cursor.clearSelection() - cursor.movePosition(QTextCursor.MoveOperation.Start) - self.textBrowser_TypeDefs.setTextCursor(cursor) - highlight_format = QTextCharFormat() - color = QColor(QColorConstants.LightGray) - color.setAlpha(96) - highlight_format.setBackground(color) - pattern = self.lineEdit_SearchText.text() - found_count = 0 - while True: - if not self.textBrowser_TypeDefs.find(pattern): - break - cursor = self.textBrowser_TypeDefs.textCursor() - cursor.mergeCharFormat(highlight_format) - found_count += 1 - self.found_count = found_count - if found_count == 0: - self.label_FoundCount.setText("0/0") - else: - self.label_FoundCount.setText("1/" + str(found_count)) - cursor = self.textBrowser_TypeDefs.textCursor() - cursor.clearSelection() - cursor.movePosition(QTextCursor.MoveOperation.Start) - self.textBrowser_TypeDefs.setTextCursor(cursor) - self.textBrowser_TypeDefs.find(pattern) - self.current_found = 1 - - def toggle_typedefs(self): - if self.typedefs_shown: - self.hide_typedefs() - else: - self.show_typedefs() - - def hide_typedefs(self): - self.typedefs_shown = False - self.widget_TypeDefs.hide() - self.pushButton_ShowTypeDefs.setText("Show typedefs") - - def show_typedefs(self): - self.typedefs_shown = True - self.widget_TypeDefs.show() - self.pushButton_ShowTypeDefs.setText("Hide typedefs") - - class LogFileWidgetForm(QWidget, LogFileWidget): def __init__(self, parent): super().__init__(parent) diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index fd39b650..e3064c52 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -663,50 +663,6 @@ Patterns at former positions have higher priority if regex is off Enter the regex. Leave blank to see all functions - - - libpince Reference - - - - - - Search - - - - - typedefs(Type Definitions) - - - - - - - - Value - Valore - - - - Item Name - - - - - Source File - - - - - Resources(Mouse-over items to see docstrings) - - - - - Hide typedefs - - @@ -761,6 +717,12 @@ Patterns at former positions have higher priority if regex is off Referenced Strings and Values + + + + Value + Valore + Restore Instructions diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 7f808eeb..a4dab0a3 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -665,50 +665,6 @@ Patterns at former positions have higher priority if regex is off Enter the regex. Leave blank to see all functions 请输入正则表达式。如果不输入任何内容,则会显示所有函数 - - - libpince Reference - libpince 引用 - - - - - Search - 搜索 - - - - typedefs(Type Definitions) - typedefs(类型定义) - - - - - - - Value - - - - - Item Name - 条目名 - - - - Source File - 源文件 - - - - Resources(Mouse-over items to see docstrings) - 资源(将鼠标悬停在项目上以查看文档字符串) - - - - Hide typedefs - 隐藏 typedefs - @@ -763,6 +719,12 @@ Patterns at former positions have higher priority if regex is off Referenced Strings and Values 引用的字符串和值 + + + + Value + + Restore Instructions diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 413421b5..824ececd 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -25,45 +25,29 @@ libc = ctypes.CDLL("libc.so.6") system_endianness = typedefs.ENDIANNESS.LITTLE if sys.byteorder == "little" else typedefs.ENDIANNESS.BIG -#:tag:GDBInformation -#:doc: # A boolean value. True if gdb is initialized, False if not gdb_initialized = False -#:tag:InferiorInformation -#:doc: # An integer. Can be a member of typedefs.INFERIOR_ARCH inferior_arch = int -#:tag:InferiorInformation -#:doc: # An integer. Can be a member of typedefs.INFERIOR_STATUS inferior_status = -1 -#:tag:InferiorInformation -#:doc: # An integer. PID of the current attached/created process currentpid = -1 -#:tag:GDBInformation -#:doc: # An integer. Can be a member of typedefs.STOP_REASON stop_reason = int -#:tag:GDBInformation -#:doc: # A dictionary. Holds breakpoint numbers and what to do on hit # Format: {bp_num1:on_hit1, bp_num2:on_hit2, ...} breakpoint_on_hit_dict = {} -#:tag:GDBInformation -#:doc: # A dictionary. Holds address and aob of instructions that were nop'ed out # Format: {address1:orig_instruction1_aob, address2:orig_instruction2_aob, ...} modified_instructions_dict = {} -#:tag:GDBInformation -#:doc: # If an action such as deletion or condition modification happens in one of the breakpoints in a list, others in the # same list will get affected as well # Format: [[[address1, size1], [address2, size2], ...], [[address1, size1], ...], ...] @@ -71,43 +55,29 @@ child = object # this object will be used with pexpect operations -#:tag:ConditionsLocks -#:doc: # This Lock is used by the function send_command to ensure synchronous execution lock_send_command = Lock() -#:tag:ConditionsLocks -#:doc: # This condition is notified whenever status of the inferior changes # Use the variable inferior_status to get information about inferior's status # See PINCE's CheckInferiorStatus class for an example status_changed_condition = Condition() -#:tag:ConditionsLocks -#:doc: # This condition is notified if the current inferior gets terminated # See PINCE's AwaitProcessExit class for an example process_exited_condition = Condition() -#:tag:ConditionsLocks -#:doc: # This condition is notified if gdb starts to wait for the prompt output # See function send_command for an example gdb_waiting_for_prompt_condition = Condition() -#:tag:GDBInformation -#:doc: # A string. Stores the output of the last command gdb_output = "" -#:tag:GDBInformation -#:doc: # An instance of typedefs.RegisterQueue. Updated whenever GDB receives an async event such as breakpoint modification # See PINCE's AwaitAsyncOutput class for an example of usage gdb_async_output = typedefs.RegisterQueue() -#:tag:GDBInformation -#:doc: # 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 @@ -116,24 +86,16 @@ # A boolean value. Used by state_observe_thread to check if a trace session is active active_trace = False -#:tag:GDBInformation -#:doc: # A string. Holds the last command sent to gdb last_gdb_command = "" -#:tag:GDBInformation -#:doc: # A list of booleans. Used to adjust gdb output # Use the function set_gdb_output_mode to make use of this variable gdb_output_mode = typedefs.gdb_output_mode(True, True, True) -#:tag:InferiorInformation -#:doc: # A string. memory file of the currently attached/created process mem_file = "/proc/" + str(currentpid) + "/mem" -#:tag:Debug -#:doc: # A string. Determines which signal to use to interrupt the process interrupt_signal = "SIGINT" @@ -154,7 +116,6 @@ """ -#:tag:GDBCommunication def set_gdb_output_mode(output_mode_tuple): """Adjusts gdb output @@ -166,7 +127,6 @@ def set_gdb_output_mode(output_mode_tuple): gdb_output_mode = output_mode_tuple -#:tag:GDBCommunication def cancel_last_command(): """Cancels the last gdb command sent if it's still present""" if lock_send_command.locked(): @@ -174,7 +134,6 @@ def cancel_last_command(): cancel_send_command = True -#:tag:GDBCommunication def send_command( command, control=False, cli_output=False, send_with_file=False, file_contents_send=None, recv_with_file=False ): @@ -338,7 +297,6 @@ def check_inferior_status(): print("Exiting state_observe_thread") -#:tag:GDBCommunication def execute_func_temporary_interruption(func, *args, **kwargs): """Interrupts the inferior before executing the given function, continues inferior's execution after calling the given function @@ -362,7 +320,6 @@ def execute_func_temporary_interruption(func, *args, **kwargs): return result -#:tag:GDBCommunication def execute_with_temporary_interruption(func): """Decorator version of execute_func_temporary_interruption""" @@ -372,7 +329,6 @@ def wrapper(*args, **kwargs): return wrapper -#:tag:Debug def can_attach(pid): """Check if we can attach to the target @@ -391,7 +347,6 @@ def can_attach(pid): return True -#:tag:Debug def wait_for_stop(timeout=0): """Block execution till the inferior stops @@ -408,7 +363,6 @@ def wait_for_stop(timeout=0): break -#:tag:Debug def interrupt_inferior(interrupt_reason=typedefs.STOP_REASON.DEBUG): """Interrupt the inferior @@ -430,7 +384,6 @@ def interrupt_inferior(interrupt_reason=typedefs.STOP_REASON.DEBUG): stop_reason = interrupt_reason -#:tag:Debug def continue_inferior(): """Continue the inferior""" if currentpid == -1: @@ -438,25 +391,21 @@ def continue_inferior(): send_command("c&") -#:tag:Debug def step_instruction(): """Step one assembly instruction""" send_command("stepi&") -#:tag:Debug def step_over_instruction(): """Step over one assembly instruction""" send_command("nexti&") -#:tag:Debug def execute_till_return(): """Continues inferior till current stack frame returns""" send_command("finish&") -#:tag:Debug def set_interrupt_signal(signal_name): """Decides on what signal to use to stop the process @@ -468,7 +417,6 @@ def set_interrupt_signal(signal_name): interrupt_signal = signal_name -#:tag:Debug def handle_signal(signal_name: str, stop: bool, pass_to_program: bool) -> None: """Decides on what will GDB do when the process recieves a signal @@ -481,7 +429,6 @@ def handle_signal(signal_name: str, stop: bool, pass_to_program: bool) -> None: send_command("pince-handle-signals", send_with_file=True, file_contents_send=params) -#:tag:Debug def handle_signals(signal_list): """Optimized version of handle_signal for multiple signals @@ -491,7 +438,6 @@ def handle_signals(signal_list): send_command("pince-handle-signals", send_with_file=True, file_contents_send=signal_list) -#:tag:GDBCommunication def init_gdb(gdb_path=utils.get_default_gdb_path()): """Spawns gdb and initializes/resets some of the global variables @@ -554,7 +500,6 @@ def init_gdb(gdb_path=utils.get_default_gdb_path()): return True -#:tag:GDBCommunication def set_logging(state): """Sets logging on or off @@ -567,7 +512,6 @@ def set_logging(state): send_command("set logging enabled on") -#:tag:GDBCommunication def set_pince_paths(): """Initializes $PINCE_PATH and $GDBINIT_AA_PATH convenience variables to make commands in gdbextensions.py and gdbutils.py work. GDB scripts need to know libpince and .config directories, unfortunately they don't start @@ -592,7 +536,6 @@ def init_referenced_dicts(pid): shelve.open(utils.get_referenced_calls_file(pid), "c") -#:tag:Debug def attach(pid, gdb_path=utils.get_default_gdb_path()): """Attaches gdb to the target and initializes some of the global variables @@ -636,7 +579,6 @@ def attach(pid, gdb_path=utils.get_default_gdb_path()): return typedefs.ATTACH_RESULT.SUCCESSFUL -#:tag:Debug def create_process(process_path, args="", ld_preload_path="", gdb_path=utils.get_default_gdb_path()): """Creates a new process for debugging and initializes some of the global variables Current process will be detached even if the create_process call fails @@ -690,7 +632,6 @@ def create_process(process_path, args="", ld_preload_path="", gdb_path=utils.get return True -#:tag:Debug def detach(): """See you, space cowboy""" global gdb_initialized @@ -708,7 +649,6 @@ def detach(): print("Detached from the process with PID:" + str(old_pid)) -#:tag:Debug def toggle_attach(): """Detaches from the current process without ending the season if currently attached. Attaches back if detached @@ -727,7 +667,6 @@ def toggle_attach(): return typedefs.TOGGLE_ATTACH.ATTACHED -#:tag:Debug def is_attached(): """Checks if gdb is attached to the current process @@ -739,7 +678,6 @@ def is_attached(): return True -#:tag:Injection def inject_with_advanced_injection(library_path): """Injects the given .so file to current process @@ -756,7 +694,6 @@ def inject_with_advanced_injection(library_path): raise NotImplementedError -#:tag:Injection def inject_with_dlopen_call(library_path): """Injects the given .so file to current process This is a variant of the function inject_with_advanced_injection @@ -780,7 +717,6 @@ def inject_with_dlopen_call(library_path): return True -#:tag:MemoryRW def read_pointer_chain(pointer_request: typedefs.PointerChainRequest) -> typedefs.PointerChainResult | None: """Reads the addresses pointed by this pointer chain @@ -844,7 +780,6 @@ def memory_handle(): return open(mem_file, "rb") -#:tag:MemoryRW def read_memory( address, value_index, @@ -944,7 +879,6 @@ def read_memory( return result -#:tag:MemoryRW def write_memory( address: str | int, value_index: int, @@ -1005,7 +939,6 @@ def write_memory( return -#:tag:Assembly def disassemble(expression, offset_or_address): """Disassembles the address evaluated by the given expression @@ -1081,7 +1014,6 @@ def examine_expressions(expression_list): ) -#:tag:GDBExpressions def parse_and_eval(expression, cast=str): """Calls gdb.parse_and_eval with the given expression and returns the value after casting with the given type Use examine_expression if your data can be expressed as an address or a symbol, use this function otherwise @@ -1105,7 +1037,6 @@ def parse_and_eval(expression, cast=str): ) -#:tag:Threads def get_thread_info(): """Invokes "info threads" command and returns the line corresponding to the current thread @@ -1117,7 +1048,6 @@ def get_thread_info(): return re.sub(r'\\"', r'"', regexes.thread_info.search(thread_info).group(1)) -#:tag:Assembly def find_closest_instruction_address(address, instruction_location="next", instruction_count=1): """Finds address of the closest instruction next to the given address, assuming that the given address is valid @@ -1163,7 +1093,6 @@ def find_closest_instruction_address(address, instruction_location="next", instr return hex(utils.get_region_info(currentpid, address).start) -#:tag:GDBExpressions def get_address_info(expression): """Runs the gdb command "info symbol" for given expression and returns the result of it @@ -1176,7 +1105,6 @@ def get_address_info(expression): return send_command("info symbol " + expression, cli_output=True) -#:tag:GDBExpressions def get_symbol_info(expression): """Runs the gdb command "info address" for given expression and returns the result of it @@ -1189,7 +1117,6 @@ def get_symbol_info(expression): return send_command("info address " + expression, cli_output=True) -#:tag:Tools def search_functions(expression, case_sensitive=False): """Runs the gdb command "info functions" for given expression and returns the result of it @@ -1218,7 +1145,6 @@ def search_functions(expression, case_sensitive=False): ) -#:tag:InferiorInformation def get_inferior_pid(): """Get pid of the current inferior @@ -1229,7 +1155,6 @@ def get_inferior_pid(): return regexes.inferior_pid.search(output).group(1) -#:tag:InferiorInformation def get_inferior_arch(): """Returns the architecture of the current inferior @@ -1241,7 +1166,6 @@ def get_inferior_arch(): return typedefs.INFERIOR_ARCH.ARCH_64 -#:tag:Registers def read_registers(): """Returns the current registers @@ -1251,7 +1175,6 @@ def read_registers(): return send_command("pince-read-registers", recv_with_file=True) -#:tag:Registers def read_float_registers(): """Returns the current floating point registers @@ -1264,8 +1187,6 @@ def read_float_registers(): return send_command("pince-read-float-registers", recv_with_file=True) -#:tag:GDBExpressions -#:tag:Registers def set_convenience_variable(variable, value): """Sets given convenience variable to given value Can be also used for modifying registers directly @@ -1277,7 +1198,6 @@ def set_convenience_variable(variable, value): send_command("set $" + variable + "=" + value) -#:tag:Registers def set_register_flag(flag, value): """Sets given register flag to given value @@ -1312,7 +1232,6 @@ def set_register_flag(flag, value): set_convenience_variable("eflags", eflags_hex_value) -#:tag:Stack def get_stacktrace_info(): """Returns information about current stacktrace @@ -1325,7 +1244,6 @@ def get_stacktrace_info(): return send_command("pince-get-stack-trace-info", recv_with_file=True) -#:tag:Stack def get_stack_info(from_base_pointer: bool = False) -> list[str]: """Returns information about current stack Also can view stack from EBP or RBP register @@ -1347,7 +1265,6 @@ def get_stack_info(from_base_pointer: bool = False) -> list[str]: return send_command("pince-get-stack-info", recv_with_file=True) -#:tag:Stack def get_stack_frame_return_addresses(): """Returns return addresses of stack frames @@ -1359,7 +1276,6 @@ def get_stack_frame_return_addresses(): return send_command("pince-get-frame-return-addresses", recv_with_file=True) -#:tag:Stack def get_stack_frame_info(index): """Returns information about stack by the given index @@ -1381,7 +1297,6 @@ def get_stack_frame_info(index): return send_command("pince-get-frame-info", send_with_file=True, file_contents_send=str(index), recv_with_file=True) -#:tag:MemoryRW def hex_dump(address, offset): """Returns hex dump of range (address to address+offset) @@ -1415,7 +1330,6 @@ def hex_dump(address, offset): return hex_byte_list -#:tag:MemoryRW def get_modified_instructions(): """Returns currently modified instructions @@ -1427,7 +1341,6 @@ def get_modified_instructions(): return modified_instructions_dict -#:tag:MemoryRW def nop_instruction(start_address, length_of_instr): """Replaces an instruction's opcodes with NOPs @@ -1447,7 +1360,6 @@ def nop_instruction(start_address, length_of_instr): write_memory(start_address, typedefs.VALUE_INDEX.AOB, nop_aob) -#:tag:MemoryRW def modify_instruction(start_address, array_of_bytes): """Replaces an instruction's opcodes with a new AOB @@ -1467,7 +1379,6 @@ def modify_instruction(start_address, array_of_bytes): write_memory(start_address, typedefs.VALUE_INDEX.AOB, array_of_bytes) -#:tag:MemoryRW def restore_instruction(start_address): """Restores a modified instruction to it's original opcodes @@ -1482,7 +1393,6 @@ def restore_instruction(start_address): write_memory(start_address, typedefs.VALUE_INDEX.AOB, array_of_bytes) -#:tag:BreakWatchpoints def get_breakpoint_info() -> list[typedefs.tuple_breakpoint_info]: """Returns current breakpoint/watchpoint list @@ -1552,7 +1462,6 @@ def get_breakpoint_info() -> list[typedefs.tuple_breakpoint_info]: return returned_list -#:tag:BreakWatchpoints def get_breakpoints_in_range(address: str | int, length: int = 1) -> list[typedefs.tuple_breakpoint_info]: """Checks if given address exists in breakpoint list @@ -1577,7 +1486,6 @@ def get_breakpoints_in_range(address: str | int, length: int = 1) -> list[typede return breakpoint_list -#:tag:BreakWatchpoints def hardware_breakpoint_available() -> bool: """Checks if there is an available hardware breakpoint slot @@ -1598,7 +1506,6 @@ def hardware_breakpoint_available() -> bool: return hw_bp_total < 4 -#:tag:BreakWatchpoints def add_breakpoint( expression, breakpoint_type=typedefs.BREAKPOINT_TYPE.HARDWARE, on_hit=typedefs.BREAKPOINT_ON_HIT.BREAK ): @@ -1640,7 +1547,6 @@ def add_breakpoint( @execute_with_temporary_interruption -#:tag:BreakWatchpoints def add_watchpoint( expression: str, length: int = 4, @@ -1706,7 +1612,6 @@ def add_watchpoint( return breakpoints_set -#:tag:BreakWatchpoints def modify_breakpoint(expression, modify_what, condition=None, count=None): """Adds a condition to the breakpoint at the address evaluated by the given expression @@ -1776,7 +1681,6 @@ def modify_breakpoint(expression, modify_what, condition=None, count=None): return True -#:tag:BreakWatchpoints def delete_breakpoint(expression): """Deletes a breakpoint at the address evaluated by the given expression @@ -1816,7 +1720,6 @@ def delete_breakpoint(expression): @execute_with_temporary_interruption -#:tag:BreakWatchpoints def track_watchpoint(expression, length, watchpoint_type): """Starts tracking a value by setting a watchpoint at the address holding it Use get_track_watchpoint_info() to get info about the watchpoint you set @@ -1840,7 +1743,6 @@ def track_watchpoint(expression, length, watchpoint_type): return breakpoints -#:tag:BreakWatchpoints def get_track_watchpoint_info(watchpoint_list): """Gathers the information for the tracked watchpoint(s) @@ -1867,7 +1769,6 @@ def get_track_watchpoint_info(watchpoint_list): @execute_with_temporary_interruption -#:tag:BreakWatchpoints def track_breakpoint(expression, register_expressions): """Starts tracking a value by setting a breakpoint at the address holding it Use get_track_breakpoint_info() to get info about the breakpoint you set @@ -1900,7 +1801,6 @@ def track_breakpoint(expression, register_expressions): return breakpoint -#:tag:BreakWatchpoints def get_track_breakpoint_info(breakpoint): """Gathers the information for the tracked breakpoint @@ -2061,7 +1961,6 @@ def cancel_trace(self): self.cancel = True -#:tag:Tools def call_function_from_inferior(expression): """Calls the given function expression from the inferior @@ -2082,7 +1981,6 @@ def call_function_from_inferior(expression): return False, False -#:tag:InferiorInformation def find_entry_point(): """Finds entry point of the inferior @@ -2096,7 +1994,6 @@ def find_entry_point(): return filtered_result.group(1) -#:tag:Tools def search_opcode(searched_str, starting_address, ending_address_or_offset, case_sensitive=False, enable_regex=False): """Searches for the given str in the disassembled output @@ -2142,7 +2039,6 @@ def search_opcode(searched_str, starting_address, ending_address_or_offset, case return returned_list -#:tag:Tools def dissect_code(region_list, discard_invalid_strings=True): """Searches given regions for jumps, calls and string references Use function get_dissect_code_data() to gather the results @@ -2155,7 +2051,6 @@ def dissect_code(region_list, discard_invalid_strings=True): send_command("pince-dissect-code", send_with_file=True, file_contents_send=(region_list, discard_invalid_strings)) -#:tag:Tools def get_dissect_code_status(): """Returns the current state of dissect code process @@ -2180,14 +2075,12 @@ def get_dissect_code_status(): return output -#:tag:Tools def cancel_dissect_code(): """Finishes the current dissect code process early on""" if last_gdb_command.find("pince-dissect-code") != -1: cancel_last_command() -#:tag:Tools def get_dissect_code_data(referenced_strings=True, referenced_jumps=True, referenced_calls=True): """Returns shelve.DbfilenameShelf objects of referenced dicts @@ -2225,7 +2118,6 @@ def get_dissect_code_data(referenced_strings=True, referenced_jumps=True, refere return dict_list -#:tag:Tools def search_referenced_strings( searched_str, value_index=typedefs.VALUE_INDEX.STRING_UTF8, case_sensitive=False, enable_regex=False ): @@ -2274,7 +2166,6 @@ def search_referenced_strings( return returned_list -#:tag:Tools def search_referenced_calls(searched_str, case_sensitive=True, enable_regex=False): """Searches for given str in the referenced calls diff --git a/libpince/utils.py b/libpince/utils.py index daed9e18..def25baa 100644 --- a/libpince/utils.py +++ b/libpince/utils.py @@ -27,7 +27,6 @@ ks_64 = Ks(KS_ARCH_X86, KS_MODE_64) -#:tag:Processes def get_process_list() -> list[str, str, str]: """Returns a list of processes @@ -42,7 +41,6 @@ def get_process_list() -> list[str, str, str]: return process_list -#:tag:Processes def get_process_name(pid: int | str) -> str: """Returns the process name of given pid @@ -56,7 +54,6 @@ def get_process_name(pid: int | str) -> str: return f.read().splitlines()[0] -#:tag:Processes def search_processes(process_name): """Searches processes and returns a list of the ones that contain process_name @@ -73,7 +70,6 @@ def search_processes(process_name): return processlist -#:tag:Processes def get_regions(pid): """Returns memory regions of a process @@ -90,7 +86,6 @@ def get_regions(pid): return regions -#:tag:Processes def get_region_dict(pid: int) -> dict[str, list[str]]: """Returns memory regions of a process as a dictionary where key is the path tail and value is the list of the corresponding start addresses of the tail, empty paths will be ignored. Also adds shortcuts for file extensions, @@ -125,7 +120,6 @@ def get_region_dict(pid: int) -> dict[str, list[str]]: return region_dict -#:tag:Processes def get_region_info(pid, address): """Finds the closest valid starting/ending address and region to given address, assuming given address is in the valid address range @@ -151,7 +145,6 @@ def get_region_info(pid, address): return typedefs.tuple_region_info(start, end, perms, file_name) -#:tag:Processes def filter_regions(pid, attribute, regex, case_sensitive=False): """Filters memory regions by searching for the given regex within the given attribute @@ -181,7 +174,6 @@ def filter_regions(pid, attribute, regex, case_sensitive=False): return filtered_regions -#:tag:Processes def is_traced(pid): """Check if the process corresponding to given pid traced by any other process @@ -203,7 +195,6 @@ def is_traced(pid): return get_process_name(tracer_pid) -#:tag:Processes def is_process_valid(pid): """Check if the process corresponding to given pid is valid @@ -216,7 +207,6 @@ def is_process_valid(pid): return os.path.exists("/proc/%d" % pid) -#:tag:Utilities def get_script_directory(): """Get main script directory @@ -226,7 +216,6 @@ def get_script_directory(): return sys.path[0] -#:tag:Utilities def get_media_directory(): """Get media directory @@ -236,7 +225,6 @@ def get_media_directory(): return get_script_directory() + "/media" -#:tag:Utilities def get_logo_directory(): """Get logo directory @@ -246,7 +234,6 @@ def get_logo_directory(): return get_script_directory() + "/media/logo" -#:tag:Utilities def get_libpince_directory(): """Get libpince directory @@ -260,7 +247,6 @@ def get_libpince_directory(): return os.path.dirname(os.path.realpath(__file__)) -#:tag:GDBCommunication def delete_ipc_path(pid): """Deletes the IPC directory of given pid @@ -272,7 +258,6 @@ def delete_ipc_path(pid): shutil.rmtree(path) -#:tag:GDBCommunication def create_ipc_path(pid): """Creates the IPC directory of given pid @@ -291,7 +276,6 @@ def create_ipc_path(pid): open(command_file, "w").close() -#:tag:GDBCommunication def create_tmp_path(pid): """Creates the tmp directory of given pid @@ -304,7 +288,6 @@ def create_tmp_path(pid): os.makedirs(path) -#:tag:GDBCommunication def get_ipc_path(pid): """Get the IPC directory of given pid @@ -317,7 +300,6 @@ def get_ipc_path(pid): return typedefs.PATHS.IPC + str(pid) -#:tag:GDBCommunication def get_tmp_path(pid): """Get the tmp directory of given pid @@ -330,7 +312,6 @@ def get_tmp_path(pid): return typedefs.PATHS.TMP + str(pid) -#:tag:GDBCommunication def get_logging_file(pid): """Get the path of gdb logfile of given pid @@ -343,7 +324,6 @@ def get_logging_file(pid): return get_tmp_path(pid) + "/gdb_log.txt" -#:tag:GDBCommunication def get_gdb_command_file(pid): """Get the path of gdb command file of given pid @@ -356,7 +336,6 @@ def get_gdb_command_file(pid): return get_ipc_path(pid) + "/gdb_command.txt" -#:tag:BreakWatchpoints def get_track_watchpoint_file(pid, watchpoint_list): """Get the path of track watchpoint file for given pid and watchpoint @@ -370,7 +349,6 @@ def get_track_watchpoint_file(pid, watchpoint_list): return get_ipc_path(pid) + "/" + str(watchpoint_list) + "_track_watchpoint.txt" -#:tag:BreakWatchpoints def get_track_breakpoint_file(pid, breakpoint): """Get the path of track breakpoint file for given pid and breakpoint @@ -384,7 +362,6 @@ def get_track_breakpoint_file(pid, breakpoint): return get_ipc_path(pid) + "/" + breakpoint + "_track_breakpoint.txt" -#:tag:Utilities def append_file_extension(string, extension): """Appends the given extension to the given string if it doesn't end with the given extension @@ -399,7 +376,6 @@ def append_file_extension(string, extension): return string if string.endswith("." + extension) else string + "." + extension -#:tag:Utilities def save_file(data, file_path, save_method="json"): """Saves the specified data to given path @@ -432,7 +408,6 @@ def save_file(data, file_path, save_method="json"): return False -#:tag:Utilities def load_file(file_path, load_method="json"): """Loads data from the given path @@ -462,7 +437,6 @@ def load_file(file_path, load_method="json"): return output -#:tag:Tools def get_trace_status_file(pid): """Get the path of trace status file for given pid @@ -487,7 +461,6 @@ def change_trace_status(pid: int | str, trace_status: int): trace_file.write(str(trace_status)) -#:tag:Tools def get_dissect_code_status_file(pid): """Get the path of dissect code status file for given pid @@ -500,7 +473,6 @@ def get_dissect_code_status_file(pid): return get_ipc_path(pid) + "/dissect_code_status.txt" -#:tag:Tools def get_referenced_strings_file(pid): """Get the path of referenced strings dict file for given pid @@ -513,7 +485,6 @@ def get_referenced_strings_file(pid): return get_tmp_path(pid) + "/referenced_strings_dict.txt" -#:tag:Tools def get_referenced_jumps_file(pid): """Get the path of referenced jumps dict file for given pid @@ -526,7 +497,6 @@ def get_referenced_jumps_file(pid): return get_tmp_path(pid) + "/referenced_jumps_dict.txt" -#:tag:Tools def get_referenced_calls_file(pid): """Get the path of referenced strings dict file for given pid @@ -539,7 +509,6 @@ def get_referenced_calls_file(pid): return get_tmp_path(pid) + "/referenced_calls_dict.txt" -#:tag:GDBCommunication def get_from_pince_file(pid): """Get the path of IPC file sent to custom gdb commands from PINCE for given pid @@ -552,7 +521,6 @@ def get_from_pince_file(pid): return get_ipc_path(pid) + typedefs.PATHS.FROM_PINCE -#:tag:GDBCommunication def get_to_pince_file(pid): """Get the path of IPC file sent to PINCE from custom gdb commands for given pid @@ -565,7 +533,6 @@ def get_to_pince_file(pid): return get_ipc_path(pid) + typedefs.PATHS.TO_PINCE -#:tag:ValueType def parse_string(string: str, value_index: int): """Parses the string according to the given value_index @@ -637,7 +604,6 @@ def parse_string(string: str, value_index: int): return string -#:tag:Assembly def instruction_follow_address(string): """Searches for the location changing instructions such as Jcc, CALL and LOOPcc in the given string. Returns the hex address the instruction jumps to @@ -654,7 +620,6 @@ def instruction_follow_address(string): return result.group(2) -#:tag:Utilities def extract_address(string): """Extracts hex address from the given string @@ -670,7 +635,6 @@ def extract_address(string): return result.group(0) -#:tag:Utilities def modulo_address(int_address, arch_type): """Calculates the modulo of the given integer based on the given architecture type to make sure that it doesn't exceed the borders of the given architecture type (0xffffffff->x86, 0xffffffffffffffff->x64) @@ -689,7 +653,6 @@ def modulo_address(int_address, arch_type): raise Exception("arch_type must be a member of typedefs.INFERIOR_ARCH") -#:tag:Utilities def get_opcodes(address, aob, inferior_arch): """Returns the instructions from the given array of bytes @@ -714,7 +677,6 @@ def get_opcodes(address, aob, inferior_arch): return "; ".join([data[2] for data in disas_data]) -#:tag:Utilities def assemble(instructions, address, inferior_arch): """Assembles the given instructions @@ -736,7 +698,6 @@ def assemble(instructions, address, inferior_arch): print(e) -#:tag:ValueType def aob_to_str(list_of_bytes, encoding="ascii", replace_unprintable=True): """Converts given array of hex strings to str @@ -773,7 +734,6 @@ def aob_to_str(list_of_bytes, encoding="ascii", replace_unprintable=True): return hexBytes.decode(encoding, "surrogateescape") -#:tag:ValueType def str_to_aob(string, encoding="ascii"): """Converts given string to aob string @@ -788,7 +748,6 @@ def str_to_aob(string, encoding="ascii"): return " ".join(s[i : i + 2] for i in range(0, len(s), 2)) -#:tag:GDBExpressions def split_symbol(symbol_string): """Splits symbol part of typedefs.tuple_function_info into smaller fractions Fraction count depends on the the symbol_string. See Examples section for demonstration @@ -842,7 +801,6 @@ def split_symbol(symbol_string): return returned_list -#:tag:Utilities def execute_command_as_user(command): """Executes given command as user @@ -853,183 +811,6 @@ def execute_command_as_user(command): os.system("sudo -Eu '#" + uid + "' " + command) -#:tag:Utilities -def get_docstrings(modules, search_for=""): - """Gathers docstrings from a list of modules - For now, this function only supports variables and functions - See get_variable_comments function to learn documenting variables in PINCE style - - Args: - modules (list): A list of modules - search_for (str): String that will be searched in variables and functions - - Returns: - dict: A dict containing docstrings for documented variables and functions - Format-->{variable1:docstring1, variable2:docstring2, ...} - """ - element_dict = {} - variable_comment_dict = get_variable_comments(modules) - for item in modules: - for key, value in item.__dict__.items(): - name_with_module = get_module_name(item) + "." + key - if name_with_module in variable_comment_dict: - element_dict[name_with_module] = variable_comment_dict[name_with_module] - else: - element_dict[name_with_module] = value.__doc__ - for item in list(element_dict): - if item.split(".")[-1].find(search_for) == -1: - del element_dict[item] - return element_dict - - -#:tag:Utilities -def get_variable_comments(modules, search_for=""): - r"""Gathers comments from a list of modules - Python normally doesn't allow modifying __doc__ variable of the variables - This function is designed to bring a solution to this problem - The documentation must be PINCE style. It must start with this--> "#:doc:" - See examples for more details - - Args: - modules (list): A list of modules - search_for (str): String that will be searched in variables - - Returns: - dict: A dict containing docstrings for documented variables - Format-->{variable1:docstring1, variable2:docstring2, ...} - - Example for single line comments: - Code--▼ - #:doc: - #Documentation for the variable - some_variable = blablabla - Returns--▼ - {"some_variable":"Documentation for the variable"} - - Example for multi line comments: - Code--▼ - #:doc: - '''Some Header - Documentation for the variable - Some Ending Word''' - some_variable = blablabla - Returns--▼ - {"some_variable":"Some Header\nDocumentation for the variable\nSome Ending Word"} - """ - comment_dict = {} - source_files = [] - for module in modules: - source_files.append(module.__file__) - for index, file_path in enumerate(source_files): - source_file = open(file_path, "r") - lines = source_file.readlines() - for row, line in enumerate(lines): - stripped_line = line.strip() - if stripped_line.startswith("#:doc:"): - docstring_list = [] - while True: - row += 1 - current_line = lines[row].strip() - if current_line.startswith("#"): - docstring_list.append(current_line.replace("#", "", 1)) - elif current_line.startswith("'''"): - current_line = current_line.replace("'''", "", 1) - if current_line.endswith("'''"): - current_line = current_line.replace("'''", "") - docstring_list.append(current_line) - continue - docstring_list.append(current_line) - while True: - row += 1 - current_line = lines[row].strip() - if current_line.endswith("'''"): - current_line = current_line.replace("'''", "") - docstring_list.append(current_line) - break - docstring_list.append(current_line) - else: - while True: - stripped_current_line = regexes.docstring_variable.search(current_line) - if stripped_current_line: - variable = stripped_current_line.group(1) - break - row += 1 - current_line = lines[row].strip() - break - if variable.find(search_for) == -1: - continue - comment_dict[get_module_name(modules[index]) + "." + variable] = "\n".join(docstring_list) - return comment_dict - - -#:tag:Utilities -def get_tags(modules, tag_to_string, search_for=""): - """Gathers tags from a python source file - The documentation must be PINCE style. It must start like this--> "#:tag:tag_name" - For now, tagging system only supports variables and functions - See examples for more details - - Args: - modules (list): A list of modules - tag_to_string (dict): A dictionary that holds tag descriptions in this format-->{tag:tag_description} - Check typedefs.tag_to_string for an example - search_for (str): String that will be searched in tags - - Returns: - dict: A dict containing tag keys for tagged variables - Format-->{tag1_desc:variable_list1, tag2_desc:variable_list2, ...} - - Examples: - Code--▼ - #:tag:tag_name - #Documentation for the variable - some_variable = blablabla - - or - - #:tag:tag_name - def func_name(...) - Returns--▼ - {tag_to_string["tag_name"]:list of some_variables or func_names that have the tag tag_name} - """ - tag_dict = {} - source_files = [] - for module in modules: - source_files.append(module.__file__) - for index, file_path in enumerate(source_files): - source_file = open(file_path, "r") - lines = source_file.readlines() - for row, line in enumerate(lines): - stripped_line = line.strip() - if stripped_line.startswith("#:tag:"): - tag = stripped_line.replace("#:tag:", "", 1) - while True: - row += 1 - current_line = lines[row].strip() - stripped_current_line = regexes.docstring_function_or_variable.search(current_line) - if stripped_current_line: - for item in stripped_current_line.groups(): - if item: - if item.find(search_for) == -1: - break - item = get_module_name(modules[index]) + "." + item - try: - tag_dict[tag].append(item) - except KeyError: - tag_dict[tag] = [item] - break - else: - continue - break - ordered_tag_dict = OrderedDict() - for tag, desc in tag_to_string.items(): - if tag in tag_dict: - ordered_tag_dict[desc] = tag_dict[tag] - else: - continue - return ordered_tag_dict - - def get_module_name(module): """Gets the name of the given module without the package name @@ -1042,7 +823,6 @@ def get_module_name(module): return module.__name__.replace(module.__package__ + ".", "", 1) -#:tag:Utilities def init_user_files(): """Initializes user files""" root_path = get_user_path(typedefs.USER_PATHS.ROOT) @@ -1056,7 +836,6 @@ def init_user_files(): open(file, "w").close() -#:tag:Utilities def get_user_ids(): """Gets uid and gid of the current user @@ -1068,7 +847,6 @@ def get_user_ids(): return uid, gid -#:tag:Utilities def get_user_home_dir(): """Returns the home directory of the current user @@ -1079,7 +857,6 @@ def get_user_home_dir(): return pwd.getpwuid(int(uid)).pw_dir -#:tag:Utilities def get_user_path(user_path): """Returns the specified user path for the current user @@ -1101,7 +878,6 @@ def get_default_gdb_path(): return typedefs.PATHS.GDB -#:tag:Tools def execute_script(file_path): """Loads and executes the script in the given path @@ -1130,7 +906,6 @@ def execute_script(file_path): return module, None -#:tag:Utilities def parse_response(response, line_num=0): """Parses the given GDB/MI output. Wraps gdbmiparser.parse_response debugcore.send_command returns an additional "^done" output because of the "source" command @@ -1146,7 +921,6 @@ def parse_response(response, line_num=0): return gdbmiparser.parse_response(response.splitlines()[line_num]) -#:tag:Utilities def search_files(directory, regex): """Searches the files in given directory for given regex recursively @@ -1165,7 +939,6 @@ def search_files(directory, regex): return sorted(file_list) -#:tag:Utilities def ignore_exceptions(func): """A decorator to ignore exceptions""" @@ -1178,7 +951,6 @@ def wrapper(*args, **kwargs): return wrapper -#:tag:Utilities def upper_hex(hex_str: str): """Converts the given hex string to uppercase while keeping the 'x' character lowercase""" # check if the given string is a hex string, if not return the string as is From b86d426ece875a9aae8de46a2ce59bf1879dfd15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 23 Jul 2024 13:38:06 +0300 Subject: [PATCH 466/487] Update roadmap and readme --- CONTRIBUTING.md | 1 - README.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ccf1192f..1d8b6765 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -142,7 +142,6 @@ So, after learning how to contribute, you are wondering where to start now. You These tasks are ordered by importance but feel free to pick any of them. Further details can be discussed in the PINCE discord server - Implement libpince engine - Implement multi-line code injection, this will also help with previously dropped inject_with_advanced_injection -- Migrate to Sphinx documentation from the custom libpince documentation - Libpince support for Mono and Java (symbol recognition, calling functions, dissect obj tree etc.) - Move GUI classes of PINCE.py to their own files - Extend documentation to GUI parts. Libpince has 100% documentation coverage but GUI doesn't diff --git a/README.md b/README.md index 1dec2604..ba6d686d 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Pre-release screenshots: - **Code Injection** * **Run-time injection:** Only .so injection is supported for now. In Memory View window, click Tools->Inject .so file to select the .so file. An example for creating .so file can be found in "libpince/Injection/". PINCE will be able to inject single line instructions or code caves in near future - **GDB Console:** You can use the GDB Console to interact with GDB, it's on the top right in main window -- **libpince:** PINCE provides a reusable python library. You can either read the code or check Reference Widget by clicking Help->libpince in Memory Viewer window to see docstrings. Contents of this widget are automatically generated by looking at the docstrings of the source files. This feature will be replaced with Sphinx in the near future +- **libpince:** PINCE provides a reusable python library. You can either read the code or check the [Github Pages](https://korcankaraokcu.github.io/PINCE/) for documentation. Currently, libpince can be used via console by following [these instructions](https://github.com/korcankaraokcu/PINCE/issues/232#issuecomment-1872906700). In the future, it'll be directly integrated into PINCE when we develop the scripting engine (IDE for PINCE) - **Extendable with .so files at runtime:** See [here](https://github.com/korcankaraokcu/PINCE/wiki/Extending-PINCE-with-.so-files) # Installing and running PINCE From b96cd58ffb2d004e6957ff2f363f4195034f4876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 24 Jul 2024 13:59:42 +0300 Subject: [PATCH 467/487] Enable sorting for value search table --- GUI/MainWindow.py | 1 + GUI/MainWindow.ui | 3 +++ PINCE.py | 7 +++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index cb39340a..e8bf6e5c 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -282,6 +282,7 @@ def retranslateUi(self, MainWindow): self.pushButton_Console.setToolTip(_translate("MainWindow", "Open a gdb console")) self.pushButton_Settings.setToolTip(_translate("MainWindow", "Configure options")) self.label_MatchCount.setText(_translate("MainWindow", "Match count: 0")) + self.tableWidget_valuesearchtable.setSortingEnabled(True) item = self.tableWidget_valuesearchtable.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "Address")) item = self.tableWidget_valuesearchtable.horizontalHeaderItem(1) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 0be8dca7..8a6f042a 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -326,6 +326,9 @@ false + + true + true diff --git a/PINCE.py b/PINCE.py index 4352a4fc..81a3e38b 100755 --- a/PINCE.py +++ b/PINCE.py @@ -454,6 +454,7 @@ def __init__(self): self.treeWidget_AddressTable.setColumnWidth(TYPE_COL, 150) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) + self.tableWidget_valuesearchtable.horizontalHeader().setSortIndicatorClearable(True) self.settings = QSettings() self.memory_view_window = MemoryViewWindowForm(self) self.await_exit_thread = AwaitProcessExit() @@ -1401,6 +1402,7 @@ def scan_callback(self): length = self._scan_to_length(current_type) mem_handle = debugcore.memory_handle() row = 0 # go back to using n when unknown issue gets fixed + self.tableWidget_valuesearchtable.setSortingEnabled(False) for n, address, offset, region_type, val, result_type in matches: address = "0x" + address result = result_type.split(" ")[0] @@ -1424,6 +1426,7 @@ def scan_callback(self): row += 1 if row == 1000: break + self.tableWidget_valuesearchtable.setSortingEnabled(True) self.QWidget_Toolbox.setEnabled(True) def _scan_to_length(self, type_index): @@ -1716,6 +1719,7 @@ def update_search_table(self): mem_handle = debugcore.memory_handle() for row_index in range(row_count): address_item = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_ADDRESS_COL) + value_item = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_VALUE_COL) previous_text = self.tableWidget_valuesearchtable.item(row_index, SEARCH_TABLE_PREVIOUS_COL).text() value_index, value_repr, endian = address_item.data(Qt.ItemDataRole.UserRole) address = address_item.text() @@ -1724,10 +1728,9 @@ def update_search_table(self): address, value_index, length, value_repr=value_repr, endian=endian, mem_handle=mem_handle ) ) - value_item = QTableWidgetItem(new_value) if new_value != previous_text: value_item.setForeground(QBrush(QColor(255, 0, 0))) - self.tableWidget_valuesearchtable.setItem(row_index, SEARCH_TABLE_VALUE_COL, value_item) + value_item.setText(new_value) def freeze(self): if debugcore.currentpid == -1: From fe110e0420ecbfe130faa0f8a652bbfa9e2d1322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 24 Jul 2024 15:33:22 +0300 Subject: [PATCH 468/487] Fix resizing for value search table --- GUI/MainWindow.py | 1 + GUI/MainWindow.ui | 3 +++ PINCE.py | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index e8bf6e5c..67704d05 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -136,6 +136,7 @@ def setupUi(self, MainWindow): self.tableWidget_valuesearchtable.setAlternatingRowColors(True) self.tableWidget_valuesearchtable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) self.tableWidget_valuesearchtable.setShowGrid(False) + self.tableWidget_valuesearchtable.setWordWrap(False) self.tableWidget_valuesearchtable.setObjectName("tableWidget_valuesearchtable") self.tableWidget_valuesearchtable.setColumnCount(3) self.tableWidget_valuesearchtable.setRowCount(0) diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 8a6f042a..5a60ebe4 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -329,6 +329,9 @@ true + + false + true diff --git a/PINCE.py b/PINCE.py index 81a3e38b..9882dc0e 100755 --- a/PINCE.py +++ b/PINCE.py @@ -452,7 +452,7 @@ def __init__(self): self.treeWidget_AddressTable.setColumnWidth(DESC_COL, 150) self.treeWidget_AddressTable.setColumnWidth(ADDR_COL, 150) self.treeWidget_AddressTable.setColumnWidth(TYPE_COL, 150) - self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 110) + self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_ADDRESS_COL, 120) self.tableWidget_valuesearchtable.setColumnWidth(SEARCH_TABLE_VALUE_COL, 80) self.tableWidget_valuesearchtable.horizontalHeader().setSortIndicatorClearable(True) self.settings = QSettings() @@ -1426,6 +1426,7 @@ def scan_callback(self): row += 1 if row == 1000: break + self.tableWidget_valuesearchtable.resizeColumnsToContents() self.tableWidget_valuesearchtable.setSortingEnabled(True) self.QWidget_Toolbox.setEnabled(True) From aac4d92ff9a41adbdd73dcd09cce617d84d11efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 24 Jul 2024 15:52:20 +0300 Subject: [PATCH 469/487] Remove fixed font sizes --- GUI/MemoryViewerWindow.py | 61 ++----------------------------------- GUI/MemoryViewerWindow.ui | 63 +++------------------------------------ 2 files changed, 7 insertions(+), 117 deletions(-) diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 0698ec09..83085a76 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -39,7 +39,6 @@ def setupUi(self, MainWindow_MemoryView): self.tableWidget_Disassemble = QtWidgets.QTableWidget(parent=self.widget_Disassemble) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.tableWidget_Disassemble.setFont(font) self.tableWidget_Disassemble.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.tableWidget_Disassemble.setAutoScroll(False) @@ -85,7 +84,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Registers.setWidgetResizable(True) self.scrollArea_Registers.setObjectName("scrollArea_Registers") self.scrollAreaWidgetContents_Registers = QtWidgets.QWidget() - self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 335, 342)) + self.scrollAreaWidgetContents_Registers.setGeometry(QtCore.QRect(0, 0, 344, 343)) self.scrollAreaWidgetContents_Registers.setObjectName("scrollAreaWidgetContents_Registers") self.gridLayout_8 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_Registers) self.gridLayout_8.setContentsMargins(0, 0, 0, 0) @@ -100,7 +99,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_3 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_3.setFont(font) self.label_3.setObjectName("label_3") self.verticalLayout_19.addWidget(self.label_3) @@ -136,7 +134,6 @@ def setupUi(self, MainWindow_MemoryView): self.RAX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RAX.setFont(font) self.RAX.setText("RAX=") self.RAX.setObjectName("RAX") @@ -144,7 +141,6 @@ def setupUi(self, MainWindow_MemoryView): self.RBX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RBX.setFont(font) self.RBX.setText("RBX=") self.RBX.setObjectName("RBX") @@ -152,7 +148,6 @@ def setupUi(self, MainWindow_MemoryView): self.RCX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RCX.setFont(font) self.RCX.setText("RCX=") self.RCX.setObjectName("RCX") @@ -160,7 +155,6 @@ def setupUi(self, MainWindow_MemoryView): self.RDX = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RDX.setFont(font) self.RDX.setText("RDX=") self.RDX.setObjectName("RDX") @@ -168,7 +162,6 @@ def setupUi(self, MainWindow_MemoryView): self.RSI = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RSI.setFont(font) self.RSI.setText("RSI=") self.RSI.setObjectName("RSI") @@ -176,7 +169,6 @@ def setupUi(self, MainWindow_MemoryView): self.RDI = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RDI.setFont(font) self.RDI.setText("RDI=") self.RDI.setObjectName("RDI") @@ -184,7 +176,6 @@ def setupUi(self, MainWindow_MemoryView): self.RBP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RBP.setFont(font) self.RBP.setText("RBP=") self.RBP.setObjectName("RBP") @@ -192,7 +183,6 @@ def setupUi(self, MainWindow_MemoryView): self.RSP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RSP.setFont(font) self.RSP.setText("RSP=") self.RSP.setObjectName("RSP") @@ -206,7 +196,6 @@ def setupUi(self, MainWindow_MemoryView): self.R8 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R8.setFont(font) self.R8.setText("R8=") self.R8.setObjectName("R8") @@ -214,7 +203,6 @@ def setupUi(self, MainWindow_MemoryView): self.R9 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R9.setFont(font) self.R9.setText("R9=") self.R9.setObjectName("R9") @@ -222,7 +210,6 @@ def setupUi(self, MainWindow_MemoryView): self.R10 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R10.setFont(font) self.R10.setText("R10=") self.R10.setObjectName("R10") @@ -230,7 +217,6 @@ def setupUi(self, MainWindow_MemoryView): self.R11 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R11.setFont(font) self.R11.setText("R11=") self.R11.setObjectName("R11") @@ -238,7 +224,6 @@ def setupUi(self, MainWindow_MemoryView): self.R12 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R12.setFont(font) self.R12.setText("R12=") self.R12.setObjectName("R12") @@ -246,7 +231,6 @@ def setupUi(self, MainWindow_MemoryView): self.R13 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R13.setFont(font) self.R13.setText("R13=") self.R13.setObjectName("R13") @@ -254,7 +238,6 @@ def setupUi(self, MainWindow_MemoryView): self.R14 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R14.setFont(font) self.R14.setText("R14=") self.R14.setObjectName("R14") @@ -262,7 +245,6 @@ def setupUi(self, MainWindow_MemoryView): self.R15 = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.R15.setFont(font) self.R15.setText("R15=") self.R15.setObjectName("R15") @@ -275,7 +257,6 @@ def setupUi(self, MainWindow_MemoryView): self.RIP = QRegisterLabel(parent=self.registers_64) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.RIP.setFont(font) self.RIP.setText("RIP=") self.RIP.setObjectName("RIP") @@ -305,7 +286,6 @@ def setupUi(self, MainWindow_MemoryView): self.EAX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.EAX.setFont(font) self.EAX.setText("EAX=") self.EAX.setObjectName("EAX") @@ -313,7 +293,6 @@ def setupUi(self, MainWindow_MemoryView): self.EBX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.EBX.setFont(font) self.EBX.setText("EBX=") self.EBX.setObjectName("EBX") @@ -321,7 +300,6 @@ def setupUi(self, MainWindow_MemoryView): self.ECX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.ECX.setFont(font) self.ECX.setText("ECX=") self.ECX.setObjectName("ECX") @@ -329,7 +307,6 @@ def setupUi(self, MainWindow_MemoryView): self.EDX = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.EDX.setFont(font) self.EDX.setText("EDX=") self.EDX.setObjectName("EDX") @@ -337,7 +314,6 @@ def setupUi(self, MainWindow_MemoryView): self.ESI = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.ESI.setFont(font) self.ESI.setText("ESI=") self.ESI.setObjectName("ESI") @@ -345,7 +321,6 @@ def setupUi(self, MainWindow_MemoryView): self.EDI = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.EDI.setFont(font) self.EDI.setText("EDI=") self.EDI.setObjectName("EDI") @@ -353,7 +328,6 @@ def setupUi(self, MainWindow_MemoryView): self.EBP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.EBP.setFont(font) self.EBP.setText("EBP=") self.EBP.setObjectName("EBP") @@ -361,7 +335,6 @@ def setupUi(self, MainWindow_MemoryView): self.ESP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.ESP.setFont(font) self.ESP.setText("ESP=") self.ESP.setObjectName("ESP") @@ -369,7 +342,6 @@ def setupUi(self, MainWindow_MemoryView): self.EIP = QRegisterLabel(parent=self.registers_32) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.EIP.setFont(font) self.EIP.setText("EIP=") self.EIP.setObjectName("EIP") @@ -384,7 +356,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_29 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_29.setFont(font) self.label_29.setObjectName("label_29") self.verticalLayout_19.addWidget(self.label_29) @@ -402,7 +373,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_31 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_31.setFont(font) self.label_31.setText("CF") self.label_31.setObjectName("label_31") @@ -410,7 +380,6 @@ def setupUi(self, MainWindow_MemoryView): self.CF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.CF.setFont(font) self.CF.setText("0") self.CF.setObjectName("CF") @@ -422,7 +391,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_35 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_35.setFont(font) self.label_35.setText("PF") self.label_35.setObjectName("label_35") @@ -430,7 +398,6 @@ def setupUi(self, MainWindow_MemoryView): self.PF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.PF.setFont(font) self.PF.setText("0") self.PF.setObjectName("PF") @@ -442,7 +409,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_37 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_37.setFont(font) self.label_37.setText("AF") self.label_37.setObjectName("label_37") @@ -450,7 +416,6 @@ def setupUi(self, MainWindow_MemoryView): self.AF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.AF.setFont(font) self.AF.setText("0") self.AF.setObjectName("AF") @@ -462,7 +427,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_39 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_39.setFont(font) self.label_39.setText("ZF") self.label_39.setObjectName("label_39") @@ -470,7 +434,6 @@ def setupUi(self, MainWindow_MemoryView): self.ZF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.ZF.setFont(font) self.ZF.setText("0") self.ZF.setObjectName("ZF") @@ -482,7 +445,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_41 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_41.setFont(font) self.label_41.setText("SF") self.label_41.setObjectName("label_41") @@ -490,7 +452,6 @@ def setupUi(self, MainWindow_MemoryView): self.SF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.SF.setFont(font) self.SF.setText("0") self.SF.setObjectName("SF") @@ -502,7 +463,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_43 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_43.setFont(font) self.label_43.setText("TF") self.label_43.setObjectName("label_43") @@ -510,7 +470,6 @@ def setupUi(self, MainWindow_MemoryView): self.TF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.TF.setFont(font) self.TF.setText("0") self.TF.setObjectName("TF") @@ -522,7 +481,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_45 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_45.setFont(font) self.label_45.setText("IF") self.label_45.setObjectName("label_45") @@ -530,7 +488,6 @@ def setupUi(self, MainWindow_MemoryView): self.IF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.IF.setFont(font) self.IF.setText("0") self.IF.setObjectName("IF") @@ -542,7 +499,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_47 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_47.setFont(font) self.label_47.setText("DF") self.label_47.setObjectName("label_47") @@ -550,7 +506,6 @@ def setupUi(self, MainWindow_MemoryView): self.DF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.DF.setFont(font) self.DF.setText("0") self.DF.setObjectName("DF") @@ -562,7 +517,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_49 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_49.setFont(font) self.label_49.setText("OF") self.label_49.setObjectName("label_49") @@ -570,7 +524,6 @@ def setupUi(self, MainWindow_MemoryView): self.OF = QFlagRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.OF.setFont(font) self.OF.setText("0") self.OF.setObjectName("OF") @@ -582,7 +535,6 @@ def setupUi(self, MainWindow_MemoryView): self.label_30 = QtWidgets.QLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.label_30.setFont(font) self.label_30.setObjectName("label_30") self.verticalLayout_19.addWidget(self.label_30) @@ -600,7 +552,6 @@ def setupUi(self, MainWindow_MemoryView): self.CS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.CS.setFont(font) self.CS.setText("CS=") self.CS.setObjectName("CS") @@ -608,7 +559,6 @@ def setupUi(self, MainWindow_MemoryView): self.ES = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.ES.setFont(font) self.ES.setText("ES=") self.ES.setObjectName("ES") @@ -622,7 +572,6 @@ def setupUi(self, MainWindow_MemoryView): self.SS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.SS.setFont(font) self.SS.setText("SS=") self.SS.setObjectName("SS") @@ -630,7 +579,6 @@ def setupUi(self, MainWindow_MemoryView): self.GS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.GS.setFont(font) self.GS.setText("GS=") self.GS.setObjectName("GS") @@ -644,7 +592,6 @@ def setupUi(self, MainWindow_MemoryView): self.DS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.DS.setFont(font) self.DS.setText("DS=") self.DS.setObjectName("DS") @@ -652,7 +599,6 @@ def setupUi(self, MainWindow_MemoryView): self.FS = QRegisterLabel(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.FS.setFont(font) self.FS.setText("FS=") self.FS.setObjectName("FS") @@ -662,7 +608,6 @@ def setupUi(self, MainWindow_MemoryView): self.pushButton_ShowFloatRegisters = QtWidgets.QPushButton(parent=self.scrollAreaWidgetContents_Registers) font = QtGui.QFont() font.setFamily("Monospace") - font.setPointSize(9) self.pushButton_ShowFloatRegisters.setFont(font) self.pushButton_ShowFloatRegisters.setObjectName("pushButton_ShowFloatRegisters") self.verticalLayout_19.addWidget(self.pushButton_ShowFloatRegisters) @@ -689,7 +634,7 @@ def setupUi(self, MainWindow_MemoryView): self.scrollArea_Hex.setWidgetResizable(True) self.scrollArea_Hex.setObjectName("scrollArea_Hex") self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() - self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 492, 200)) + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 492, 197)) self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") self.gridLayout_11 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) self.gridLayout_11.setContentsMargins(0, 0, 0, 0) @@ -825,7 +770,7 @@ def setupUi(self, MainWindow_MemoryView): self.gridLayout_5.addWidget(self.splitter_MainMiddle, 0, 0, 1, 1) MainWindow_MemoryView.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(parent=MainWindow_MemoryView) - self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 23)) self.menubar.setObjectName("menubar") self.menuView = QtWidgets.QMenu(parent=self.menubar) self.menuView.setObjectName("menuView") diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index 7db3c098..f06ca9dc 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -76,7 +76,6 @@ Monospace - 9 @@ -190,8 +189,8 @@ 0 0 - 335 - 342 + 344 + 343 @@ -225,7 +224,6 @@ Monospace - 9 @@ -300,7 +298,6 @@ Monospace - 9 @@ -313,7 +310,6 @@ Monospace - 9 @@ -326,7 +322,6 @@ Monospace - 9 @@ -339,7 +334,6 @@ Monospace - 9 @@ -352,7 +346,6 @@ Monospace - 9 @@ -365,7 +358,6 @@ Monospace - 9 @@ -378,7 +370,6 @@ Monospace - 9 @@ -391,7 +382,6 @@ Monospace - 9 @@ -424,7 +414,6 @@ Monospace - 9 @@ -437,7 +426,6 @@ Monospace - 9 @@ -450,7 +438,6 @@ Monospace - 9 @@ -463,7 +450,6 @@ Monospace - 9 @@ -476,7 +462,6 @@ Monospace - 9 @@ -489,7 +474,6 @@ Monospace - 9 @@ -502,7 +486,6 @@ Monospace - 9 @@ -515,7 +498,6 @@ Monospace - 9 @@ -537,7 +519,6 @@ Monospace - 9 @@ -614,7 +595,6 @@ Monospace - 9 @@ -627,7 +607,6 @@ Monospace - 9 @@ -640,7 +619,6 @@ Monospace - 9 @@ -653,7 +631,6 @@ Monospace - 9 @@ -666,7 +643,6 @@ Monospace - 9 @@ -679,7 +655,6 @@ Monospace - 9 @@ -692,7 +667,6 @@ Monospace - 9 @@ -705,7 +679,6 @@ Monospace - 9 @@ -718,7 +691,6 @@ Monospace - 9 @@ -754,7 +726,6 @@ Monospace - 9 @@ -784,7 +755,6 @@ Monospace - 9 @@ -797,7 +767,6 @@ Monospace - 9 @@ -817,7 +786,6 @@ Monospace - 9 @@ -830,7 +798,6 @@ Monospace - 9 @@ -850,7 +817,6 @@ Monospace - 9 @@ -863,7 +829,6 @@ Monospace - 9 @@ -883,7 +848,6 @@ Monospace - 9 @@ -896,7 +860,6 @@ Monospace - 9 @@ -916,7 +879,6 @@ Monospace - 9 @@ -929,7 +891,6 @@ Monospace - 9 @@ -949,7 +910,6 @@ Monospace - 9 @@ -962,7 +922,6 @@ Monospace - 9 @@ -982,7 +941,6 @@ Monospace - 9 @@ -995,7 +953,6 @@ Monospace - 9 @@ -1015,7 +972,6 @@ Monospace - 9 @@ -1028,7 +984,6 @@ Monospace - 9 @@ -1048,7 +1003,6 @@ Monospace - 9 @@ -1061,7 +1015,6 @@ Monospace - 9 @@ -1094,7 +1047,6 @@ Monospace - 9 @@ -1124,7 +1076,6 @@ Monospace - 9 @@ -1137,7 +1088,6 @@ Monospace - 9 @@ -1170,7 +1120,6 @@ Monospace - 9 @@ -1183,7 +1132,6 @@ Monospace - 9 @@ -1216,7 +1164,6 @@ Monospace - 9 @@ -1229,7 +1176,6 @@ Monospace - 9 @@ -1246,7 +1192,6 @@ Monospace - 9 @@ -1329,7 +1274,7 @@ 0 0 492 - 200 + 197 @@ -1631,7 +1576,7 @@ 0 0 800 - 22 + 23 From c00e955b3968e01a18330ca4ea20c75b81290334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 24 Jul 2024 20:13:18 +0300 Subject: [PATCH 470/487] Remove redundant size property --- GUI/MemoryViewerWindow.py | 1 - GUI/MemoryViewerWindow.ui | 6 ------ 2 files changed, 7 deletions(-) diff --git a/GUI/MemoryViewerWindow.py b/GUI/MemoryViewerWindow.py index 83085a76..1e636318 100644 --- a/GUI/MemoryViewerWindow.py +++ b/GUI/MemoryViewerWindow.py @@ -71,7 +71,6 @@ def setupUi(self, MainWindow_MemoryView): self.verticalScrollBar_Disassemble.setObjectName("verticalScrollBar_Disassemble") self.gridLayout_2.addWidget(self.verticalScrollBar_Disassemble, 0, 1, 1, 1) self.widget_Registers = QtWidgets.QWidget(parent=self.splitter_Disassemble_Registers) - self.widget_Registers.setMinimumSize(QtCore.QSize(0, 0)) font = QtGui.QFont() font.setFamily("Monospace") self.widget_Registers.setFont(font) diff --git a/GUI/MemoryViewerWindow.ui b/GUI/MemoryViewerWindow.ui index f06ca9dc..6578615a 100644 --- a/GUI/MemoryViewerWindow.ui +++ b/GUI/MemoryViewerWindow.ui @@ -152,12 +152,6 @@ - - - 0 - 0 - - Monospace From bec671ed12e25c719f03ab75d4868ef4abad2ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Tue, 30 Jul 2024 17:41:08 +0300 Subject: [PATCH 471/487] Add missing xmm registers --- GUI/FloatRegisterWidget.py | 4 ++-- GUI/FloatRegisterWidget.ui | 2 +- PINCE.py | 17 ++++++++++------- libpince/debugcore.py | 4 ++-- libpince/gdb_python_scripts/gdbutils.py | 6 +++++- libpince/typedefs.py | 3 ++- 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/GUI/FloatRegisterWidget.py b/GUI/FloatRegisterWidget.py index 551e17b1..4f54389f 100644 --- a/GUI/FloatRegisterWidget.py +++ b/GUI/FloatRegisterWidget.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'FloatRegisterWidget.ui' # -# Created by: PyQt6 UI code generator 6.5.1 +# Created by: PyQt6 UI code generator 6.4.2 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -12,7 +12,7 @@ class Ui_TabWidget(object): def setupUi(self, TabWidget): TabWidget.setObjectName("TabWidget") - TabWidget.resize(400, 300) + TabWidget.resize(400, 316) self.FPU = QtWidgets.QWidget() self.FPU.setObjectName("FPU") self.gridLayout = QtWidgets.QGridLayout(self.FPU) diff --git a/GUI/FloatRegisterWidget.ui b/GUI/FloatRegisterWidget.ui index eee44c35..3719368e 100644 --- a/GUI/FloatRegisterWidget.ui +++ b/GUI/FloatRegisterWidget.ui @@ -7,7 +7,7 @@ 0 0 400 - 300 + 316 diff --git a/PINCE.py b/PINCE.py index 9882dc0e..c13df459 100755 --- a/PINCE.py +++ b/PINCE.py @@ -4534,13 +4534,16 @@ def update_registers(self): self.tableWidget_FPU.setRowCount(0) self.tableWidget_FPU.setRowCount(8) self.tableWidget_XMM.setRowCount(0) - self.tableWidget_XMM.setRowCount(8) - float_registers = debugcore.read_float_registers() - for row, (st, xmm) in enumerate(zip(typedefs.REGISTERS.FLOAT.ST, typedefs.REGISTERS.FLOAT.XMM)): - self.tableWidget_FPU.setItem(row, FLOAT_REGISTERS_NAME_COL, QTableWidgetItem(st)) - self.tableWidget_FPU.setItem(row, FLOAT_REGISTERS_VALUE_COL, QTableWidgetItem(float_registers[st])) - self.tableWidget_XMM.setItem(row, FLOAT_REGISTERS_NAME_COL, QTableWidgetItem(xmm)) - self.tableWidget_XMM.setItem(row, FLOAT_REGISTERS_VALUE_COL, QTableWidgetItem(float_registers[xmm])) + self.tableWidget_XMM.setRowCount(16) + float_registers = list(debugcore.read_float_registers().items()) + st_registers = float_registers[:8] + xmm_registers = float_registers[8:] + for row, (name, value) in enumerate(st_registers): + self.tableWidget_FPU.setItem(row, FLOAT_REGISTERS_NAME_COL, QTableWidgetItem(name)) + self.tableWidget_FPU.setItem(row, FLOAT_REGISTERS_VALUE_COL, QTableWidgetItem(value)) + for row, (name, value) in enumerate(xmm_registers): + self.tableWidget_XMM.setItem(row, FLOAT_REGISTERS_NAME_COL, QTableWidgetItem(name)) + self.tableWidget_XMM.setItem(row, FLOAT_REGISTERS_VALUE_COL, QTableWidgetItem(value)) def set_register(self, index): if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 824ececd..2aac697a 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -1175,11 +1175,11 @@ def read_registers(): return send_command("pince-read-registers", recv_with_file=True) -def read_float_registers(): +def read_float_registers() -> OrderedDict[str, str]: """Returns the current floating point registers Returns: - dict: A dict that holds floating point registers. Check typedefs.REGISTERS.FLOAT for the full list + OrderedDict[str, str]: A dict that holds floating point registers. Check typedefs.REGISTERS.FLOAT for the full list Note: Returned xmm values are based on xmm.v4_float diff --git a/libpince/gdb_python_scripts/gdbutils.py b/libpince/gdb_python_scripts/gdbutils.py index 9d65fa21..a452d87c 100644 --- a/libpince/gdb_python_scripts/gdbutils.py +++ b/libpince/gdb_python_scripts/gdbutils.py @@ -116,7 +116,11 @@ def get_float_registers(): for register in typedefs.REGISTERS.FLOAT.ST: value = gdb.parse_and_eval("$" + register) contents_send[register] = str(value) - for register in typedefs.REGISTERS.FLOAT.XMM: + if current_arch == typedefs.INFERIOR_ARCH.ARCH_64: + xmm_registers = typedefs.REGISTERS.FLOAT.XMM_64 + else: + xmm_registers = typedefs.REGISTERS.FLOAT.XMM_32 + for register in xmm_registers: value = gdb.parse_and_eval("$" + register + ".v4_float") contents_send[register] = str(value) return contents_send diff --git a/libpince/typedefs.py b/libpince/typedefs.py index 910e7d6a..f61dd6e1 100644 --- a/libpince/typedefs.py +++ b/libpince/typedefs.py @@ -151,7 +151,8 @@ class REGISTERS: class FLOAT: ST = ["st" + str(i) for i in range(8)] - XMM = ["xmm" + str(i) for i in range(8)] + XMM_32 = ["xmm" + str(i) for i in range(8)] + XMM_64 = ["xmm" + str(i) for i in range(16)] class FREEZE_TYPE: From 31f464a73539acb0b277d24923081cfa62150af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Fri, 2 Aug 2024 19:54:58 +0300 Subject: [PATCH 472/487] Add context menu to search table and extend its key events Rename append_to_travel_history to append_history --- GUI/Utils/guiutils.py | 37 +++++++-- PINCE.py | 179 ++++++++++++++++++++++++++++-------------- i18n/ts/it_IT.ts | 5 ++ i18n/ts/zh_CN.ts | 5 ++ tr/tr.py | 1 + 5 files changed, 163 insertions(+), 64 deletions(-) diff --git a/GUI/Utils/guiutils.py b/GUI/Utils/guiutils.py index b3b619dd..3ea5b8a2 100644 --- a/GUI/Utils/guiutils.py +++ b/GUI/Utils/guiutils.py @@ -15,11 +15,24 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from PyQt6.QtWidgets import QWidget, QScrollBar, QTableWidget, QComboBox, QMenu, QLayout +from PyQt6.QtWidgets import ( + QWidget, + QScrollBar, + QTableWidget, + QTableWidgetItem, + QTreeWidget, + QTreeWidgetItem, + QListWidget, + QListWidgetItem, + QComboBox, + QMenu, + QLayout, +) from PyQt6.QtCore import QObject, QRegularExpression from PyQt6.QtGui import QShortcut, QRegularExpressionValidator from libpince import utils, typedefs, regexes from tr.tr import TranslationConstants as tr +from typing import overload validator_map: dict[str, QRegularExpressionValidator | None] = { "int": QRegularExpressionValidator(QRegularExpression(regexes.decimal_number.pattern)), # integers @@ -135,14 +148,26 @@ def get_current_row(tablewidget: QTableWidget): return -1 -def get_current_item(tablewidget: QTableWidget): - r"""Returns the currently selected item for the given QTableWidget +@overload +def get_current_item(listwidget: QListWidget) -> QListWidgetItem | None: ... + + +@overload +def get_current_item(tablewidget: QTableWidget) -> QTableWidgetItem | None: ... + + +@overload +def get_current_item(treewidget: QTreeWidget) -> QTreeWidgetItem | None: ... + + +def get_current_item(widget: QListWidget | QTableWidget | QTreeWidget): + r"""Returns the currently selected item for the given widget If you try to use only selectionModel().currentItem() for this purpose, you'll get the last selected item even if it was unselected afterwards. This is why this function exists, it checks the selection state before returning the selected item. Unlike get_current_row, this function can be used with QTreeWidget Args: - tablewidget (QTableWidget): Self-explanatory + widget (QListWidget | QTableWidget | QTreeWidget): Self-explanatory Returns: Any: Currently selected item. Returns None if nothing is selected @@ -155,8 +180,8 @@ def get_current_item(tablewidget: QTableWidget): For developers: You can use the regex \.current.*\.connect to search signals if a cleanup is needed """ - if tablewidget.selectionModel().selectedRows(): - return tablewidget.currentItem() + if widget.selectionModel().selectedRows(): + return widget.currentItem() def delete_menu_entries(menu: QMenu, QAction_list: list): diff --git a/PINCE.py b/PINCE.py index c13df459..662a4b86 100755 --- a/PINCE.py +++ b/PINCE.py @@ -38,7 +38,7 @@ QCursor, QKeySequence, QColor, - QTextCharFormat, + QContextMenuEvent, QBrush, QTextCursor, QShortcut, @@ -544,6 +544,7 @@ def __init__(self): ) self.tableWidget_valuesearchtable.keyPressEvent_original = self.tableWidget_valuesearchtable.keyPressEvent self.tableWidget_valuesearchtable.keyPressEvent = self.tableWidget_valuesearchtable_key_press_event + self.tableWidget_valuesearchtable.contextMenuEvent = self.tableWidget_valuesearchtable_context_menu_event self.treeWidget_AddressTable.itemClicked.connect(self.treeWidget_AddressTable_item_clicked) self.treeWidget_AddressTable.itemDoubleClicked.connect(self.treeWidget_AddressTable_item_double_clicked) self.treeWidget_AddressTable.expanded.connect(self.resize_address_table) @@ -736,6 +737,7 @@ def nextscan_hotkey_pressed(self, index): def treeWidget_AddressTable_context_menu_event(self, event): current_row = guiutils.get_current_item(self.treeWidget_AddressTable) + current_address = current_row.text(ADDR_COL) if current_row else None header = self.treeWidget_AddressTable.headerItem() menu = QMenu() delete_record = menu.addAction(f"{tr.DELETE}[Del]") @@ -839,8 +841,8 @@ def treeWidget_AddressTable_context_menu_event(self, event): freeze_default: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT), freeze_inc: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.INCREMENT), freeze_dec: lambda: self.change_freeze_type(typedefs.FREEZE_TYPE.DECREMENT), - browse_region: self.browse_region_for_selected_row, - disassemble: self.disassemble_selected_row, + browse_region: lambda: self.browse_region_for_address(current_address), + disassemble: lambda: self.disassemble_for_address(current_address), pointer_scanner: self.exec_pointer_scanner, pointer_scan: self.exec_pointer_scan, what_writes: lambda: self.exec_track_watchpoint_widget(typedefs.WATCHPOINT_TYPE.WRITE_ONLY), @@ -896,21 +898,16 @@ def exec_track_watchpoint_widget(self, watchpoint_type): byte_len = typedefs.index_to_valuetype_dict[value_type.value_index][0] TrackWatchpointWidgetForm(self, address, byte_len, watchpoint_type) - def browse_region_for_selected_row(self): - row = guiutils.get_current_item(self.treeWidget_AddressTable) - if row: - self.memory_view_window.hex_dump_address(int(row.text(ADDR_COL).strip("P->"), 16)) + def browse_region_for_address(self, address: str): + if address: + self.memory_view_window.hex_dump_address(int(address.strip("P->"), 16)) self.memory_view_window.show() self.memory_view_window.activateWindow() - def disassemble_selected_row(self): - row = guiutils.get_current_item(self.treeWidget_AddressTable) - if row: - if self.memory_view_window.disassemble_expression( - row.text(ADDR_COL).strip("P->"), append_to_travel_history=True - ): - self.memory_view_window.show() - self.memory_view_window.activateWindow() + def disassemble_for_address(self, address: str): + if address and self.memory_view_window.disassemble_expression(address.strip("P->"), append_history=True): + self.memory_view_window.show() + self.memory_view_window.activateWindow() def change_freeze_type(self, freeze_type): for row in self.treeWidget_AddressTable.selectedItems(): @@ -1050,15 +1047,20 @@ def delete_records(self): for item in self.treeWidget_AddressTable.selectedItems(): (item.parent() or root).removeChild(item) - def treeWidget_AddressTable_key_press_event(self, event): + def treeWidget_AddressTable_key_press_event(self, event: QKeyEvent): + current_row = guiutils.get_current_item(self.treeWidget_AddressTable) + current_address = current_row.text(ADDR_COL) if current_row else None actions = typedefs.KeyboardModifiersTupleDict( [ (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), self.delete_records), ( QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), - self.browse_region_for_selected_row, + lambda: self.browse_region_for_address(current_address), + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), + lambda: self.disassemble_for_address(current_address), ), - (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), self.disassemble_selected_row), ( QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.pushButton_RefreshAdressTable_clicked, @@ -1453,27 +1455,90 @@ def tableWidget_valuesearchtable_cell_double_clicked(self, row, col): self.update_address_table() def tableWidget_valuesearchtable_key_press_event(self, event: QKeyEvent) -> None: - if event.key() == Qt.Key.Key_Delete: - # get selected rows - selected_rows = self.tableWidget_valuesearchtable.selectedItems() - if not selected_rows: - return + current_item = self.tableWidget_valuesearchtable.currentItem() + if debugcore.currentpid == -1 or not current_item: + return + current_address = self.tableWidget_valuesearchtable.item(current_item.row(), SEARCH_TABLE_ADDRESS_COL).text() + actions = typedefs.KeyboardModifiersTupleDict( + [ + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_C), + self.copy_valuesearchtable_selection, + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_B), + lambda: self.browse_region_for_address(current_address), + ), + ( + QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), + lambda: self.disassemble_for_address(current_address), + ), + ( + QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Delete), + self.delete_valuesearchtable_selection, + ), + ] + ) + try: + actions[QKeyCombination(event.modifiers(), Qt.Key(event.key()))]() + except KeyError: + self.tableWidget_valuesearchtable.keyPressEvent_original(event) - # get the row indexes - rows = set() - for item in selected_rows: - rows.add(item.row()) + def tableWidget_valuesearchtable_context_menu_event(self, event: QContextMenuEvent) -> None: + selected_indexes = self.tableWidget_valuesearchtable.selectionModel().selectedRows() + if debugcore.currentpid == -1 or not selected_indexes: + return + current_row = self.tableWidget_valuesearchtable.currentItem().row() + address = self.tableWidget_valuesearchtable.item(current_row, SEARCH_TABLE_ADDRESS_COL).text() + menu = QMenu() + if len(selected_indexes) > 1: + copy_selection = menu.addAction(f"{tr.COPY_ADDRESSES}[Ctrl+C]") + else: + copy_selection = menu.addAction(f"{tr.COPY_ADDRESS}[Ctrl+C]") + menu.addSeparator() + browse_region = menu.addAction(f"{tr.BROWSE_MEMORY_REGION}[Ctrl+B]") + disassemble = menu.addAction(f"{tr.DISASSEMBLE_ADDRESS}[Ctrl+D]") + menu.addSeparator() + delete_selection = menu.addAction(f"{tr.DELETE_SELECTION}[Del]") + font_size = self.tableWidget_valuesearchtable.font().pointSize() + menu.setStyleSheet(f"font-size: {font_size}pt;") + action = menu.exec(event.globalPos()) + actions = { + copy_selection: self.copy_valuesearchtable_selection, + browse_region: lambda: self.browse_region_for_address(address), + disassemble: lambda: self.disassemble_for_address(address), + delete_selection: self.delete_valuesearchtable_selection + } + try: + actions[action]() + except KeyError: + pass - scanmem.send_command("delete {}".format(",".join([str(row) for row in rows]))) + def copy_valuesearchtable_selection(self): + selected_indexes = self.tableWidget_valuesearchtable.selectionModel().selectedRows() + address_list = [] + for index in selected_indexes: + row = index.row() + address = self.tableWidget_valuesearchtable.item(row, SEARCH_TABLE_ADDRESS_COL).text() + address_list.append(address) + app.clipboard().setText(" ".join(address_list)) + + def delete_valuesearchtable_selection(self): + selected_rows = self.tableWidget_valuesearchtable.selectedItems() + if not selected_rows: + return - # remove the rows from the table - removing in reverse sorted order to avoid index issues - for row in sorted(rows, reverse=True): - self.tableWidget_valuesearchtable.removeRow(row) - self.update_match_count() + # get the row indexes + rows = set() + for item in selected_rows: + rows.add(item.row()) - return + scanmem.send_command("delete {}".format(",".join([str(row) for row in rows]))) - self.tableWidget_valuesearchtable.keyPressEvent_original(event) + # remove the rows from the table - removing in reverse sorted order to avoid index issues + for row in sorted(rows, reverse=True): + self.tableWidget_valuesearchtable.removeRow(row) + self.update_match_count() def comboBox_ValueType_current_index_changed(self): current_type = self.comboBox_ValueType.currentData(Qt.ItemDataRole.UserRole) @@ -3251,7 +3316,7 @@ def widget_HexView_context_menu_event(self, event): actions = { edit: self.exec_hex_view_edit_dialog, go_to: self.exec_hex_view_go_to_dialog, - disassemble: lambda: self.disassemble_expression(hex(addr), append_to_travel_history=True), + disassemble: lambda: self.disassemble_expression(hex(addr), append_history=True), add_address: self.exec_hex_view_add_address_dialog, copy_selection: self.copy_hex_view_selection, refresh: self.refresh_hex_view, @@ -3509,7 +3574,7 @@ def refresh_hex_view(self): # offset can also be an address as hex str # returns True if the given expression is disassembled correctly, False if not - def disassemble_expression(self, expression, offset="+200", append_to_travel_history=False): + def disassemble_expression(self, expression, offset="+200", append_history=False): if debugcore.currentpid == -1: return disas_data = debugcore.disassemble(expression, offset) @@ -3629,7 +3694,7 @@ def disassemble_expression(self, expression, offset="+200", append_to_travel_his # We append the old record to travel history as last action because we wouldn't like to see unnecessary # addresses in travel history if any error occurs while displaying the next location - if append_to_travel_history: + if append_history: self.tableWidget_Disassemble.travel_history.append(previous_first_address) self.disassemble_currently_displayed_address = current_first_address return True @@ -3861,7 +3926,7 @@ def tableWidget_Stack_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_R), self.update_stack), ( QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), - lambda: self.disassemble_expression(current_address, append_to_travel_history=True), + lambda: self.disassemble_expression(current_address, append_history=True), ), ( QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_H), @@ -3914,7 +3979,7 @@ def copy_to_clipboard(row, column): copy_value: lambda: copy_to_clipboard(selected_row, STACK_VALUE_COL), copy_points_to: lambda: copy_to_clipboard(selected_row, STACK_POINTS_TO_COL), refresh: self.update_stack, - show_in_disas: lambda: self.disassemble_expression(current_address, append_to_travel_history=True), + show_in_disas: lambda: self.disassemble_expression(current_address, append_history=True), show_in_hex: lambda: self.hex_dump_address(int(current_address, 16)), } try: @@ -3937,7 +4002,7 @@ def tableWidget_Stack_double_click(self, index): if points_to_text.startswith("(str)"): self.hex_dump_address(int(current_address, 16)) else: - self.disassemble_expression(current_address, append_to_travel_history=True) + self.disassemble_expression(current_address, append_history=True) def tableWidget_StackTrace_double_click(self, index): if debugcore.currentpid == -1: @@ -3946,7 +4011,7 @@ def tableWidget_StackTrace_double_click(self, index): if index.column() == STACKTRACE_RETURN_ADDRESS_COL: current_address_text = self.tableWidget_StackTrace.item(selected_row, STACKTRACE_RETURN_ADDRESS_COL).text() current_address = utils.extract_address(current_address_text) - self.disassemble_expression(current_address, append_to_travel_history=True) + self.disassemble_expression(current_address, append_history=True) if index.column() == STACKTRACE_FRAME_ADDRESS_COL: current_address_text = self.tableWidget_StackTrace.item(selected_row, STACKTRACE_FRAME_ADDRESS_COL).text() current_address = utils.extract_address(current_address_text) @@ -4022,9 +4087,7 @@ def widget_HexView_key_press_event(self, event): (QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_G), self.exec_hex_view_go_to_dialog), ( QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_D), - lambda: self.disassemble_expression( - hex(self.hex_selection_address_begin), append_to_travel_history=True - ), + lambda: self.disassemble_expression(hex(self.hex_selection_address_begin), append_history=True), ), ( QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_A), @@ -4129,7 +4192,7 @@ def follow_instruction(self, selected_row): self.tableWidget_Disassemble.item(selected_row, DISAS_OPCODES_COL).text() ) if address: - self.disassemble_expression(address, append_to_travel_history=True) + self.disassemble_expression(address, append_history=True) def disassemble_go_back(self): if debugcore.currentpid == -1: @@ -4235,7 +4298,7 @@ def copy_all_columns(row): except KeyError: pass if action in bookmark_actions: - self.disassemble_expression(utils.extract_address(action.text()), append_to_travel_history=True) + self.disassemble_expression(utils.extract_address(action.text()), append_history=True) def dissect_current_region(self): if debugcore.currentpid == -1: @@ -4294,7 +4357,7 @@ def exec_disassemble_go_to_dialog(self): go_to_dialog = InputDialogForm(self, [(tr.ENTER_EXPRESSION, current_address)]) if go_to_dialog.exec(): traveled_exp = go_to_dialog.get_values() - self.disassemble_expression(traveled_exp, append_to_travel_history=True) + self.disassemble_expression(traveled_exp, append_history=True) def bookmark_address(self, int_address): if debugcore.currentpid == -1: @@ -4464,7 +4527,7 @@ def change_display(self, row): self.lineEdit_Comment.setText(self.parent().tableWidget_Disassemble.bookmarks[int(current_address, 16)]) def listWidget_item_double_clicked(self, item): - self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_history=True) def exec_add_entry_dialog(self): entry_dialog = InputDialogForm(self, [(tr.ENTER_EXPRESSION, "")]) @@ -4660,7 +4723,7 @@ def tableWidget_Instructions_key_press_event(self, event): def tableWidget_Instructions_double_clicked(self, index): current_address_text = self.tableWidget_Instructions.item(index.row(), INSTR_ADDR_COL).text() current_address = utils.extract_address(current_address_text) - self.parent().disassemble_expression(current_address, append_to_travel_history=True) + self.parent().disassemble_expression(current_address, append_history=True) class BreakpointInfoWidgetForm(QTabWidget, BreakpointInfoWidget): @@ -4807,7 +4870,7 @@ def tableWidget_BreakpointInfo_double_clicked(self, index): else: current_breakpoint_type = self.tableWidget_BreakpointInfo.item(index.row(), BREAK_TYPE_COL).text() if "breakpoint" in current_breakpoint_type: - self.parent().disassemble_expression(current_address, append_to_travel_history=True) + self.parent().disassemble_expression(current_address, append_history=True) else: self.parent().hex_dump_address(current_address_int) @@ -4876,7 +4939,7 @@ def tableWidget_Opcodes_current_changed(self, QModelIndex_current): def tableWidget_Opcodes_item_double_clicked(self, index): self.parent().memory_view_window.disassemble_expression( - self.tableWidget_Opcodes.item(index.row(), TRACK_WATCHPOINT_ADDR_COL).text(), append_to_travel_history=True + self.tableWidget_Opcodes.item(index.row(), TRACK_WATCHPOINT_ADDR_COL).text(), append_history=True ) self.parent().memory_view_window.show() self.parent().memory_view_window.activateWindow() @@ -5176,7 +5239,7 @@ def treeWidget_InstructionInfo_item_double_clicked(self, index): return address = utils.extract_address(current_item.trace_data[0]) if address: - self.parent().disassemble_expression(address, append_to_travel_history=True) + self.parent().disassemble_expression(address, append_history=True) class FunctionsInfoWidgetForm(QWidget, FunctionsInfoWidget): @@ -5267,7 +5330,7 @@ def tableWidget_SymbolInfo_item_double_clicked(self, index): address = self.tableWidget_SymbolInfo.item(index.row(), FUNCTIONS_INFO_ADDR_COL).text() if address == tr.DEFINED: return - self.parent().disassemble_expression(address, append_to_travel_history=True) + self.parent().disassemble_expression(address, append_history=True) def pushButton_Help_clicked(self): InputDialogForm( @@ -5533,7 +5596,7 @@ def pushButton_Help_clicked(self): def tableWidget_Opcodes_item_double_clicked(self, index): row = index.row() address = self.tableWidget_Opcodes.item(row, SEARCH_OPCODE_ADDR_COL).text() - self.parent().disassemble_expression(utils.extract_address(address), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(address), append_history=True) def tableWidget_Opcodes_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -5828,7 +5891,7 @@ def tableWidget_References_item_double_clicked(self, index): self.parent().hex_dump_address(int(address, 16)) def listWidget_Referrers_item_double_clicked(self, item): - self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_history=True) def tableWidget_References_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -5945,10 +6008,10 @@ def tableWidget_References_current_changed(self, QModelIndex_current): def tableWidget_References_item_double_clicked(self, index): row = index.row() address = self.tableWidget_References.item(row, REF_CALL_ADDR_COL).text() - self.parent().disassemble_expression(utils.extract_address(address), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(address), append_history=True) def listWidget_Referrers_item_double_clicked(self, item): - self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_history=True) def tableWidget_References_context_menu_event(self, event): def copy_to_clipboard(row, column): @@ -6082,7 +6145,7 @@ def listWidget_Referrers_current_changed(self, QModelIndex_current): self.textBrowser_DisasInfo.ensureCursorVisible() def listWidget_Referrers_item_double_clicked(self, item): - self.parent().disassemble_expression(utils.extract_address(item.text()), append_to_travel_history=True) + self.parent().disassemble_expression(utils.extract_address(item.text()), append_history=True) def listWidget_Referrers_context_menu_event(self, event): def copy_to_clipboard(row): diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index e3064c52..5032cbc1 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -1609,6 +1609,11 @@ To change the current GDB path, check Settings->Debug Delete + + + Delete selection + + Cut diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index a4dab0a3..4d87aabe 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -1613,6 +1613,11 @@ To change the current GDB path, check Settings->Debug Delete 删除 + + + Delete selection + + Cut diff --git a/tr/tr.py b/tr/tr.py index ac34af68..6c3c8c0c 100644 --- a/tr/tr.py +++ b/tr/tr.py @@ -71,6 +71,7 @@ def translate(): BROWSE_MEMORY_REGION = QT_TR_NOOP("Browse this memory region") DISASSEMBLE_ADDRESS = QT_TR_NOOP("Disassemble this address") DELETE = QT_TR_NOOP("Delete") + DELETE_SELECTION = QT_TR_NOOP("Delete selection") CUT = QT_TR_NOOP("Cut") COPY = QT_TR_NOOP("Copy") PASTE = QT_TR_NOOP("Paste") From 1062f5907a55f0cc42165500b586dd610d282f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Wed, 14 Aug 2024 20:49:52 +0300 Subject: [PATCH 473/487] Add ability to filter scan regions --- GUI/MainWindow.py | 4 + GUI/MainWindow.ui | 7 ++ GUI/ScanRegionsDialog.py | 88 +++++++++++++++++++++ GUI/ScanRegionsDialog.ui | 163 +++++++++++++++++++++++++++++++++++++++ PINCE.py | 81 ++++++++++++++++++- i18n/ts/it_IT.ts | 51 ++++++++++++ i18n/ts/zh_CN.ts | 51 ++++++++++++ libscanmem-PINCE | 2 +- 8 files changed, 445 insertions(+), 2 deletions(-) create mode 100644 GUI/ScanRegionsDialog.py create mode 100644 GUI/ScanRegionsDialog.ui diff --git a/GUI/MainWindow.py b/GUI/MainWindow.py index 67704d05..27f18a18 100644 --- a/GUI/MainWindow.py +++ b/GUI/MainWindow.py @@ -233,6 +233,9 @@ def setupUi(self, MainWindow): self.comboBox_Endianness.setObjectName("comboBox_Endianness") self.horizontalLayout_3.addWidget(self.comboBox_Endianness) self.verticalLayout_4.addLayout(self.horizontalLayout_3) + self.pushButton_ScanRegions = QtWidgets.QPushButton(parent=self.widget) + self.pushButton_ScanRegions.setObjectName("pushButton_ScanRegions") + self.verticalLayout_4.addWidget(self.pushButton_ScanRegions) spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) self.verticalLayout_4.addItem(spacerItem4) self.horizontalLayout_4.addWidget(self.widget) @@ -298,4 +301,5 @@ def retranslateUi(self, MainWindow): self.label_2.setText(_translate("MainWindow", "Value Type:")) self.label_ScanScope.setText(_translate("MainWindow", "Scan Scope:")) self.label_3.setText(_translate("MainWindow", "Endianness:")) + self.pushButton_ScanRegions.setText(_translate("MainWindow", "Manage Scan Regions")) from GUI.TreeWidgets.AddressTree import QAddressTree diff --git a/GUI/MainWindow.ui b/GUI/MainWindow.ui index 5a60ebe4..7197c4c4 100644 --- a/GUI/MainWindow.ui +++ b/GUI/MainWindow.ui @@ -506,6 +506,13 @@ + + + + Manage Scan Regions + + + diff --git a/GUI/ScanRegionsDialog.py b/GUI/ScanRegionsDialog.py new file mode 100644 index 00000000..3f70fc72 --- /dev/null +++ b/GUI/ScanRegionsDialog.py @@ -0,0 +1,88 @@ +# Form implementation generated from reading ui file 'ScanRegionsDialog.ui' +# +# Created by: PyQt6 UI code generator 6.4.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(724, 568) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.label = QtWidgets.QLabel(parent=Dialog) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.pushButton_Invert = QtWidgets.QPushButton(parent=Dialog) + self.pushButton_Invert.setObjectName("pushButton_Invert") + self.horizontalLayout.addWidget(self.pushButton_Invert) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.tableWidget_Regions = QtWidgets.QTableWidget(parent=Dialog) + font = QtGui.QFont() + font.setFamily("Monospace") + self.tableWidget_Regions.setFont(font) + self.tableWidget_Regions.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) + self.tableWidget_Regions.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows) + self.tableWidget_Regions.setWordWrap(False) + self.tableWidget_Regions.setObjectName("tableWidget_Regions") + self.tableWidget_Regions.setColumnCount(7) + self.tableWidget_Regions.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Regions.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Regions.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Regions.setHorizontalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Regions.setHorizontalHeaderItem(3, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Regions.setHorizontalHeaderItem(4, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Regions.setHorizontalHeaderItem(5, item) + item = QtWidgets.QTableWidgetItem() + self.tableWidget_Regions.setHorizontalHeaderItem(6, item) + self.tableWidget_Regions.horizontalHeader().setStretchLastSection(True) + self.tableWidget_Regions.verticalHeader().setVisible(False) + self.tableWidget_Regions.verticalHeader().setDefaultSectionSize(16) + self.tableWidget_Regions.verticalHeader().setMinimumSectionSize(16) + self.gridLayout.addWidget(self.tableWidget_Regions, 1, 0, 1, 1) + self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Manage Scan Regions")) + self.label.setText(_translate("Dialog", "Selected regions will be deleted from the current scan")) + self.pushButton_Invert.setText(_translate("Dialog", "Invert Selection")) + self.tableWidget_Regions.setSortingEnabled(True) + item = self.tableWidget_Regions.horizontalHeaderItem(0) + item.setText(_translate("Dialog", "ID")) + item = self.tableWidget_Regions.horizontalHeaderItem(1) + item.setText(_translate("Dialog", "Start Address")) + item = self.tableWidget_Regions.horizontalHeaderItem(2) + item.setText(_translate("Dialog", "Size(bytes)")) + item = self.tableWidget_Regions.horizontalHeaderItem(3) + item.setText(_translate("Dialog", "Type")) + item = self.tableWidget_Regions.horizontalHeaderItem(4) + item.setText(_translate("Dialog", "Load Address")) + item = self.tableWidget_Regions.horizontalHeaderItem(5) + item.setText(_translate("Dialog", "Perms")) + item = self.tableWidget_Regions.horizontalHeaderItem(6) + item.setText(_translate("Dialog", "File")) diff --git a/GUI/ScanRegionsDialog.ui b/GUI/ScanRegionsDialog.ui new file mode 100644 index 00000000..0c71bcbf --- /dev/null +++ b/GUI/ScanRegionsDialog.ui @@ -0,0 +1,163 @@ + + + Dialog + + + + 0 + 0 + 724 + 568 + + + + Manage Scan Regions + + + + + + + + Selected regions will be deleted from the current scan + + + + + + + Invert Selection + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Monospace + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectRows + + + true + + + false + + + true + + + false + + + 16 + + + 16 + + + + ID + + + + + Start Address + + + + + Size(bytes) + + + + + Type + + + + + Load Address + + + + + Perms + + + + + File + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/PINCE.py b/PINCE.py index 662a4b86..ccfe8af5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -47,6 +47,7 @@ QStandardItem, QCloseEvent, QKeyEvent, + QMouseEvent, ) from PyQt6.QtWidgets import ( QApplication, @@ -138,6 +139,7 @@ from GUI.PointerScanSearchDialog import Ui_Dialog as PointerScanSearchDialog from GUI.PointerScanFilterDialog import Ui_Dialog as PointerScanFilterDialog from GUI.PointerScanWindow import Ui_MainWindow as PointerScanWindow +from GUI.ScanRegionsDialog import Ui_Dialog as ScanRegionsDialog from GUI.AbstractTableModels.HexModel import QHexModel from GUI.AbstractTableModels.AsciiModel import QAsciiModel @@ -515,6 +517,7 @@ def __init__(self): self.pushButton_NewFirstScan.clicked.connect(self.pushButton_NewFirstScan_clicked) self.pushButton_UndoScan.clicked.connect(self.pushButton_UndoScan_clicked) self.pushButton_NextScan.clicked.connect(self.pushButton_NextScan_clicked) + self.pushButton_ScanRegions.clicked.connect(self.pushButton_ScanRegions_clicked) self.scan_mode = typedefs.SCAN_MODE.NEW self.pushButton_NewFirstScan_clicked() self.comboBox_ScanScope_init() @@ -1394,6 +1397,10 @@ def pushButton_NextScan_clicked(self): self.scan_values() self.pushButton_UndoScan.setEnabled(True) + def pushButton_ScanRegions_clicked(self): + scan_regions_dialog = ScanRegionsDialogForm(self) + scan_regions_dialog.exec() + def scan_callback(self): self.progress_bar_timer.stop() self.progressBar.setValue(100) @@ -1507,7 +1514,7 @@ def tableWidget_valuesearchtable_context_menu_event(self, event: QContextMenuEve copy_selection: self.copy_valuesearchtable_selection, browse_region: lambda: self.browse_region_for_address(address), disassemble: lambda: self.disassemble_for_address(address), - delete_selection: self.delete_valuesearchtable_selection + delete_selection: self.delete_valuesearchtable_selection, } try: actions[action]() @@ -6346,6 +6353,78 @@ def filter_triggered(self) -> None: self.textEdit.setText(os.linesep.join(filter_result)) +class ScanRegionsDialogForm(QDialog, ScanRegionsDialog): + def __init__(self, parent) -> None: + super().__init__(parent) + self.setupUi(self) + regions_text = scanmem.send_command("lregions", True).decode("utf-8") + regex = re.compile(r"\[\s*(\d+)\] (\w+),\s+(\d+) bytes,\s+(\w+),\s+(\w+),\s+([rwx-]+),\s+(.+)") + data = regex.findall(regions_text) + self.tableWidget_Regions.setRowCount(len(data)) + for row, (region_id, start_address, size, region_type, load_address, perms, file) in enumerate(data): + id_item = QTableWidgetItem(region_id) + id_item.setCheckState(Qt.CheckState.Unchecked) + self.tableWidget_Regions.setItem(row, 0, id_item) + self.tableWidget_Regions.setItem(row, 1, QTableWidgetItem(start_address)) + self.tableWidget_Regions.setItem(row, 2, QTableWidgetItem(size)) + self.tableWidget_Regions.setItem(row, 3, QTableWidgetItem(region_type)) + self.tableWidget_Regions.setItem(row, 4, QTableWidgetItem(load_address)) + self.tableWidget_Regions.setItem(row, 5, QTableWidgetItem(perms)) + self.tableWidget_Regions.setItem(row, 6, QTableWidgetItem(file)) + self.tableWidget_Regions.resizeColumnsToContents() + guiutils.center_to_parent(self) + self.tableWidget_Regions.mousePressEvent_original = self.tableWidget_Regions.mousePressEvent + self.tableWidget_Regions.mousePressEvent = self.tableWidget_Regions_mouse_press_event + self.tableWidget_Regions.mouseReleaseEvent_original = self.tableWidget_Regions.mouseReleaseEvent + self.tableWidget_Regions.mouseReleaseEvent = self.tableWidget_Regions_mouse_release_event + self.tableWidget_Regions.keyPressEvent_original = self.tableWidget_Regions.keyPressEvent + self.tableWidget_Regions.keyPressEvent = self.tableWidget_Regions_key_press_event + self.pushButton_Invert.clicked.connect(self.invert_selection) + + def tableWidget_Regions_mouse_press_event(self, event: QMouseEvent) -> None: + self.tableWidget_Regions.mousePressEvent_original(event) + item = self.tableWidget_Regions.itemAt(event.pos()) + if item and item.column() == 0: + row = item.row() + self.tableWidget_Regions.selectRow(row) + + def tableWidget_Regions_mouse_release_event(self, event: QMouseEvent) -> None: + self.tableWidget_Regions.mouseReleaseEvent_original(event) + item = self.tableWidget_Regions.itemAt(event.pos()) + if item and item.column() == 0: + new_state = item.checkState() + for selected_item in self.tableWidget_Regions.selectedItems(): + if selected_item.column() == 0: + selected_item.setCheckState(new_state) + + def tableWidget_Regions_key_press_event(self, event: QKeyEvent) -> None: + if event.key() == Qt.Key.Key_Space: + current_row = self.tableWidget_Regions.currentRow() + if current_row != -1: + cur_state = self.tableWidget_Regions.item(current_row, 0).checkState() + new_state = Qt.CheckState.Unchecked if cur_state == Qt.CheckState.Checked else Qt.CheckState.Checked + for selected_item in self.tableWidget_Regions.selectedItems(): + if selected_item.column() == 0: + selected_item.setCheckState(new_state) + else: + self.tableWidget_Regions.keyPressEvent_original(event) + + def invert_selection(self) -> None: + for row in range(self.tableWidget_Regions.rowCount()): + item = self.tableWidget_Regions.item(row, 0) + cur_state = item.checkState() + new_state = Qt.CheckState.Unchecked if cur_state == Qt.CheckState.Checked else Qt.CheckState.Checked + item.setCheckState(new_state) + + def accept(self) -> None: + for row in range(self.tableWidget_Regions.rowCount()): + item = self.tableWidget_Regions.item(row, 0) + if item.checkState() == Qt.CheckState.Checked: + region_id = int(item.text()) + scanmem.send_command(f"dregion {region_id}") + return super().accept() + + def handle_exit(): global exiting exiting = 1 diff --git a/i18n/ts/it_IT.ts b/i18n/ts/it_IT.ts index 5032cbc1..f42ea358 100644 --- a/i18n/ts/it_IT.ts +++ b/i18n/ts/it_IT.ts @@ -142,6 +142,7 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin + Type @@ -289,6 +290,51 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Solve Circular References + + + Manage Scan Regions + + + + + Selected regions will be deleted from the current scan + + + + + Invert Selection + + + + + ID + + + + + Start Address + + + + + Size(bytes) + + + + + Load Address + + + + + Perms + + + + + File + + Settings @@ -950,6 +996,11 @@ Patterns at former positions have higher priority if regex is off Endianness: + + + Manage Scan Regions + + Pointer Scanner diff --git a/i18n/ts/zh_CN.ts b/i18n/ts/zh_CN.ts index 4d87aabe..56eb13eb 100644 --- a/i18n/ts/zh_CN.ts +++ b/i18n/ts/zh_CN.ts @@ -143,6 +143,7 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin 多个条目用分号(;)分隔 + Type @@ -290,6 +291,51 @@ Unchecking it makes ReferencedStringsWidget load slower but allows you to examin Solve Circular References + + + Manage Scan Regions + + + + + Selected regions will be deleted from the current scan + + + + + Invert Selection + + + + + ID + + + + + Start Address + + + + + Size(bytes) + + + + + Load Address + + + + + Perms + 权限 + + + + File + 文件 + Settings @@ -952,6 +998,11 @@ Patterns at former positions have higher priority if regex is off Endianness: 字节序: + + + Manage Scan Regions + + Pointer Scanner diff --git a/libscanmem-PINCE b/libscanmem-PINCE index 7e0fede9..e04f7963 160000 --- a/libscanmem-PINCE +++ b/libscanmem-PINCE @@ -1 +1 @@ -Subproject commit 7e0fede930534ae6c242526e7f202c56c2713538 +Subproject commit e04f7963af5c4aa3d3d32270eb1b1c1137af6637 From d909ed2d4d3c893439e85326351c4ca54f9f8c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 15 Aug 2024 14:00:23 +0300 Subject: [PATCH 474/487] Fix invalid freeze entries --- PINCE.py | 8 ++++++-- libpince/debugcore.py | 18 +++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/PINCE.py b/PINCE.py index ccfe8af5..4548cdf5 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1809,8 +1809,11 @@ def freeze(self): if debugcore.currentpid == -1: return it = QTreeWidgetItemIterator(self.treeWidget_AddressTable) - while it.value(): + while True: row = it.value() + if not row: + break + it += 1 if row.checkState(FROZEN_COL) == Qt.CheckState.Checked: vt: typedefs.ValueType = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) address = row.text(ADDR_COL).strip("P->") @@ -1819,6 +1822,8 @@ def freeze(self): freeze_type = frozen.freeze_type if typedefs.VALUE_INDEX.is_number(vt.value_index): new_value = debugcore.read_memory(address, vt.value_index, endian=vt.endian) + if new_value == None: + continue if ( freeze_type == typedefs.FREEZE_TYPE.INCREMENT and new_value > value @@ -1829,7 +1834,6 @@ def freeze(self): debugcore.write_memory(address, vt.value_index, new_value, endian=vt.endian) continue debugcore.write_memory(address, vt.value_index, value, vt.zero_terminate, vt.endian) - it += 1 def treeWidget_AddressTable_item_clicked(self, row: QTreeWidgetItem, column: int): if column == FROZEN_COL: diff --git a/libpince/debugcore.py b/libpince/debugcore.py index 2aac697a..981b0d82 100644 --- a/libpince/debugcore.py +++ b/libpince/debugcore.py @@ -781,14 +781,14 @@ def memory_handle(): def read_memory( - address, - value_index, - length=None, - zero_terminate=True, - value_repr=typedefs.VALUE_REPR.UNSIGNED, - endian=typedefs.ENDIANNESS.HOST, - mem_handle=None, -): + address: str | int, + value_index: int, + length: int = 0, + zero_terminate: bool = True, + value_repr: int = typedefs.VALUE_REPR.UNSIGNED, + endian: int = typedefs.ENDIANNESS.HOST, + mem_handle: io.BufferedReader | None = None, +) -> str | float | int | None: """Reads value from the given address Args: @@ -800,7 +800,7 @@ def read_memory( value_index is STRING. Ignored otherwise value_repr (int): Can be a member of typedefs.VALUE_REPR. Only usable with integer types endian (int): Can be a member of typedefs.ENDIANNESS - mem_handle (BinaryIO): A file handle that points to the memory file of the current process + mem_handle (io.BufferedReader, None): A file handle that points to the memory file of the current process This parameter is used for optimization, See memory_handle Don't forget to close the handle after you're done if you use this parameter manually From 49aa4ab3a8684fc3ce9f06a95abe54c9f2b367d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 17 Aug 2024 14:59:00 +0300 Subject: [PATCH 475/487] Fix selection issues of freeze column --- PINCE.py | 139 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 91 insertions(+), 48 deletions(-) diff --git a/PINCE.py b/PINCE.py index 4548cdf5..c57d0bdd 100755 --- a/PINCE.py +++ b/PINCE.py @@ -508,6 +508,10 @@ def __init__(self): guiutils.append_shortcut_to_tooltip(self.pushButton_Save, self.shortcut_save_file) # Saving the original function because super() doesn't work when we override functions like this + self.treeWidget_AddressTable.mousePressEvent_original = self.treeWidget_AddressTable.mousePressEvent + self.treeWidget_AddressTable.mousePressEvent = self.treeWidget_AddressTable_mouse_press_event + self.treeWidget_AddressTable.mouseReleaseEvent_original = self.treeWidget_AddressTable.mouseReleaseEvent + self.treeWidget_AddressTable.mouseReleaseEvent = self.treeWidget_AddressTable_mouse_release_event self.treeWidget_AddressTable.keyPressEvent_original = self.treeWidget_AddressTable.keyPressEvent self.treeWidget_AddressTable.keyPressEvent = self.treeWidget_AddressTable_key_press_event self.treeWidget_AddressTable.contextMenuEvent = self.treeWidget_AddressTable_context_menu_event @@ -548,11 +552,11 @@ def __init__(self): self.tableWidget_valuesearchtable.keyPressEvent_original = self.tableWidget_valuesearchtable.keyPressEvent self.tableWidget_valuesearchtable.keyPressEvent = self.tableWidget_valuesearchtable_key_press_event self.tableWidget_valuesearchtable.contextMenuEvent = self.tableWidget_valuesearchtable_context_menu_event - self.treeWidget_AddressTable.itemClicked.connect(self.treeWidget_AddressTable_item_clicked) self.treeWidget_AddressTable.itemDoubleClicked.connect(self.treeWidget_AddressTable_item_double_clicked) self.treeWidget_AddressTable.expanded.connect(self.resize_address_table) self.treeWidget_AddressTable.collapsed.connect(self.resize_address_table) self.treeWidget_AddressTable.header().setSortIndicatorClearable(True) + self.treeWidget_AddressTable.header().setSortIndicator(-1, Qt.SortOrder.AscendingOrder) # Clear sort indicator icons_directory = guiutils.get_icons_directory() self.pushButton_AttachProcess.setIcon(QIcon(QPixmap(icons_directory + "/monitor.png"))) self.pushButton_Open.setIcon(QIcon(QPixmap(icons_directory + "/folder.png"))) @@ -912,34 +916,51 @@ def disassemble_for_address(self, address: str): self.memory_view_window.show() self.memory_view_window.activateWindow() - def change_freeze_type(self, freeze_type): - for row in self.treeWidget_AddressTable.selectedItems(): - frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) - frozen.freeze_type = freeze_type - - if freeze_type == typedefs.FREEZE_TYPE.DEFAULT: + def change_freeze_type(self, freeze_type: int | None = None, row: QTreeWidgetItem | None = None) -> None: + if freeze_type == None: + # No type has been specified, iterate through the freeze types + # This usually happens if user clicks the freeze type text instead of the checkbox + frozen: typedefs.Frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + if frozen.freeze_type == typedefs.FREEZE_TYPE.DECREMENT: + # Decrement is the last freeze type + freeze_type = typedefs.FREEZE_TYPE.DEFAULT + else: + freeze_type = frozen.freeze_type + 1 + rows = [row] if row else self.treeWidget_AddressTable.selectedItems() + for row in rows: + frozen: typedefs.Frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + if row.checkState(FROZEN_COL) == Qt.CheckState.Checked: + frozen.freeze_type = freeze_type + if freeze_type == typedefs.FREEZE_TYPE.DEFAULT: + row.setText(FROZEN_COL, "") + row.setForeground(FROZEN_COL, QBrush()) + elif freeze_type == typedefs.FREEZE_TYPE.INCREMENT: + row.setText(FROZEN_COL, "▲") + row.setForeground(FROZEN_COL, QBrush(QColor(0, 255, 0))) + elif freeze_type == typedefs.FREEZE_TYPE.DECREMENT: + row.setText(FROZEN_COL, "▼") + row.setForeground(FROZEN_COL, QBrush(QColor(255, 0, 0))) + else: + frozen.freeze_type = typedefs.FREEZE_TYPE.DEFAULT row.setText(FROZEN_COL, "") row.setForeground(FROZEN_COL, QBrush()) - elif freeze_type == typedefs.FREEZE_TYPE.INCREMENT: - row.setText(FROZEN_COL, "▲") - row.setForeground(FROZEN_COL, QBrush(QColor(0, 255, 0))) - elif freeze_type == typedefs.FREEZE_TYPE.DECREMENT: - row.setText(FROZEN_COL, "▼") - row.setForeground(FROZEN_COL, QBrush(QColor(255, 0, 0))) def toggle_records(self, toggle_children=False): row = guiutils.get_current_item(self.treeWidget_AddressTable) - if row: + selected_items = self.treeWidget_AddressTable.selectedItems() + # If only one item is selected and then clicked while ctrl is being held + # There'll be no selected rows even with a current row present + if row and selected_items: + if not row.isSelected(): + row = selected_items[0] check_state = row.checkState(FROZEN_COL) new_state = Qt.CheckState.Checked if check_state == Qt.CheckState.Unchecked else Qt.CheckState.Unchecked - for row in self.treeWidget_AddressTable.selectedItems(): - row.setCheckState(FROZEN_COL, new_state) - self.treeWidget_AddressTable_item_clicked(row, FROZEN_COL) + for row in selected_items: + self.handle_freeze_change(row, new_state) if toggle_children: for index in range(row.childCount()): child = row.child(index) - child.setCheckState(FROZEN_COL, new_state) - self.treeWidget_AddressTable_item_clicked(child, FROZEN_COL) + self.handle_freeze_change(child, new_state) def cut_records(self): self.copy_records() @@ -1050,6 +1071,37 @@ def delete_records(self): for item in self.treeWidget_AddressTable.selectedItems(): (item.parent() or root).removeChild(item) + def treeWidget_AddressTable_mouse_press_event(self, event: QMouseEvent) -> None: + self.treeWidget_AddressTable.mousePressEvent_original(event) + item = self.treeWidget_AddressTable.itemAt(event.pos()) + column = self.treeWidget_AddressTable.columnAt(event.pos().x()) + # Qt doesn't select rows when checkboxes are clicked + # Ensure that the row is selected when frozen col is clicked + if item and column == FROZEN_COL: + item.setSelected(True) + + def treeWidget_AddressTable_mouse_release_event(self, event: QMouseEvent) -> None: + item = self.treeWidget_AddressTable.itemAt(event.pos()) + column = self.treeWidget_AddressTable.columnAt(event.pos().x()) + if item and column == FROZEN_COL: + old_state = item.checkState(FROZEN_COL) + self.treeWidget_AddressTable.mouseReleaseEvent_original(event) + new_state = item.checkState(FROZEN_COL) + item.setSelected(True) + box_clicked = old_state != new_state + current_item = self.treeWidget_AddressTable.currentItem() + if not box_clicked and new_state == Qt.CheckState.Checked: + self.change_freeze_type(row=current_item) + frozen: typedefs.Frozen = current_item.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + freeze_type = frozen.freeze_type + for selected_item in self.treeWidget_AddressTable.selectedItems(): + if box_clicked: + self.handle_freeze_change(selected_item, new_state) + elif new_state == Qt.CheckState.Checked: + self.change_freeze_type(freeze_type, selected_item) + else: + self.treeWidget_AddressTable.mouseReleaseEvent_original(event) + def treeWidget_AddressTable_key_press_event(self, event: QKeyEvent): current_row = guiutils.get_current_item(self.treeWidget_AddressTable) current_address = current_row.text(ADDR_COL) if current_row else None @@ -1069,6 +1121,7 @@ def treeWidget_AddressTable_key_press_event(self, event: QKeyEvent): self.pushButton_RefreshAdressTable_clicked, ), (QKeyCombination(Qt.KeyboardModifier.NoModifier, Qt.Key.Key_Space), self.toggle_records), + (QKeyCombination(Qt.KeyboardModifier.ShiftModifier, Qt.Key.Key_Space), self.toggle_records), ( QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Space), lambda: self.toggle_records(True), @@ -1835,35 +1888,25 @@ def freeze(self): continue debugcore.write_memory(address, vt.value_index, value, vt.zero_terminate, vt.endian) - def treeWidget_AddressTable_item_clicked(self, row: QTreeWidgetItem, column: int): - if column == FROZEN_COL: - frozen: typedefs.Frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) - is_checked = row.checkState(FROZEN_COL) == Qt.CheckState.Checked - is_frozen = frozen.enabled - - frozen_state_toggled = is_checked and not is_frozen or not is_checked and is_frozen - # this helps determine whether the user clicked checkbox or the text - # if the user clicked the text, change the freeze type - - if not frozen_state_toggled and is_checked: - # user clicked the text, iterate through the freeze type - if frozen.freeze_type == typedefs.FREEZE_TYPE.DECREMENT: - # decrement is the last freeze type - self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT) - else: - self.change_freeze_type(frozen.freeze_type + 1) - - if frozen_state_toggled: - if is_checked: - frozen.enabled = True - # reapply the freeze type, to reflect the current freeze type in the UI - # otherwise the UI will show DEFAULT freeze type after enabling instead of the actual type - self.change_freeze_type(frozen.freeze_type) - vt: typedefs.ValueType = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) - frozen.value = utils.parse_string(row.text(VALUE_COL), vt.value_index) - else: - frozen.enabled = False # it has just been toggled off - self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT) + def handle_freeze_change(self, row: QTreeWidgetItem, check_state: Qt.CheckState) -> None: + frozen: typedefs.Frozen = row.data(FROZEN_COL, Qt.ItemDataRole.UserRole) + is_checked = check_state == Qt.CheckState.Checked + frozen_state_toggled = (is_checked and not frozen.enabled) or (not is_checked and frozen.enabled) + row.setCheckState(FROZEN_COL, check_state) + # this helps determine whether the user clicked checkbox or the text + # if the user clicked the text, change the freeze type + + if frozen_state_toggled: + if is_checked: + frozen.enabled = True + # reapply the freeze type, to reflect the current freeze type in the UI + # otherwise the UI will show DEFAULT freeze type after enabling instead of the actual type + self.change_freeze_type(frozen.freeze_type, row) + vt: typedefs.ValueType = row.data(TYPE_COL, Qt.ItemDataRole.UserRole) + frozen.value = utils.parse_string(row.text(VALUE_COL), vt.value_index) + else: + frozen.enabled = False # it has just been toggled off + self.change_freeze_type(typedefs.FREEZE_TYPE.DEFAULT, row) def treeWidget_AddressTable_change_repr(self, new_repr): value_type = guiutils.get_current_item(self.treeWidget_AddressTable).data(TYPE_COL, Qt.ItemDataRole.UserRole) From 51c26113eb0c19c6a16033755208b87fbc42ba7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 17 Aug 2024 15:34:45 +0300 Subject: [PATCH 476/487] add guiutils to sphinx docs --- docs/source/guiutils.rst | 7 +++++++ docs/source/modules.rst | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 docs/source/guiutils.rst diff --git a/docs/source/guiutils.rst b/docs/source/guiutils.rst new file mode 100644 index 00000000..b60d0540 --- /dev/null +++ b/docs/source/guiutils.rst @@ -0,0 +1,7 @@ +GUI.Utils.guiutils module +========================= + +.. automodule:: GUI.Utils.guiutils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 185c8b0f..194e8bba 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -5,3 +5,11 @@ libpince :maxdepth: 4 libpince + +guiutils +======== + +.. toctree:: + :maxdepth: 4 + + guiutils From d3aeeb615bfc5339266a2a98dfa384fa2ecfc789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 17 Aug 2024 15:44:31 +0300 Subject: [PATCH 477/487] Allow workflows to be triggered on patch versions --- .github/workflows/build_docs.yml | 2 +- .github/workflows/release_appimage.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index f2614a43..924fd1f2 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -3,7 +3,7 @@ name: Deploy Sphinx Docs to GitHub Pages on: push: tags: - - "v*.*" + - "v*.*.*" workflow_dispatch: jobs: diff --git a/.github/workflows/release_appimage.yml b/.github/workflows/release_appimage.yml index f7f2a1bc..bbc8ab13 100644 --- a/.github/workflows/release_appimage.yml +++ b/.github/workflows/release_appimage.yml @@ -3,7 +3,7 @@ name: Release AppImage on: push: tags: - - "v*.*" + - "v*.*.*" jobs: build: From afbf7b4a4fb91632e68b4a35ca4d323c8f21eb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sat, 17 Aug 2024 15:59:25 +0300 Subject: [PATCH 478/487] Include both minor and patch versions in workflows --- .github/workflows/build_docs.yml | 1 + .github/workflows/release_appimage.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 924fd1f2..de9d3c8c 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -3,6 +3,7 @@ name: Deploy Sphinx Docs to GitHub Pages on: push: tags: + - "v*.*" - "v*.*.*" workflow_dispatch: diff --git a/.github/workflows/release_appimage.yml b/.github/workflows/release_appimage.yml index bbc8ab13..88757849 100644 --- a/.github/workflows/release_appimage.yml +++ b/.github/workflows/release_appimage.yml @@ -3,6 +3,7 @@ name: Release AppImage on: push: tags: + - "v*.*" - "v*.*.*" jobs: From 19c19943de50e7dbd2594afdb22bd4eda3468b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 18 Aug 2024 14:17:38 +0300 Subject: [PATCH 479/487] Add Documentation --- CONTRIBUTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d8b6765..cf6498ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,6 +8,7 @@ - [GUI](./GUI) - Contains Qt Designer forms and their respective codes along with utility functions and custom Qt classes - [media](./media) - Contains media files such as logos and icons - [tr](./tr) - Contains translation constants +- [docs](./docs) - Contains Sphinx documentation. The build files are automatically generated in the `gh-pages` branch. - [i18n](./i18n) - Contains translation files. `ts` files are created with Qt Linguist and [compile_ts.sh](./compile_ts.sh), `qm` files are created within the last section of [install.sh](./install.sh) - ### **[libpince](./libpince)** - [debugcore.py](./libpince/debugcore.py) - Everything related to communicating with GDB and debugging @@ -58,6 +59,13 @@ It could maybe replaced with something else after a refactorization About the max characters per line, I used to use PyCharm when I first started this project years ago. 120 characters is a limit brought by PyCharm, I've quit using PyCharm eventually but I think the limit makes the code look quite nice. Black suggests a limit of 88 characters, which is a bit short to be frank. So I think it's good to keep this old habit, especially considering that docstrings have also followed this rule for a long time now. This limit for docstrings however, is not strict at all. A few characters passing the limit is ok, sometimes going for a newline messes up the readability, trust your guts and decide for yourself +# Documentation +We use Google style documentation and type hints. A good example would be `get_breakpoints_in_range` function in [debugcore.py](./libpince/debugcore.py). Root folder of libpince has 100% documentation coverage so a pull request regarding libpince has to be documented. For other places, it's enough to document the parts you think that'd be confusing to read later on. You are not obliged to document everything in other places as we are also quite lax with it + +We use Sphinx to automatically generate html files from the docs and napoleon extension to convert Google style docs to reStructuredText. To test locally, `cd` into the [docs](./docs) directory and execute `sh install_sphinx.sh`. This will install Sphinx and its extensions within the venv. After this, You can modify [source files](./docs/source) and then build html files with `sh build_html.sh` to test your changes. To create source files for multiple modules automatically, `sphinx-apidoc` can be used. For single modules, you can edit the source files manually (like I did with `guiutils`) + +[build_docs.yml](.github/workflows/build_docs.yml) workflow is responsible for automatic html generation, it gets triggered automatically whenever there's a new release or manually whenever necessary. The workflow generates files within the `gh-pages` branch. It's an orphaned branch so it can be deleted without affecting the history + # UI Files You need to have [Qt6 Designer](https://pkgs.org/search/?q=designer&on=files) and [pyuic6](https://pkgs.org/search/?q=pyuic6&on=files) installed. If there are no available packages for your distro, install [pyqt6-tools](https://pypi.org/project/pyqt6-tools/) instead From 498cf6f4db1aa960e33d8791c03e4ba27bdde1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 18 Aug 2024 15:06:21 +0300 Subject: [PATCH 480/487] Update screenshots --- README.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ba6d686d..95c92fee 100644 --- a/README.md +++ b/README.md @@ -13,16 +13,10 @@ PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB) Pre-release screenshots: -![pince0](https://user-images.githubusercontent.com/5638719/219640001-b99f96a2-bffb-4b61-99a1-b187713897e2.png) -![pince1](https://user-images.githubusercontent.com/5638719/219640254-40152be1-8e97-4d26-a313-62a56b9fe1a5.png) -![pince2](https://user-images.githubusercontent.com/5638719/219706426-56c233f5-b047-4a8f-b090-ab439b98ef3a.png) -![pince3](https://user-images.githubusercontent.com/5638719/219640353-bb733c19-9ce7-4baf-81ce-4306c658fbe6.png) -![pince4](https://user-images.githubusercontent.com/5638719/219640370-a73c1796-8d2b-4d31-a63c-aa0b41f9f608.png) -![pince5](https://user-images.githubusercontent.com/5638719/219640384-62a384c8-cc32-45ef-b975-e310674302c2.png) -![pince6](https://user-images.githubusercontent.com/5638719/219640402-e03768b3-4e88-4c75-9d73-29dfbb69b3c0.png) -![pince7](https://user-images.githubusercontent.com/5638719/219640469-8b496c67-b074-4c9a-9890-9e52227cf75d.png) -![pince8](https://user-images.githubusercontent.com/5638719/219640488-61a8df17-405b-45ae-9b29-f9d214eb8571.png) -![pince9](https://user-images.githubusercontent.com/5638719/219640522-85cac1a9-e425-4b4f-abeb-a61104caa618.png) +![pince1](https://github.com/user-attachments/assets/7344c33d-3ea7-408a-8a5b-793f0b4c78ec) +![pince2](https://github.com/user-attachments/assets/271cbbe7-b588-48e0-b939-f59e82f36812) +![pince3](https://github.com/user-attachments/assets/479b4f56-7b62-4100-a3d9-3f9cd11ff5b8) +![pince4](https://github.com/user-attachments/assets/08d8a6fe-6960-481b-9b55-aa550f860dc7) # Features - **Memory scanning:** PINCE uses a specialized fork of [libscanmem](https://github.com/brkzlr/scanmem-PINCE) to scan the memory efficiently From 4d31d853618a623d7287b2269bbdca8f4183097a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 18 Aug 2024 15:24:10 +0300 Subject: [PATCH 481/487] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 95c92fee..37cf99fc 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,6 @@ PINCE is a front-end/reverse engineering tool for the GNU Project Debugger (GDB) *Disclaimer: **YOU** are responsible for your actions. PINCE does **NOT** take any responsibility for the damage caused by the users* -Pre-release screenshots: - ![pince1](https://github.com/user-attachments/assets/7344c33d-3ea7-408a-8a5b-793f0b4c78ec) ![pince2](https://github.com/user-attachments/assets/271cbbe7-b588-48e0-b939-f59e82f36812) ![pince3](https://github.com/user-attachments/assets/479b4f56-7b62-4100-a3d9-3f9cd11ff5b8) From b0047aa304f1b1e70c4117f38c81145c65235eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Sun, 18 Aug 2024 15:32:42 +0300 Subject: [PATCH 482/487] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cf6498ea..d0571dac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ - [i18n](./i18n) - Contains translation files. `ts` files are created with Qt Linguist and [compile_ts.sh](./compile_ts.sh), `qm` files are created within the last section of [install.sh](./install.sh) - ### **[libpince](./libpince)** - [debugcore.py](./libpince/debugcore.py) - Everything related to communicating with GDB and debugging - - [utils.py](./libpince/utils.py) - Contains generic utility functions such as parsing, file creation, documentation etc + - [utils.py](./libpince/utils.py) - Contains generic utility functions such as parsing, file creation, process querying etc - [typedefs.py](./libpince/typedefs.py) - Contains all constants and variable definitions - [regexes.py](./libpince/regexes.py) - Contains regexes for parsing GDB output and other things - [injection](./libpince/injection) - An example for injecting .so files From 1f4e4d1f9b6b8bc71cb993610a58267528fe36a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 22 Aug 2024 14:51:53 +0300 Subject: [PATCH 483/487] Add libegl1 dependency --- .github/workflows/build_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index de9d3c8c..07e05ee9 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | - sudo apt install libgirepository1.0-dev + sudo apt install libegl1 libgirepository1.0-dev python3 -m venv .venv/PINCE . .venv/PINCE/bin/activate pip3 install --upgrade pip From 4b9f674ac1b1f8982763d3565490a1cd06da5270 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Tue, 3 Sep 2024 20:58:05 +0100 Subject: [PATCH 484/487] Disable 'Show Float Registers' button while process is running --- PINCE.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PINCE.py b/PINCE.py index c57d0bdd..7f3af733 100755 --- a/PINCE.py +++ b/PINCE.py @@ -3136,6 +3136,8 @@ def __init__(self, parent): def initialize_register_view(self): self.pushButton_ShowFloatRegisters.clicked.connect(self.pushButton_ShowFloatRegisters_clicked) + if debugcore.currentpid == -1 or debugcore.inferior_status == typedefs.INFERIOR_STATUS.RUNNING: + self.pushButton_ShowFloatRegisters.setEnabled(False) def initialize_stack_view(self): self.stackedWidget_StackScreens.setCurrentWidget(self.StackTrace) @@ -3819,6 +3821,7 @@ def on_process_stop(self): self.activateWindow() if self.stacktrace_info_widget.isVisible(): self.stacktrace_info_widget.update_stacktrace() + self.pushButton_ShowFloatRegisters.setEnabled(True) if self.float_registers_widget.isVisible(): self.float_registers_widget.update_registers() app.processEvents() @@ -3828,6 +3831,7 @@ def on_process_stop(self): def on_process_running(self): self.setWindowTitle(tr.MV_RUNNING) + self.pushButton_ShowFloatRegisters.setEnabled(False) def add_breakpoint_condition(self, int_address, length=1): if debugcore.currentpid == -1: From 2fe921ea1b331ddef310113a6204810a7237df4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korcan=20Karaok=C3=A7u?= Date: Thu, 5 Sep 2024 00:17:38 +0300 Subject: [PATCH 485/487] Remove redundant html text --- GUI/ConsoleWidget.py | 5 ----- GUI/ConsoleWidget.ui | 7 ------- 2 files changed, 12 deletions(-) diff --git a/GUI/ConsoleWidget.py b/GUI/ConsoleWidget.py index 094c882c..31f5de53 100644 --- a/GUI/ConsoleWidget.py +++ b/GUI/ConsoleWidget.py @@ -58,11 +58,6 @@ def setupUi(self, Form): font.setBold(False) font.setItalic(False) self.textBrowser.setFont(font) - self.textBrowser.setHtml("\n" -"\n" -"


") self.textBrowser.setObjectName("textBrowser") self.verticalLayout.addWidget(self.textBrowser) self.horizontalLayout = QtWidgets.QHBoxLayout() diff --git a/GUI/ConsoleWidget.ui b/GUI/ConsoleWidget.ui index f2639453..f4b589dd 100644 --- a/GUI/ConsoleWidget.ui +++ b/GUI/ConsoleWidget.ui @@ -128,13 +128,6 @@ false
- - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Monospace'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - From 3b42936b8207d03ce20b695bb9a9ea92144b71f1 Mon Sep 17 00:00:00 2001 From: brkzlr Date: Sat, 14 Sep 2024 00:11:37 +0100 Subject: [PATCH 486/487] Add 32bits pointer support for pointer scanning --- PINCE.py | 5 +++++ install.sh | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/PINCE.py b/PINCE.py index 7f3af733..593c9e18 100755 --- a/PINCE.py +++ b/PINCE.py @@ -1664,6 +1664,11 @@ def attach_to_pid(self, pid: int): self.apply_after_init() scanmem.pid(pid) ptrscan.set_process(pid) + if debugcore.get_inferior_arch() == typedefs.INFERIOR_ARCH.ARCH_64: + ptr_size = 8 + else: + ptr_size = 4 + ptrscan.set_bitness(ptr_size) self.on_new_process() process_signals.attach.emit() diff --git a/install.sh b/install.sh index 830feb24..846b7798 100755 --- a/install.sh +++ b/install.sh @@ -99,12 +99,11 @@ install_libptrscan() { ( cd libpince/libptrscan # Source code download as we might be forced to distribute it due to licence - curl -L -O https://github.com/kekeimiku/PointerSearcher-X/archive/refs/tags/v0.7.3-dylib.tar.gz || return 1 + curl -L -O https://github.com/kekeimiku/PointerSearcher-X/archive/refs/tags/v0.7.4-dylib.tar.gz || return 1 # Actual .so and py wrapper - curl -L -o libptrscan.tar.gz https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.3-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.tar.gz || return 1 + curl -L -o libptrscan.tar.gz https://github.com/kekeimiku/PointerSearcher-X/releases/download/v0.7.4-dylib/libptrscan_pince-x86_64-unknown-linux-gnu.tar.gz || return 1 tar xf libptrscan.tar.gz --strip-components 1 || return 1 rm -f libptrscan.tar.gz - mv libptrscan_pince.so libptrscan.so cd ../.. ) || return 1 return 0 From 8548502413a637bd4015ec50b08573f354459514 Mon Sep 17 00:00:00 2001 From: Jared Ballou Date: Thu, 19 Sep 2024 12:43:40 -0400 Subject: [PATCH 487/487] Added small feature to allow changing selected addresses by specified offset --- PINCE.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/PINCE.py b/PINCE.py index 593c9e18..ff3916d0 100755 --- a/PINCE.py +++ b/PINCE.py @@ -753,6 +753,8 @@ def treeWidget_AddressTable_context_menu_event(self, event): edit_address = edit_menu.addAction(f"{header.text(ADDR_COL)}[Ctrl+Alt+Enter]") edit_type = edit_menu.addAction(f"{header.text(TYPE_COL)}[Alt+Enter]") edit_value = edit_menu.addAction(f"{header.text(VALUE_COL)}[Enter]") + edit_offset = edit_menu.addAction("Offset[Shift+Enter]") + show_hex = menu.addAction(tr.SHOW_HEX) show_dec = menu.addAction(tr.SHOW_DEC) show_unsigned = menu.addAction(tr.SHOW_UNSIGNED) @@ -839,6 +841,7 @@ def treeWidget_AddressTable_context_menu_event(self, event): edit_address: self.treeWidget_AddressTable_edit_address, edit_type: self.treeWidget_AddressTable_edit_type, edit_value: self.treeWidget_AddressTable_edit_value, + edit_offset: self.treeWidget_AddressTable_edit_offset, show_hex: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.HEX), show_dec: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.UNSIGNED), show_unsigned: lambda: self.treeWidget_AddressTable_change_repr(typedefs.VALUE_REPR.UNSIGNED), @@ -1138,6 +1141,14 @@ def treeWidget_AddressTable_key_press_event(self, event: QKeyEvent): QKeyCombination(Qt.KeyboardModifier.KeypadModifier, Qt.Key.Key_Enter), self.treeWidget_AddressTable_edit_value, ), + ( + QKeyCombination(Qt.KeyboardModifier.ShiftModifier, Qt.Key.Key_Return), + self.treeWidget_AddressTable_edit_offset, + ), + ( + QKeyCombination(Qt.KeyboardModifier.ShiftModifier, Qt.Key.Key_Enter), + self.treeWidget_AddressTable_edit_offset, + ), ( QKeyCombination(Qt.KeyboardModifier.ControlModifier, Qt.Key.Key_Return), self.treeWidget_AddressTable_edit_desc, @@ -1942,6 +1953,25 @@ def treeWidget_AddressTable_edit_value(self): debugcore.write_memory(address, vt.value_index, parsed_value, vt.zero_terminate, vt.endian) self.update_address_table() + def treeWidget_AddressTable_edit_offset(self): + row = guiutils.get_current_item(self.treeWidget_AddressTable) + if not row: + return + + dialog = InputDialogForm(self, item_list=[("Offset addresses by:",'')]) + if dialog.exec(): + offset_value = dialog.get_values() + offset_int = int(offset_value, 16) + print(offset_value) + print(offset_int) + for row in self.treeWidget_AddressTable.selectedItems(): + desc, address_expr, value_type = self.read_address_table_entries(row) + address = row.text(ADDR_COL).strip("P->") + address_int = int(address, 16) + address_new = hex(address_int + offset_int) + self.change_address_table_entries(row, desc, address_new, value_type) + self.update_address_table() + def treeWidget_AddressTable_edit_desc(self): row = guiutils.get_current_item(self.treeWidget_AddressTable) if not row: