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();
}
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;

View File

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

View File

@@ -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("<html><head/><body><p>Determines how the path is specified when setting breakpoints:</p><ul>"
"<li><i>Use Engine Default</i>: Preferred setting of the debugger engine.</li>"
"<li><i>Use Full Path</i>: Pass full path, avoiding ambiguities should files of the same "
"name exist in several modules. This is the engine default for CDB and LLDB.</li>"
"<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>");
tr("<html><head/><body><p>Determines how the path is specified "
"when setting breakpoints:</p><ul>"
"<li><i>Use Engine Default</i>: Preferred setting of the "
"debugger engine.</li>"
"<li><i>Use Full Path</i>: Pass full path, avoiding ambiguities "
"should files of the same name exist in several modules. "
"This is the engine default for CDB and LLDB.</li>"
"<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.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)

View File

@@ -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
};

View File

@@ -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)) {

View File

@@ -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);

View File

@@ -44,6 +44,7 @@
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QPointer>
#include <QtCore/QProcess>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QSettings>
@@ -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);