forked from qt-creator/qt-creator
debugger: add possibility to break on fork, vfork, exec, syscall
This commit is contained in:
@@ -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;
|
||||
|
@@ -59,6 +59,10 @@ enum BreakpointType
|
||||
BreakpointAtThrow,
|
||||
BreakpointAtCatch,
|
||||
BreakpointAtMain,
|
||||
BreakpointAtFork,
|
||||
BreakpointAtExec,
|
||||
BreakpointAtVFork,
|
||||
BreakpointAtSysCall,
|
||||
Watchpoint
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
};
|
||||
|
||||
|
@@ -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)) {
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user