mirror of https://github.com/mgba-emu/mgba.git
GDB Stub: allow to override GDB's handling logic of write watchpoint
Also allow to break on nonmodifying writes.
This commit is contained in:
parent
5159d389a3
commit
6f697744d1
|
@ -24,6 +24,12 @@ enum GDBStubAckState {
|
|||
GDB_ACK_OFF
|
||||
};
|
||||
|
||||
enum GDBWatchpointsBehvaior {
|
||||
GDB_WATCHPOINT_STANDARD_LOGIC = 0,
|
||||
GDB_WATCHPOINT_OVERRIDE_LOGIC,
|
||||
GDB_WATCHPOINT_OVERRIDE_LOGIC_ANY_WRITE,
|
||||
};
|
||||
|
||||
struct GDBStub {
|
||||
struct mDebugger d;
|
||||
|
||||
|
@ -40,10 +46,12 @@ struct GDBStub {
|
|||
|
||||
bool supportsSwbreak;
|
||||
bool supportsHwbreak;
|
||||
|
||||
enum GDBWatchpointsBehvaior watchpointsBehavior;
|
||||
};
|
||||
|
||||
void GDBStubCreate(struct GDBStub*);
|
||||
bool GDBStubListen(struct GDBStub*, int port, const struct Address* bindAddress);
|
||||
bool GDBStubListen(struct GDBStub*, int port, const struct Address* bindAddress, enum GDBWatchpointsBehvaior watchpointsBehavior);
|
||||
|
||||
void GDBStubHangup(struct GDBStub*);
|
||||
void GDBStubShutdown(struct GDBStub*);
|
||||
|
|
|
@ -53,7 +53,7 @@ struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) {
|
|||
case DEBUGGER_GDB:
|
||||
#ifdef USE_GDB_STUB
|
||||
GDBStubCreate(&debugger->gdb);
|
||||
GDBStubListen(&debugger->gdb, 2345, 0);
|
||||
GDBStubListen(&debugger->gdb, 2345, 0, GDB_WATCHPOINT_STANDARD_LOGIC);
|
||||
break;
|
||||
#endif
|
||||
case DEBUGGER_NONE:
|
||||
|
|
|
@ -79,15 +79,18 @@ static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReaso
|
|||
case DEBUGGER_ENTER_WATCHPOINT:
|
||||
if (info) {
|
||||
const char* type = 0;
|
||||
|
||||
if (stub->watchpointsBehavior != GDB_WATCHPOINT_STANDARD_LOGIC && info->type.wp.watchType & WATCHPOINT_WRITE) {
|
||||
// We send S05 instead of T05watch because it bypasses GDB's internal logic to check if
|
||||
// the value changed and to bypass a step into by GDB. This allows to control the change
|
||||
// logic even when using savestates which we already handle in the core debugger logic
|
||||
snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP);
|
||||
_sendMessage(stub);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (info->type.wp.watchType) {
|
||||
case WATCHPOINT_WRITE:
|
||||
if (info->type.wp.newValue == info->type.wp.oldValue) {
|
||||
if (stub->d.state == DEBUGGER_PAUSED) {
|
||||
stub->d.state = DEBUGGER_RUNNING;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Fall through
|
||||
case WATCHPOINT_WRITE_CHANGE:
|
||||
type = "watch";
|
||||
break;
|
||||
|
@ -575,7 +578,7 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) {
|
|||
stub->d.platform->setBreakpoint(stub->d.platform, &breakpoint);
|
||||
break;
|
||||
case '2':
|
||||
watchpoint.type = WATCHPOINT_WRITE_CHANGE;
|
||||
watchpoint.type = stub->watchpointsBehavior == GDB_WATCHPOINT_OVERRIDE_LOGIC_ANY_WRITE ? WATCHPOINT_WRITE : WATCHPOINT_WRITE_CHANGE;
|
||||
stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint);
|
||||
break;
|
||||
case '3':
|
||||
|
@ -763,7 +766,7 @@ void GDBStubCreate(struct GDBStub* stub) {
|
|||
stub->shouldBlock = false;
|
||||
}
|
||||
|
||||
bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress) {
|
||||
bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress, enum GDBWatchpointsBehvaior watchpointsBehavior) {
|
||||
if (!SOCKET_FAILED(stub->socket)) {
|
||||
GDBStubShutdown(stub);
|
||||
}
|
||||
|
@ -780,6 +783,7 @@ bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAdd
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
stub->watchpointsBehavior = watchpointsBehavior;
|
||||
memset(stub->memoryMapXml, 0, GDB_STUB_MAX_LINE);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -32,8 +32,12 @@ void GDBController::setBindAddress(const Address& address) {
|
|||
m_bindAddress = address;
|
||||
}
|
||||
|
||||
void GDBController::setWatchpointsBehavior(int watchpointsBehaviorId) {
|
||||
m_watchpointsBehavior = static_cast<GDBWatchpointsBehvaior>(watchpointsBehaviorId);
|
||||
}
|
||||
|
||||
void GDBController::listen() {
|
||||
if (GDBStubListen(&m_gdbStub, m_port, &m_bindAddress)) {
|
||||
if (GDBStubListen(&m_gdbStub, m_port, &m_bindAddress, m_watchpointsBehavior)) {
|
||||
if (!isAttached()) {
|
||||
attach();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
public slots:
|
||||
void setPort(ushort port);
|
||||
void setBindAddress(const Address&);
|
||||
void setWatchpointsBehavior(int watchpointsBehaviorId);
|
||||
void listen();
|
||||
|
||||
signals:
|
||||
|
@ -41,6 +42,7 @@ private:
|
|||
|
||||
ushort m_port = 2345;
|
||||
Address m_bindAddress;
|
||||
enum GDBWatchpointsBehvaior m_watchpointsBehavior = GDB_WATCHPOINT_STANDARD_LOGIC;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "GDBWindow.h"
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
|
@ -12,6 +13,7 @@
|
|||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QRadioButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "GDBController.h"
|
||||
|
@ -47,6 +49,28 @@ GDBWindow::GDBWindow(GDBController* controller, QWidget* parent)
|
|||
connect(m_bindAddressEdit, &QLineEdit::textChanged, this, &GDBWindow::bindAddressChanged);
|
||||
settingsGrid->addWidget(m_bindAddressEdit, 1, 1, Qt::AlignLeft);
|
||||
|
||||
QGroupBox* watchpointsSettings = new QGroupBox(tr("Write watchpoints behavior"));
|
||||
mainSegment->addWidget(watchpointsSettings);
|
||||
|
||||
QVBoxLayout* watchpointsSettingsLayout = new QVBoxLayout;
|
||||
watchpointsSettings->setLayout(watchpointsSettingsLayout);
|
||||
|
||||
QButtonGroup* watchpointsButtonGroup = new QButtonGroup(watchpointsSettings);
|
||||
connect(watchpointsButtonGroup, &QButtonGroup::idClicked, controller, &GDBController::setWatchpointsBehavior);
|
||||
|
||||
m_watchpointsStandardRadio = new QRadioButton(tr("Standard GDB"), watchpointsSettings);
|
||||
m_watchpointsStandardRadio->setChecked(true);
|
||||
watchpointsButtonGroup->addButton(m_watchpointsStandardRadio, GDB_WATCHPOINT_STANDARD_LOGIC);
|
||||
watchpointsSettingsLayout->addWidget(m_watchpointsStandardRadio);
|
||||
|
||||
m_watchpointsOverrideLogicRadio = new QRadioButton(tr("Internal change detection"), watchpointsSettings);
|
||||
watchpointsButtonGroup->addButton(m_watchpointsOverrideLogicRadio, GDB_WATCHPOINT_OVERRIDE_LOGIC);
|
||||
watchpointsSettingsLayout->addWidget(m_watchpointsOverrideLogicRadio);
|
||||
|
||||
m_watchpointsOverrideLogicAnyWriteRadio = new QRadioButton(tr("Break on all writes"), watchpointsSettings);
|
||||
watchpointsButtonGroup->addButton(m_watchpointsOverrideLogicAnyWriteRadio, GDB_WATCHPOINT_OVERRIDE_LOGIC_ANY_WRITE);
|
||||
watchpointsSettingsLayout->addWidget(m_watchpointsOverrideLogicAnyWriteRadio);
|
||||
|
||||
QHBoxLayout* buttons = new QHBoxLayout;
|
||||
|
||||
m_startStopButton = new QPushButton;
|
||||
|
@ -92,6 +116,9 @@ void GDBWindow::bindAddressChanged(const QString& bindAddressString) {
|
|||
void GDBWindow::started() {
|
||||
m_portEdit->setEnabled(false);
|
||||
m_bindAddressEdit->setEnabled(false);
|
||||
m_watchpointsStandardRadio->setEnabled(false);
|
||||
m_watchpointsOverrideLogicRadio->setEnabled(false);
|
||||
m_watchpointsOverrideLogicAnyWriteRadio->setEnabled(false);
|
||||
m_startStopButton->setText(tr("Stop"));
|
||||
m_breakButton->setEnabled(true);
|
||||
disconnect(m_startStopButton, &QAbstractButton::clicked, m_gdbController, &GDBController::listen);
|
||||
|
@ -102,6 +129,9 @@ void GDBWindow::started() {
|
|||
void GDBWindow::stopped() {
|
||||
m_portEdit->setEnabled(true);
|
||||
m_bindAddressEdit->setEnabled(true);
|
||||
m_watchpointsStandardRadio->setEnabled(true);
|
||||
m_watchpointsOverrideLogicRadio->setEnabled(true);
|
||||
m_watchpointsOverrideLogicAnyWriteRadio->setEnabled(true);
|
||||
m_startStopButton->setText(tr("Start"));
|
||||
m_breakButton->setEnabled(false);
|
||||
disconnect(m_startStopButton, &QAbstractButton::clicked, m_gdbController, &DebuggerController::detach);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QRadioButton;
|
||||
|
||||
namespace QGBA {
|
||||
|
||||
|
@ -34,6 +35,9 @@ private:
|
|||
|
||||
QLineEdit* m_portEdit;
|
||||
QLineEdit* m_bindAddressEdit;
|
||||
QRadioButton* m_watchpointsStandardRadio;
|
||||
QRadioButton* m_watchpointsOverrideLogicRadio;
|
||||
QRadioButton* m_watchpointsOverrideLogicAnyWriteRadio;
|
||||
QPushButton* m_startStopButton;
|
||||
QPushButton* m_breakButton;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue