debugger: add possibility to break on fork, vfork, exec, syscall

This commit is contained in:
hjk
2011-03-04 19:26:11 +01:00
parent 486c1ddb18
commit 822bbff157
7 changed files with 104 additions and 35 deletions

View File

@@ -1029,26 +1029,29 @@ bool BreakHandler::needsChange(BreakpointId id) const
return it->needsChange(); 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); Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return); QTC_ASSERT(it != m_storage.end(), return);
BreakpointItem &item = it.value(); BreakpointItem &item = it.value();
item.response = response; item.response = response;
item.destroyMarker(); item.destroyMarker();
// Take over corrected values from response // Take over corrected values from response.
if (takeOver) { if (takeOver) {
if (item.data.type == BreakpointByFileAndLine if (item.data.type == BreakpointByFileAndLine
&& response.correctedLineNumber > 0) && response.correctedLineNumber > 0)
item.data.lineNumber = response.correctedLineNumber; item.data.lineNumber = response.correctedLineNumber;
if ((item.data.type == BreakpointByFileAndLine || item.data.type == BreakpointByFunction) if ((item.data.type == BreakpointByFileAndLine
&& !response.module.isEmpty()) || item.data.type == BreakpointByFunction)
&& !response.module.isEmpty())
item.data.module = response.module; item.data.module = response.module;
} }
updateMarker(id); updateMarker(id);
} }
void BreakHandler::setBreakpointData(BreakpointId id, const BreakpointParameters &data) void BreakHandler::setBreakpointData(BreakpointId id,
const BreakpointParameters &data)
{ {
Iterator it = m_storage.find(id); Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return); QTC_ASSERT(it != m_storage.end(), return);
@@ -1178,6 +1181,18 @@ QString BreakHandler::BreakpointItem::toToolTip() const
case BreakpointAtCatch: case BreakpointAtCatch:
t = tr("Breakpoint at \"catch\""); t = tr("Breakpoint at \"catch\"");
break; 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: case BreakpointAtMain:
t = tr("Breakpoint at Function \"main()\""); t = tr("Breakpoint at Function \"main()\"");
break; break;

View File

@@ -59,6 +59,10 @@ enum BreakpointType
BreakpointAtThrow, BreakpointAtThrow,
BreakpointAtCatch, BreakpointAtCatch,
BreakpointAtMain, BreakpointAtMain,
BreakpointAtFork,
BreakpointAtExec,
BreakpointAtVFork,
BreakpointAtSysCall,
Watchpoint Watchpoint
}; };

View File

@@ -123,7 +123,10 @@ BreakpointDialog::BreakpointDialog(unsigned engineCapabilities, QWidget *parent)
m_ui.setupUi(this); m_ui.setupUi(this);
QStringList types; QStringList types;
types << tr("File and Line Number") << tr("Function Name") << tr("Address") 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)"); << tr("Address (Watchpoint)");
QTC_ASSERT(types.size() == Watchpoint, return; ) QTC_ASSERT(types.size() == Watchpoint, return; )
m_ui.comboBoxType->addItems(types); m_ui.comboBoxType->addItems(types);
@@ -137,20 +140,26 @@ BreakpointDialog::BreakpointDialog(unsigned engineCapabilities, QWidget *parent)
m_ui.lineEditModule->setToolTip(moduleToolTip); m_ui.lineEditModule->setToolTip(moduleToolTip);
const QString commandToolTip = const QString commandToolTip =
tr("Debugger command to be executed when the breakpoint is hit.\n" 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.lineEditCommand->setToolTip(commandToolTip);
m_ui.labelCommand->setToolTip(commandToolTip); m_ui.labelCommand->setToolTip(commandToolTip);
m_ui.spinBoxIgnoreCount->setMinimum(0); m_ui.spinBoxIgnoreCount->setMinimum(0);
m_ui.spinBoxIgnoreCount->setMaximum(2147483647); m_ui.spinBoxIgnoreCount->setMaximum(2147483647);
const QString pathToolTip = const QString pathToolTip =
tr("<html><head/><body><p>Determines how the path is specified when setting breakpoints:</p><ul>" tr("<html><head/><body><p>Determines how the path is specified "
"<li><i>Use Engine Default</i>: Preferred setting of the debugger engine.</li>" "when setting breakpoints:</p><ul>"
"<li><i>Use Full Path</i>: Pass full path, avoiding ambiguities should files of the same " "<li><i>Use Engine Default</i>: Preferred setting of the "
"name exist in several modules. This is the engine default for CDB and LLDB.</li>" "debugger engine.</li>"
"<li><i>Use File Name</i>: Pass the file name only. This is useful " "<li><i>Use Full Path</i>: Pass full path, avoiding ambiguities "
"when using a source tree whose location does not match the one used when building the modules. " "should files of the same name exist in several modules. "
"It is the engine default for gdb as using full paths can be slow with this engine.</li>" "This is the engine default for CDB and LLDB.</li>"
"</ul></body></html>"); "<li><i>Use File Name</i>: Pass the file name only. This is "
"useful when using a source tree whose location does "
"not match the one used when building the modules. "
"It is the engine default for gdb as using full paths can "
"be slow with this engine.</li>"
"</ul></body></html>");
m_ui.labelUseFullPath->setToolTip(pathToolTip); m_ui.labelUseFullPath->setToolTip(pathToolTip);
m_ui.comboBoxPathUsage->setToolTip(pathToolTip); m_ui.comboBoxPathUsage->setToolTip(pathToolTip);
} }
@@ -328,6 +337,10 @@ void BreakpointDialog::typeChanged(int)
case BreakpointAtThrow: case BreakpointAtThrow:
case BreakpointAtCatch: case BreakpointAtCatch:
case BreakpointAtMain: case BreakpointAtMain:
case BreakpointAtFork:
case BreakpointAtExec:
case BreakpointAtVFork:
case BreakpointAtSysCall:
break; break;
case BreakpointByAddress: case BreakpointByAddress:
case Watchpoint: case Watchpoint:
@@ -351,6 +364,10 @@ void BreakpointDialog::typeChanged(int)
break; break;
case BreakpointAtThrow: case BreakpointAtThrow:
case BreakpointAtCatch: case BreakpointAtCatch:
case BreakpointAtFork:
case BreakpointAtExec:
case BreakpointAtVFork:
case BreakpointAtSysCall:
clearOtherParts(AllConditionParts|ModulePart|TracePointPart); clearOtherParts(AllConditionParts|ModulePart|TracePointPart);
setPartsEnabled(AllConditionParts|TracePointPart); setPartsEnabled(AllConditionParts|TracePointPart);
break; break;
@@ -384,10 +401,11 @@ bool BreakpointDialog::showDialog(BreakpointParameters *data)
} }
// Dialog allowing changing properties of multiple breakpoints at a time. // Dialog allowing changing properties of multiple breakpoints at a time.
class MultiBreakPointsDialog : public QDialog { class MultiBreakPointsDialog : public QDialog
{
Q_OBJECT Q_OBJECT
public: public:
explicit MultiBreakPointsDialog(unsigned engineCapabilities = AllDebuggerCapabilities, QWidget *parent = 0); MultiBreakPointsDialog(unsigned engineCapabilities, QWidget *parent = 0);
QString condition() const { return m_ui.lineEditCondition->text(); } QString condition() const { return m_ui.lineEditCondition->text(); }
int ignoreCount() const { return m_ui.spinBoxIgnoreCount->value(); } int ignoreCount() const { return m_ui.spinBoxIgnoreCount->value(); }
@@ -403,7 +421,7 @@ private:
Ui::BreakCondition m_ui; Ui::BreakCondition m_ui;
}; };
MultiBreakPointsDialog::MultiBreakPointsDialog(unsigned engineCapabilities,QWidget *parent) : MultiBreakPointsDialog::MultiBreakPointsDialog(unsigned engineCapabilities, QWidget *parent) :
QDialog(parent) QDialog(parent)
{ {
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -577,10 +595,6 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
QAction *addBreakpointAction = QAction *addBreakpointAction =
new QAction(tr("Add Breakpoint..."), this); 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(addBreakpointAction);
menu.addAction(deleteAction); menu.addAction(deleteAction);
@@ -592,11 +606,6 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
//menu.addAction(deleteByFileAction); //menu.addAction(deleteByFileAction);
menu.addSeparator(); menu.addSeparator();
menu.addAction(synchronizeAction); menu.addAction(synchronizeAction);
if (engineCapabilities & BreakOnThrowAndCatchCapability) {
menu.addSeparator();
menu.addAction(breakAtThrowAction);
menu.addAction(breakAtCatchAction);
}
menu.addSeparator(); menu.addSeparator();
menu.addAction(debuggerCore()->action(UseToolTipsInBreakpointsView)); menu.addAction(debuggerCore()->action(UseToolTipsInBreakpointsView));
menu.addAction(debuggerCore()->action(UseAddressInBreakpointsView)); menu.addAction(debuggerCore()->action(UseAddressInBreakpointsView));
@@ -627,10 +636,6 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
setBreakpointsEnabled(selectedIds, !enabled); setBreakpointsEnabled(selectedIds, !enabled);
else if (act == addBreakpointAction) else if (act == addBreakpointAction)
addBreakpoint(); 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) void BreakWindow::setBreakpointsEnabled(const BreakpointIds &ids, bool enabled)

View File

@@ -171,12 +171,13 @@ enum DebuggerCapabilities
BreakOnThrowAndCatchCapability = 0x200, BreakOnThrowAndCatchCapability = 0x200,
BreakConditionCapability = 0x400, //!< Conditional Breakpoints BreakConditionCapability = 0x400, //!< Conditional Breakpoints
BreakModuleCapability = 0x800, //!< Breakpoint specification includes module BreakModuleCapability = 0x800, //!< Breakpoint specification includes module
TracePointCapability = 0x1000, //!< Breakpoint specification includes module TracePointCapability = 0x1000,
ReturnFromFunctionCapability = 0x2000, ReturnFromFunctionCapability = 0x2000,
CreateFullBacktraceCapability = 0x4000, CreateFullBacktraceCapability = 0x4000,
AddWatcherCapability = 0x8000, AddWatcherCapability = 0x8000,
WatchpointCapability = 0x10000, WatchpointCapability = 0x10000,
ShowModuleSymbolsCapability = 0x20000, ShowModuleSymbolsCapability = 0x20000,
CatchCapability = 0x40000, //!< fork, vfork, syscall
AllDebuggerCapabilities = 0xFFFFFFFF AllDebuggerCapabilities = 0xFFFFFFFF
}; };

