diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 84860b07547..6526ffddfe8 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1029,26 +1029,29 @@ bool BreakHandler::needsChange(BreakpointId id) const return it->needsChange(); } -void BreakHandler::setResponse(BreakpointId id, const BreakpointResponse &response, bool takeOver) +void BreakHandler::setResponse(BreakpointId id, + const BreakpointResponse &response, bool takeOver) { Iterator it = m_storage.find(id); QTC_ASSERT(it != m_storage.end(), return); BreakpointItem &item = it.value(); item.response = response; item.destroyMarker(); - // Take over corrected values from response + // Take over corrected values from response. if (takeOver) { if (item.data.type == BreakpointByFileAndLine && response.correctedLineNumber > 0) item.data.lineNumber = response.correctedLineNumber; - if ((item.data.type == BreakpointByFileAndLine || item.data.type == BreakpointByFunction) - && !response.module.isEmpty()) + if ((item.data.type == BreakpointByFileAndLine + || item.data.type == BreakpointByFunction) + && !response.module.isEmpty()) item.data.module = response.module; } updateMarker(id); } -void BreakHandler::setBreakpointData(BreakpointId id, const BreakpointParameters &data) +void BreakHandler::setBreakpointData(BreakpointId id, + const BreakpointParameters &data) { Iterator it = m_storage.find(id); QTC_ASSERT(it != m_storage.end(), return); @@ -1178,6 +1181,18 @@ QString BreakHandler::BreakpointItem::toToolTip() const case BreakpointAtCatch: t = tr("Breakpoint at \"catch\""); break; + case BreakpointAtFork: + t = tr("Breakpoint at \"fork\""); + break; + case BreakpointAtExec: + t = tr("Breakpoint at \"exec\""); + break; + case BreakpointAtVFork: + t = tr("Breakpoint at \"vfork\""); + break; + case BreakpointAtSysCall: + t = tr("Breakpoint at \"syscall\""); + break; case BreakpointAtMain: t = tr("Breakpoint at Function \"main()\""); break; diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h index a6513b81a3f..6c85561cfa4 100644 --- a/src/plugins/debugger/breakpoint.h +++ b/src/plugins/debugger/breakpoint.h @@ -59,6 +59,10 @@ enum BreakpointType BreakpointAtThrow, BreakpointAtCatch, BreakpointAtMain, + BreakpointAtFork, + BreakpointAtExec, + BreakpointAtVFork, + BreakpointAtSysCall, Watchpoint }; diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index 9a5415fc279..355a822299a 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -123,7 +123,10 @@ BreakpointDialog::BreakpointDialog(unsigned engineCapabilities, QWidget *parent) m_ui.setupUi(this); QStringList types; types << tr("File and Line Number") << tr("Function Name") << tr("Address") - << tr("throw") << tr("catch") << tr("Function \"main()\"") + << tr("throw") << tr("catch") + << tr("Function \"main()\"") + << tr("fork") << tr("exec") + << tr("vfork") << tr("syscall") << tr("Address (Watchpoint)"); QTC_ASSERT(types.size() == Watchpoint, return; ) m_ui.comboBoxType->addItems(types); @@ -137,20 +140,26 @@ BreakpointDialog::BreakpointDialog(unsigned engineCapabilities, QWidget *parent) m_ui.lineEditModule->setToolTip(moduleToolTip); const QString commandToolTip = tr("Debugger command to be executed when the breakpoint is hit.\n" - "gdb allows for specifying a sequence of commands separated by the delimiter '\\n'."); + "gdb allows for specifying a sequence of commands separated by " + "the delimiter '\\n'."); m_ui.lineEditCommand->setToolTip(commandToolTip); m_ui.labelCommand->setToolTip(commandToolTip); m_ui.spinBoxIgnoreCount->setMinimum(0); m_ui.spinBoxIgnoreCount->setMaximum(2147483647); const QString pathToolTip = - tr("

Determines how the path is specified when setting breakpoints:

"); + tr("

Determines how the path is specified " + "when setting breakpoints:

"); m_ui.labelUseFullPath->setToolTip(pathToolTip); m_ui.comboBoxPathUsage->setToolTip(pathToolTip); } @@ -328,6 +337,10 @@ void BreakpointDialog::typeChanged(int) case BreakpointAtThrow: case BreakpointAtCatch: case BreakpointAtMain: + case BreakpointAtFork: + case BreakpointAtExec: + case BreakpointAtVFork: + case BreakpointAtSysCall: break; case BreakpointByAddress: case Watchpoint: @@ -351,6 +364,10 @@ void BreakpointDialog::typeChanged(int) break; case BreakpointAtThrow: case BreakpointAtCatch: + case BreakpointAtFork: + case BreakpointAtExec: + case BreakpointAtVFork: + case BreakpointAtSysCall: clearOtherParts(AllConditionParts|ModulePart|TracePointPart); setPartsEnabled(AllConditionParts|TracePointPart); break; @@ -384,10 +401,11 @@ bool BreakpointDialog::showDialog(BreakpointParameters *data) } // Dialog allowing changing properties of multiple breakpoints at a time. -class MultiBreakPointsDialog : public QDialog { +class MultiBreakPointsDialog : public QDialog +{ Q_OBJECT public: - explicit MultiBreakPointsDialog(unsigned engineCapabilities = AllDebuggerCapabilities, QWidget *parent = 0); + MultiBreakPointsDialog(unsigned engineCapabilities, QWidget *parent = 0); QString condition() const { return m_ui.lineEditCondition->text(); } int ignoreCount() const { return m_ui.spinBoxIgnoreCount->value(); } @@ -403,7 +421,7 @@ private: Ui::BreakCondition m_ui; }; -MultiBreakPointsDialog::MultiBreakPointsDialog(unsigned engineCapabilities,QWidget *parent) : +MultiBreakPointsDialog::MultiBreakPointsDialog(unsigned engineCapabilities, QWidget *parent) : QDialog(parent) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); @@ -577,10 +595,6 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) QAction *addBreakpointAction = new QAction(tr("Add Breakpoint..."), this); - QAction *breakAtThrowAction = - new QAction(tr("Set Breakpoint at \"throw\""), this); - QAction *breakAtCatchAction = - new QAction(tr("Set Breakpoint at \"catch\""), this); menu.addAction(addBreakpointAction); menu.addAction(deleteAction); @@ -592,11 +606,6 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) //menu.addAction(deleteByFileAction); menu.addSeparator(); menu.addAction(synchronizeAction); - if (engineCapabilities & BreakOnThrowAndCatchCapability) { - menu.addSeparator(); - menu.addAction(breakAtThrowAction); - menu.addAction(breakAtCatchAction); - } menu.addSeparator(); menu.addAction(debuggerCore()->action(UseToolTipsInBreakpointsView)); menu.addAction(debuggerCore()->action(UseAddressInBreakpointsView)); @@ -627,10 +636,6 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) setBreakpointsEnabled(selectedIds, !enabled); else if (act == addBreakpointAction) addBreakpoint(); - else if (act == breakAtThrowAction) - handler->appendBreakpoint(BreakpointParameters(BreakpointAtThrow)); - else if (act == breakAtCatchAction) - handler->appendBreakpoint(BreakpointParameters(BreakpointAtCatch)); } void BreakWindow::setBreakpointsEnabled(const BreakpointIds &ids, bool enabled) diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index cf3775f7b26..3a9e6b46906 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -171,12 +171,13 @@ enum DebuggerCapabilities BreakOnThrowAndCatchCapability = 0x200, BreakConditionCapability = 0x400, //!< Conditional Breakpoints BreakModuleCapability = 0x800, //!< Breakpoint specification includes module - TracePointCapability = 0x1000, //!< Breakpoint specification includes module + TracePointCapability = 0x1000, ReturnFromFunctionCapability = 0x2000, CreateFullBacktraceCapability = 0x4000, AddWatcherCapability = 0x8000, WatchpointCapability = 0x10000, ShowModuleSymbolsCapability = 0x20000, + CatchCapability = 0x40000, //!< fork, vfork, syscall AllDebuggerCapabilities = 0xFFFFFFFF }; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 3e0a8591764..ffe0230cbb8 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1873,7 +1873,8 @@ unsigned GdbEngine::debuggerCapabilities() const | CreateFullBacktraceCapability | WatchpointCapability | AddWatcherCapability - | ShowModuleSymbolsCapability; + | ShowModuleSymbolsCapability + | CatchCapability; if (startParameters().startMode == AttachCore) return caps; @@ -2314,6 +2315,16 @@ void GdbEngine::attemptAdjustBreakpointLocation(BreakpointId id) CB(handleInfoLine), id); } +void GdbEngine::handleCatchInsert(const GdbResponse &response) +{ + BreakHandler *handler = breakHandler(); + BreakpointId id(response.cookie.toInt()); + if (response.resultClass == GdbResultDone) { + handler->notifyBreakpointInsertOk(id); + attemptAdjustBreakpointLocation(id); + } +} + void GdbEngine::handleBreakInsert1(const GdbResponse &response) { BreakHandler *handler = breakHandler(); @@ -2644,12 +2655,33 @@ void GdbEngine::insertBreakpoint(BreakpointId id) BreakHandler *handler = breakHandler(); QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/); handler->notifyBreakpointInsertProceeding(id); - if (handler->type(id) == Watchpoint) { + BreakpointType type = handler->type(id); + if (type == Watchpoint) { postCommand("watch " + addressSpec(handler->address(id)), NeedsStop | RebuildBreakpointModel, CB(handleWatchInsert), id); return; } + if (type == BreakpointAtFork) { + postCommand("catch fork", NeedsStop | RebuildBreakpointModel, + CB(handleCatchInsert), id); + return; + } + if (type == BreakpointAtVFork) { + postCommand("catch vfork", NeedsStop | RebuildBreakpointModel, + CB(handleCatchInsert), id); + return; + } + if (type == BreakpointAtExec) { + postCommand("catch exec", NeedsStop | RebuildBreakpointModel, + CB(handleCatchInsert), id); + return; + } + if (type == BreakpointAtSysCall) { + postCommand("catch syscall", NeedsStop | RebuildBreakpointModel, + CB(handleCatchInsert), id); + return; + } QByteArray cmd = "xxx"; if (handler->isTracepoint(id)) { diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 82a9c9fa0ad..95ff06c09a3 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -370,6 +370,7 @@ private: ////////// View & Data Stuff ////////// void handleBreakInfo(const GdbResponse &response); void handleBreakThreadSpec(const GdbResponse &response); void handleWatchInsert(const GdbResponse &response); + void handleCatchInsert(const GdbResponse &response); void handleInfoLine(const GdbResponse &response); void extractDataFromInfoBreak(const QString &output, BreakpointId); void updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkpt); diff --git a/tests/manual/gdbdebugger/simple/simple_gdbtest_app.cpp b/tests/manual/gdbdebugger/simple/simple_gdbtest_app.cpp index 9fa776d6168..64415556c93 100644 --- a/tests/manual/gdbdebugger/simple/simple_gdbtest_app.cpp +++ b/tests/manual/gdbdebugger/simple/simple_gdbtest_app.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -2397,6 +2398,16 @@ void testBoostSharedPtr() #endif } +void testFork() +{ + QProcess proc; + proc.start("/bin/ls"); + proc.waitForFinished(); + QByteArray ba = proc.readAllStandardError(); + ba.append('x'); + ba.append('x'); +} + int main(int argc, char *argv[]) { testPrivate(); @@ -2493,7 +2504,7 @@ int main(int argc, char *argv[]) testBoostOptional(); testBoostSharedPtr(); - //*(int *)0 = 0; + testFork(); testQObject(argc, argv);