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();
|
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
|
||||||
|
|| item.data.type == BreakpointByFunction)
|
||||||
&& !response.module.isEmpty())
|
&& !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;
|
||||||
|
@@ -59,6 +59,10 @@ enum BreakpointType
|
|||||||
BreakpointAtThrow,
|
BreakpointAtThrow,
|
||||||
BreakpointAtCatch,
|
BreakpointAtCatch,
|
||||||
BreakpointAtMain,
|
BreakpointAtMain,
|
||||||
|
BreakpointAtFork,
|
||||||
|
BreakpointAtExec,
|
||||||
|
BreakpointAtVFork,
|
||||||
|
BreakpointAtSysCall,
|
||||||
Watchpoint
|
Watchpoint
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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,19 +140,25 @@ 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>"
|
||||||
|
"<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>");
|
"</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(); }
|
||||||
@@ -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)
|
||||||
|
@@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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)) {
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user