View File

@@ -1873,7 +1873,8 @@ unsigned GdbEngine::debuggerCapabilities() const
| CreateFullBacktraceCapability | CreateFullBacktraceCapability
| WatchpointCapability | WatchpointCapability
| AddWatcherCapability | AddWatcherCapability
| ShowModuleSymbolsCapability; | ShowModuleSymbolsCapability
| CatchCapability;
if (startParameters().startMode == AttachCore) if (startParameters().startMode == AttachCore)
return caps; return caps;
@@ -2314,6 +2315,16 @@ void GdbEngine::attemptAdjustBreakpointLocation(BreakpointId id)
CB(handleInfoLine), 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) void GdbEngine::handleBreakInsert1(const GdbResponse &response)
{ {
BreakHandler *handler = breakHandler(); BreakHandler *handler = breakHandler();
@@ -2644,12 +2655,33 @@ void GdbEngine::insertBreakpoint(BreakpointId id)
BreakHandler *handler = breakHandler(); BreakHandler *handler = breakHandler();
QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/); QTC_ASSERT(handler->state(id) == BreakpointInsertRequested, /**/);
handler->notifyBreakpointInsertProceeding(id); handler->notifyBreakpointInsertProceeding(id);
if (handler->type(id) == Watchpoint) { BreakpointType type = handler->type(id);
if (type == Watchpoint) {
postCommand("watch " + addressSpec(handler->address(id)), postCommand("watch " + addressSpec(handler->address(id)),
NeedsStop | RebuildBreakpointModel, NeedsStop | RebuildBreakpointModel,
CB(handleWatchInsert), id); CB(handleWatchInsert), id);
return; 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"; QByteArray cmd = "xxx";
if (handler->isTracepoint(id)) { if (handler->isTracepoint(id)) {

View File

@@ -370,6 +370,7 @@ private: ////////// View & Data Stuff //////////
void handleBreakInfo(const GdbResponse &response); void handleBreakInfo(const GdbResponse &response);
void handleBreakThreadSpec(const GdbResponse &response); void handleBreakThreadSpec(const GdbResponse &response);
void handleWatchInsert(const GdbResponse &response); void handleWatchInsert(const GdbResponse &response);
void handleCatchInsert(const GdbResponse &response);
void handleInfoLine(const GdbResponse &response); void handleInfoLine(const GdbResponse &response);
void extractDataFromInfoBreak(const QString &output, BreakpointId); void extractDataFromInfoBreak(const QString &output, BreakpointId);
void updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkpt); void updateBreakpointDataFromOutput(BreakpointId id, const GdbMi &bkpt);

View File

@@ -44,6 +44,7 @@
#include <QtCore/QList> #include <QtCore/QList>
#include <QtCore/QMap> #include <QtCore/QMap>
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtCore/QProcess>
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QSettings> #include <QtCore/QSettings>
@@ -2397,6 +2398,16 @@ void testBoostSharedPtr()
#endif #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[]) int main(int argc, char *argv[])
{ {
testPrivate(); testPrivate();
@@ -2493,7 +2504,7 @@ int main(int argc, char *argv[])
testBoostOptional(); testBoostOptional();
testBoostSharedPtr(); testBoostSharedPtr();
//*(int *)0 = 0; testFork();
testQObject(argc, argv); testQObject(argc, argv);