debugger: support for per-thread breakpoints

This commit is contained in:
hjk
2010-04-29 18:36:18 +02:00
parent 2b250985ce
commit 24d1fbd15b
10 changed files with 219 additions and 65 deletions

View File

@@ -14,32 +14,65 @@
<item> <item>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="labelFileName">
<property name="text">
<string>File name:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditFileName"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelLineNumber">
<property name="text">
<string>Line number:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditLineNumber"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelFunction">
<property name="text">
<string>Function:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditFunction"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelCondition"> <widget class="QLabel" name="labelCondition">
<property name="text"> <property name="text">
<string>Condition:</string> <string>Condition:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="3" column="1">
<widget class="QLineEdit" name="lineEditCondition"/> <widget class="QLineEdit" name="lineEditCondition"/>
</item> </item>
<item row="1" column="0"> <item row="4" column="0">
<widget class="QLabel" name="labelIgnoreCount"> <widget class="QLabel" name="labelIgnoreCount">
<property name="text"> <property name="text">
<string>Ignore count:</string> <string>Ignore count:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="4" column="1">
<widget class="QSpinBox" name="spinBoxIgnoreCount"> <widget class="QLineEdit" name="lineEditIgnoreCount"/>
<property name="layoutDirection"> </item>
<enum>Qt::LeftToRight</enum> <item row="5" column="0">
</property> <widget class="QLabel" name="labelThreadSpec">
<property name="maximum"> <property name="text">
<number>999999999</number> <string>Thread specification:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineEditThreadSpec"/>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View File

@@ -247,6 +247,8 @@ QString BreakpointData::toToolTip() const
<< "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>" << "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Ignore Count:") << "<tr><td>" << BreakHandler::tr("Ignore Count:")
<< "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>" << "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>"
<< "<tr><td>" << BreakHandler::tr("Thread Specification:")
<< "</td><td>" << threadSpec << "</td><td>" << bpThreadSpec << "</td></tr>"
<< "</table></body></html>"; << "</table></body></html>";
return rc; return rc;
} }
@@ -268,7 +270,9 @@ QString BreakpointData::toString() const
<< BreakHandler::tr("Condition:") << BreakHandler::tr("Condition:")
<< condition << " -- " << bpCondition << '\n' << condition << " -- " << bpCondition << '\n'
<< BreakHandler::tr("Ignore Count:") << BreakHandler::tr("Ignore Count:")
<< ignoreCount << " -- " << bpIgnoreCount << '\n'; << ignoreCount << " -- " << bpIgnoreCount << '\n'
<< BreakHandler::tr("Thread Specification:")
<< threadSpec << " -- " << bpThreadSpec << '\n';
return rc; return rc;
} }
@@ -320,7 +324,7 @@ BreakHandler::~BreakHandler()
int BreakHandler::columnCount(const QModelIndex &parent) const int BreakHandler::columnCount(const QModelIndex &parent) const
{ {
return parent.isValid() ? 0 : 7; return parent.isValid() ? 0 : 8;
} }
int BreakHandler::rowCount(const QModelIndex &parent) const int BreakHandler::rowCount(const QModelIndex &parent) const
@@ -418,6 +422,8 @@ void BreakHandler::saveBreakpoints()
map.insert(QLatin1String("condition"), data->condition); map.insert(QLatin1String("condition"), data->condition);
if (!data->ignoreCount.isEmpty()) if (!data->ignoreCount.isEmpty())
map.insert(QLatin1String("ignorecount"), data->ignoreCount); map.insert(QLatin1String("ignorecount"), data->ignoreCount);
if (!data->threadSpec.isEmpty())
map.insert(QLatin1String("threadspec"), data->threadSpec);
if (!data->enabled) if (!data->enabled)
map.insert(QLatin1String("disabled"), QLatin1String("1")); map.insert(QLatin1String("disabled"), QLatin1String("1"));
if (data->useFullPath) if (data->useFullPath)
@@ -447,6 +453,9 @@ void BreakHandler::loadBreakpoints()
v = map.value(QLatin1String("ignorecount")); v = map.value(QLatin1String("ignorecount"));
if (v.isValid()) if (v.isValid())
data->ignoreCount = v.toString().toLatin1(); data->ignoreCount = v.toString().toLatin1();
v = map.value(QLatin1String("threadspec"));
if (v.isValid())
data->threadSpec = v.toString().toLatin1();
v = map.value(QLatin1String("funcname")); v = map.value(QLatin1String("funcname"));
if (v.isValid()) if (v.isValid())
data->funcName = v.toString(); data->funcName = v.toString();
@@ -476,6 +485,7 @@ void BreakHandler::resetBreakpoints()
data->bpCorrectedLineNumber.clear(); data->bpCorrectedLineNumber.clear();
data->bpCondition.clear(); data->bpCondition.clear();
data->bpIgnoreCount.clear(); data->bpIgnoreCount.clear();
data->bpThreadSpec.clear();
data->bpAddress.clear(); data->bpAddress.clear();
// Keep marker data if it was primary. // Keep marker data if it was primary.
if (data->markerFileName() != data->fileName) if (data->markerFileName() != data->fileName)
@@ -502,7 +512,7 @@ QVariant BreakHandler::headerData(int section,
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
static QString headers[] = { static QString headers[] = {
tr("Number"), tr("Function"), tr("File"), tr("Line"), tr("Number"), tr("Function"), tr("File"), tr("Line"),
tr("Condition"), tr("Ignore"), tr("Address") tr("Condition"), tr("Ignore"), tr("Threads"), tr("Address")
}; };
return headers[section]; return headers[section];
} }
@@ -538,6 +548,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
const QString str = data->pending ? data->funcName : data->bpFuncName; const QString str = data->pending ? data->funcName : data->bpFuncName;
return str.isEmpty() ? empty : str; return str.isEmpty() ? empty : str;
} }
if (role == Qt::UserRole + 1)
return data->funcName;
break; break;
case 2: case 2:
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
@@ -553,6 +565,8 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
} }
if (role == Qt::UserRole) if (role == Qt::UserRole)
return data->useFullPath; return data->useFullPath;
if (role == Qt::UserRole + 1)
return data->fileName;
break; break;
case 3: case 3:
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
@@ -562,19 +576,36 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
const QString str = data->pending ? data->lineNumber : data->bpLineNumber; const QString str = data->pending ? data->lineNumber : data->bpLineNumber;
return str.isEmpty() ? empty : str; return str.isEmpty() ? empty : str;
} }
if (role == Qt::UserRole + 1)
return data->lineNumber;
break; break;
case 4: case 4:
if (role == Qt::DisplayRole) if (role == Qt::DisplayRole)
return data->pending ? data->condition : data->bpCondition; return data->pending ? data->condition : data->bpCondition;
if (role == Qt::ToolTipRole) if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit if this condition is met."); return tr("Breakpoint will only be hit if this condition is met.");
if (role == Qt::UserRole + 1)
return data->condition;
break; break;
case 5: case 5:
if (role == Qt::DisplayRole) if (role == Qt::DisplayRole)
return data->pending ? data->ignoreCount : data->bpIgnoreCount; return data->pending ? data->ignoreCount : data->bpIgnoreCount;
if (role == Qt::ToolTipRole) if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit after being ignored so many times."); return tr("Breakpoint will only be hit after being ignored so many times.");
if (role == Qt::UserRole + 1)
return data->ignoreCount;
case 6: case 6:
if (role == Qt::DisplayRole) {
if (data->pending)
return !data->threadSpec.isEmpty() ? data->threadSpec : tr("(all)");
else
return !data->bpThreadSpec.isEmpty() ? data->bpThreadSpec : tr("(all)");
}
if (role == Qt::ToolTipRole)
return tr("Breakpoint will only be hit in the specified thread(s).");
if (role == Qt::UserRole + 1)
return data->threadSpec;
case 7:
if (role == Qt::DisplayRole) if (role == Qt::DisplayRole)
return data->bpAddress; return data->bpAddress;
break; break;
@@ -597,38 +628,73 @@ Qt::ItemFlags BreakHandler::flags(const QModelIndex &mi) const
bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role) bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int role)
{ {
if (role != Qt::EditRole)
return false;
BreakpointData *data = at(mi.row()); BreakpointData *data = at(mi.row());
if (role == Qt::UserRole + 1) {
if (data->enabled != value.toBool()) {
toggleBreakpointEnabled(data);
layoutChanged();
}
return true;
}
if (role == Qt::UserRole + 2) {
if (data->useFullPath != value.toBool()) {
data->useFullPath = value.toBool();
layoutChanged();
}
return true;
}
//if (role != Qt::EditRole)
// return false;
switch (mi.column()) { switch (mi.column()) {
case 0: { case 1: {
if (data->enabled != value.toBool()) { QString val = value.toString();
toggleBreakpointEnabled(data); if (data->funcName != val) {
dataChanged(mi, mi); data->funcName = val;
layoutChanged();
} }
return true; return true;
} }
case 2: { case 2: {
if (data->useFullPath != value.toBool()) { QString val = value.toString();
data->useFullPath = value.toBool(); if (data->fileName != val) {
dataChanged(mi, mi); data->fileName = val;
layoutChanged();
}
return true;
}
case 3: {
QByteArray val = value.toString().toLatin1();
if (data->lineNumber != val) {
data->lineNumber = val;
layoutChanged();
} }
return true; return true;
} }
case 4: { case 4: {
QString val = value.toString(); QByteArray val = value.toString().toLatin1();
if (val != data->condition) { if (val != data->condition) {
data->condition = val.toLatin1(); data->condition = val;
dataChanged(mi, mi); layoutChanged();
} }
return true; return true;
} }
case 5: { case 5: {
QString val = value.toString(); QByteArray val = value.toString().toLatin1();
if (val != data->ignoreCount) { if (val != data->ignoreCount) {
data->ignoreCount = val.toLatin1(); data->ignoreCount = val;
dataChanged(mi, mi); layoutChanged();
}
return true;
}
case 6: {
QByteArray val = value.toString().toLatin1();
if (val != data->threadSpec) {
data->threadSpec = val;
layoutChanged();
} }
return true; return true;
} }

View File

@@ -80,6 +80,7 @@ public:
QByteArray condition; // Condition associated with breakpoint. QByteArray condition; // Condition associated with breakpoint.
QByteArray ignoreCount; // Ignore count associated with breakpoint. QByteArray ignoreCount; // Ignore count associated with breakpoint.
QByteArray lineNumber; // Line in source file. QByteArray lineNumber; // Line in source file.
QByteArray threadSpec; // Thread specification.
QString funcName; // Name of containing function. QString funcName; // Name of containing function.
bool useFullPath; // Should we use the full path when setting the bp? bool useFullPath; // Should we use the full path when setting the bp?
@@ -91,6 +92,7 @@ public:
QString bpFullName; // Full file name acknowledged by the debugger engine. QString bpFullName; // Full file name acknowledged by the debugger engine.
QByteArray bpLineNumber; // Line number acknowledged by the debugger engine. QByteArray bpLineNumber; // Line number acknowledged by the debugger engine.
QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine. QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine.
QByteArray bpThreadSpec; // Thread spec acknowledged by the debugger engine.
QString bpFuncName; // Function name acknowledged by the debugger engine. QString bpFuncName; // Function name acknowledged by the debugger engine.
QByteArray bpAddress; // Address acknowledged by the debugger engine. QByteArray bpAddress; // Address acknowledged by the debugger engine.
bool bpMultiple; // Happens in constructors/gdb. bool bpMultiple; // Happens in constructors/gdb.

View File

@@ -103,7 +103,7 @@ BreakWindow::BreakWindow(Debugger::DebuggerManager *manager)
void BreakWindow::showAddressColumn(bool on) void BreakWindow::showAddressColumn(bool on)
{ {
setColumnHidden(6, !on); setColumnHidden(7, !on);
} }
static QModelIndexList normalizeIndexes(const QModelIndexList &list) static QModelIndexList normalizeIndexes(const QModelIndexList &list)
@@ -133,6 +133,13 @@ void BreakWindow::resizeEvent(QResizeEvent *ev)
QTreeView::resizeEvent(ev); QTreeView::resizeEvent(ev);
} }
void BreakWindow::mouseDoubleClickEvent(QMouseEvent *ev)
{
QModelIndex indexUnderMouse = indexAt(ev->pos());
if (indexUnderMouse.isValid())
editBreakpoint(QModelIndexList() << indexUnderMouse);
}
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
{ {
QMenu menu; QMenu menu;
@@ -185,9 +192,9 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
alwaysAdjustAction->setCheckable(true); alwaysAdjustAction->setCheckable(true);
alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents); alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);
QAction *editConditionAction = QAction *editBreakpointAction =
new QAction(tr("Edit Condition..."), &menu); new QAction(tr("Edit Breakpoint..."), &menu);
editConditionAction->setEnabled(si.size() > 0); editBreakpointAction->setEnabled(si.size() > 0);
QAction *synchronizeAction = QAction *synchronizeAction =
new QAction(tr("Synchronize Breakpoints"), &menu); new QAction(tr("Synchronize Breakpoints"), &menu);
@@ -223,7 +230,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
new QAction(tr("Set Breakpoint at \"catch\""), this); new QAction(tr("Set Breakpoint at \"catch\""), this);
menu.addAction(deleteAction); menu.addAction(deleteAction);
menu.addAction(editConditionAction); menu.addAction(editBreakpointAction);
menu.addAction(toggleEnabledAction); menu.addAction(toggleEnabledAction);
menu.addAction(pathAction); menu.addAction(pathAction);
menu.addSeparator(); menu.addSeparator();
@@ -261,8 +268,8 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
resizeColumnsToContents(); resizeColumnsToContents();
else if (act == alwaysAdjustAction) else if (act == alwaysAdjustAction)
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents); setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
else if (act == editConditionAction) else if (act == editBreakpointAction)
editConditions(si); editBreakpoint(si);
else if (act == synchronizeAction) else if (act == synchronizeAction)
emit breakpointSynchronizationRequested(); emit breakpointSynchronizationRequested();
else if (act == toggleEnabledAction) else if (act == toggleEnabledAction)
@@ -284,7 +291,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled) void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled)
{ {
foreach (const QModelIndex &idx, list) foreach (const QModelIndex &idx, list)
model()->setData(idx, enabled); model()->setData(idx, enabled, Qt::UserRole + 1);
emit breakpointSynchronizationRequested(); emit breakpointSynchronizationRequested();
} }
@@ -292,7 +299,7 @@ void BreakWindow::setBreakpointsFullPath(const QModelIndexList &list, bool fullp
{ {
foreach (const QModelIndex &idx, list) { foreach (const QModelIndex &idx, list) {
QModelIndex idx2 = idx.sibling(idx.row(), 2); QModelIndex idx2 = idx.sibling(idx.row(), 2);
model()->setData(idx2, fullpath); model()->setData(idx2, fullpath, Qt::UserRole + 2);
} }
emit breakpointSynchronizationRequested(); emit breakpointSynchronizationRequested();
} }
@@ -320,7 +327,7 @@ void BreakWindow::deleteBreakpoints(QList<int> list)
setCurrentIndex(model()->index(row, 0)); setCurrentIndex(model()->index(row, 0));
} }
void BreakWindow::editConditions(const QModelIndexList &list) void BreakWindow::editBreakpoint(const QModelIndexList &list)
{ {
QDialog dlg(this); QDialog dlg(this);
Ui::BreakCondition ui; Ui::BreakCondition ui;
@@ -330,15 +337,36 @@ void BreakWindow::editConditions(const QModelIndexList &list)
QModelIndex idx = list.front(); QModelIndex idx = list.front();
int row = idx.row(); int row = idx.row();
dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row)); dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row));
ui.lineEditCondition->setText(model()->data(idx.sibling(row, 4)).toString()); int role = Qt::UserRole + 1;
ui.spinBoxIgnoreCount->setValue(model()->data(idx.sibling(row, 5)).toInt()); ui.lineEditFunction->hide();
ui.labelFunction->hide();
ui.lineEditFileName->hide();
ui.labelFileName->hide();
ui.lineEditLineNumber->hide();
ui.labelLineNumber->hide();
//ui.lineEditFunction->setText(
// model()->data(idx.sibling(row, 1), role).toString());
//ui.lineEditFileName->setText(
// model()->data(idx.sibling(row, 2), role).toString());
//ui.lineEditLineNumber->setText(
// model()->data(idx.sibling(row, 3), role).toString());
ui.lineEditCondition->setText(
model()->data(idx.sibling(row, 4), role).toString());
ui.lineEditIgnoreCount->setText(
model()->data(idx.sibling(row, 5), role).toString());
ui.lineEditThreadSpec->setText(
model()->data(idx.sibling(row, 6), role).toString());
if (dlg.exec() == QDialog::Rejected) if (dlg.exec() == QDialog::Rejected)
return; return;
foreach (const QModelIndex &idx, list) { foreach (const QModelIndex &idx, list) {
//model()->setData(idx.sibling(idx.row(), 1), ui.lineEditFunction->text());
//model()->setData(idx.sibling(idx.row(), 2), ui.lineEditFileName->text());
//model()->setData(idx.sibling(idx.row(), 3), ui.lineEditLineNumber->text());
model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text()); model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
model()->setData(idx.sibling(idx.row(), 5), ui.spinBoxIgnoreCount->value()); model()->setData(idx.sibling(idx.row(), 5), ui.lineEditIgnoreCount->text());
model()->setData(idx.sibling(idx.row(), 6), ui.lineEditThreadSpec->text());
} }
emit breakpointSynchronizationRequested(); emit breakpointSynchronizationRequested();
} }

View File

@@ -1,4 +1,5 @@
/************************************************************************** /**************************************************************************
QT_END_NAMESPACE
** **
** This file is part of Qt Creator ** This file is part of Qt Creator
** **
@@ -65,11 +66,12 @@ protected:
void resizeEvent(QResizeEvent *ev); void resizeEvent(QResizeEvent *ev);
void contextMenuEvent(QContextMenuEvent *ev); void contextMenuEvent(QContextMenuEvent *ev);
void keyPressEvent(QKeyEvent *ev); void keyPressEvent(QKeyEvent *ev);
void mouseDoubleClickEvent(QMouseEvent *ev);
private: private:
void deleteBreakpoints(const QModelIndexList &list); void deleteBreakpoints(const QModelIndexList &list);
void deleteBreakpoints(QList<int> rows); void deleteBreakpoints(QList<int> rows);
void editConditions(const QModelIndexList &list); void editBreakpoint(const QModelIndexList &list);
void setBreakpointsEnabled(const QModelIndexList &list, bool enabled); void setBreakpointsEnabled(const QModelIndexList &list, bool enabled);
void setBreakpointsFullPath(const QModelIndexList &list, bool fullpath); void setBreakpointsFullPath(const QModelIndexList &list, bool fullpath);

View File

@@ -102,6 +102,7 @@ bool synchronizeBreakPoints(CIDebugControl* debugControl,
// Take over rest as is // Take over rest as is
nbd->bpCondition = nbd->condition; nbd->bpCondition = nbd->condition;
nbd->bpIgnoreCount = nbd->ignoreCount; nbd->bpIgnoreCount = nbd->ignoreCount;
nbd->bpThreadSpec = nbd->threadSpec;
nbd->bpFileName = nbd->fileName; nbd->bpFileName = nbd->fileName;
nbd->bpLineNumber = nbd->lineNumber; nbd->bpLineNumber = nbd->lineNumber;
nbd->bpFuncName = nbd->funcName; nbd->bpFuncName = nbd->funcName;

View File

@@ -443,7 +443,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
int progress = m_progress->progressValue(); int progress = m_progress->progressValue();
m_progress->setProgressValue(qMin(70, progress + 1)); m_progress->setProgressValue(qMin(70, progress + 1));
QByteArray id = result.findChild("id").data(); QByteArray id = result.findChild("id").data();
showStatusMessage(tr("Thread group %1 created.").arg(_(id)), 1000); showStatusMessage(tr("Thread group %1 created").arg(_(id)), 1000);
int pid = id.toInt(); int pid = id.toInt();
if (pid != inferiorPid()) if (pid != inferiorPid())
handleInferiorPidChanged(pid); handleInferiorPidChanged(pid);
@@ -789,7 +789,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
} else if (state() == InferiorRunningRequested_Kill) { } else if (state() == InferiorRunningRequested_Kill) {
debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)")); debugMessage(_("RUNNING REQUESTED; POSTPONING INTERRUPT (KILL PENDING)"));
} else if (state() == InferiorRunning) { } else if (state() == InferiorRunning) {
showStatusMessage(tr("Stopping temporarily."), 1000); showStatusMessage(tr("Stopping temporarily"), 1000);
interruptInferiorTemporarily(); interruptInferiorTemporarily();
} else { } else {
qDebug() << "ATTEMPTING TO QUEUE COMMAND IN INAPPROPRIATE STATE" << state(); qDebug() << "ATTEMPTING TO QUEUE COMMAND IN INAPPROPRIATE STATE" << state();
@@ -802,7 +802,7 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
void GdbEngine::flushQueuedCommands() void GdbEngine::flushQueuedCommands()
{ {
showStatusMessage(tr("Processing queued commands."), 1000); showStatusMessage(tr("Processing queued commands"), 1000);
while (!m_commandsToRunOnTemporaryBreak.isEmpty()) { while (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst(); GdbCommand cmd = m_commandsToRunOnTemporaryBreak.takeFirst();
debugMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' ' debugMessage(_("RUNNING QUEUED COMMAND " + cmd.command + ' '
@@ -908,7 +908,7 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
debugMessage(_("APPLYING WORKAROUND #1")); debugMessage(_("APPLYING WORKAROUND #1"));
showMessageBox(QMessageBox::Critical, showMessageBox(QMessageBox::Critical,
tr("Executable failed"), QString::fromLocal8Bit(msg)); tr("Executable failed"), QString::fromLocal8Bit(msg));
showStatusMessage(tr("Process failed to start.")); showStatusMessage(tr("Process failed to start"));
shutdown(); shutdown();
} else if (msg == "\"finish\" not meaningful in the outermost frame.") { } else if (msg == "\"finish\" not meaningful in the outermost frame.") {
// Handle a case known to appear on gdb 6.4 symbianelf when // Handle a case known to appear on gdb 6.4 symbianelf when
@@ -1091,7 +1091,7 @@ void GdbEngine::handleExecJumpToLine(const GdbResponse &response)
// ~"242\t x *= 2;" // ~"242\t x *= 2;"
//109^done" //109^done"
setState(InferiorStopped); setState(InferiorStopped);
showStatusMessage(tr("Jumped. Stopped.")); showStatusMessage(tr("Jumped. Stopped"));
QByteArray output = response.data.findChild("logstreamoutput").data(); QByteArray output = response.data.findChild("logstreamoutput").data();
if (output.isEmpty()) if (output.isEmpty())
return; return;
@@ -1117,7 +1117,7 @@ void GdbEngine::handleExecJumpToLine(const GdbResponse &response)
// // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"} // // file="main.cpp",fullname="/tmp/g/main.cpp",line="37"}
// QTC_ASSERT(state() == InferiorStopping, qDebug() << state()) // QTC_ASSERT(state() == InferiorStopping, qDebug() << state())
// setState(InferiorStopped); // setState(InferiorStopped);
// showStatusMessage(tr("Function reached. Stopped.")); // showStatusMessage(tr("Function reached. Stopped"));
// GdbMi frame = response.data.findChild("frame"); // GdbMi frame = response.data.findChild("frame");
// StackFrame f = parseStackFrame(frame, 0); // StackFrame f = parseStackFrame(frame, 0);
// gotoLocation(f, true); // gotoLocation(f, true);
@@ -1389,7 +1389,7 @@ void GdbEngine::handleStop1(const GdbMi &data)
if (reason == "breakpoint-hit") { if (reason == "breakpoint-hit") {
QByteArray bpNumber = data.findChild("bkptno").data(); QByteArray bpNumber = data.findChild("bkptno").data();
QByteArray threadId = data.findChild("thread-id").data(); QByteArray threadId = data.findChild("thread-id").data();
showStatusMessage(tr("Stopped at breakpoint %1 in thread %2.") showStatusMessage(tr("Stopped at breakpoint %1 in thread %2")
.arg(_(bpNumber), _(threadId))); .arg(_(bpNumber), _(threadId)));
} else { } else {
QString reasontr = tr("Stopped: \"%1\"").arg(_(reason)); QString reasontr = tr("Stopped: \"%1\"").arg(_(reason));
@@ -2115,6 +2115,8 @@ void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt
if (ba.startsWith('<') && ba.endsWith('>')) if (ba.startsWith('<') && ba.endsWith('>'))
ba = ba.mid(1, ba.size() - 2); ba = ba.mid(1, ba.size() - 2);
data->bpFuncName = _(ba); data->bpFuncName = _(ba);
} else if (child.hasName("thread")) {
data->bpThreadSpec = child.data();
} }
} }
// This field is not present. Contents needs to be parsed from // This field is not present. Contents needs to be parsed from
@@ -2145,9 +2147,8 @@ QString GdbEngine::breakLocation(const QString &file) const
return where; return where;
} }
QByteArray GdbEngine::breakpointLocation(int index) QByteArray GdbEngine::breakpointLocation(const BreakpointData *data)
{ {
const BreakpointData *data = manager()->breakHandler()->at(index);
if (!data->funcName.isEmpty()) if (!data->funcName.isEmpty())
return data->funcName.toLatin1(); return data->funcName.toLatin1();
// In this case, data->funcName is something like '*0xdeadbeef' // In this case, data->funcName is something like '*0xdeadbeef'
@@ -2162,21 +2163,28 @@ QByteArray GdbEngine::breakpointLocation(int index)
void GdbEngine::sendInsertBreakpoint(int index) void GdbEngine::sendInsertBreakpoint(int index)
{ {
const BreakpointData *data = manager()->breakHandler()->at(index);
// Set up fallback in case of pending breakpoints which aren't handled // Set up fallback in case of pending breakpoints which aren't handled
// by the MI interface. // by the MI interface.
QByteArray cmd; QByteArray cmd;
if (m_isMacGdb) if (m_isMacGdb) {
cmd = "-break-insert -l -1 -f "; cmd = "-break-insert -l -1 -f ";
else if (m_gdbAdapter->isTrkAdapter()) } else if (m_gdbAdapter->isTrkAdapter()) {
cmd = "-break-insert -h -f "; cmd = "-break-insert -h -f ";
else if (m_gdbVersion >= 60800) } else if (m_gdbVersion >= 70000) {
cmd = "-break-insert ";
if (!data->threadSpec.isEmpty())
cmd += "-p " + data->threadSpec;
cmd += " -f ";
} else if (m_gdbVersion >= 60800) {
// Probably some earlier version would work as well. // Probably some earlier version would work as well.
cmd = "-break-insert -f "; cmd = "-break-insert -f ";
else } else {
cmd = "-break-insert "; cmd = "-break-insert ";
}
//if (!data->condition.isEmpty()) //if (!data->condition.isEmpty())
// cmd += "-c " + data->condition + ' '; // cmd += "-c " + data->condition + ' ';
cmd += breakpointLocation(index); cmd += breakpointLocation(data);
postCommand(cmd, NeedsStop | RebuildBreakpointModel, postCommand(cmd, NeedsStop | RebuildBreakpointModel,
CB(handleBreakInsert1), index); CB(handleBreakInsert1), index);
} }
@@ -2184,17 +2192,16 @@ void GdbEngine::sendInsertBreakpoint(int index)
void GdbEngine::handleBreakInsert1(const GdbResponse &response) void GdbEngine::handleBreakInsert1(const GdbResponse &response)
{ {
int index = response.cookie.toInt(); int index = response.cookie.toInt();
BreakHandler *handler = manager()->breakHandler(); BreakpointData *data = manager()->breakHandler()->at(index);
if (response.resultClass == GdbResultDone) { if (response.resultClass == GdbResultDone) {
// Interesting only on Mac? // Interesting only on Mac?
BreakpointData *data = handler->at(index);
GdbMi bkpt = response.data.findChild("bkpt"); GdbMi bkpt = response.data.findChild("bkpt");
breakpointDataFromOutput(data, bkpt); breakpointDataFromOutput(data, bkpt);
} else { } else {
// Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)" // Some versions of gdb like "GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)"
// know how to do pending breakpoints using CLI but not MI. So try // know how to do pending breakpoints using CLI but not MI. So try
// again with MI. // again with MI.
QByteArray cmd = "break " + breakpointLocation(index); QByteArray cmd = "break " + breakpointLocation(data);
postCommand(cmd, NeedsStop | RebuildBreakpointModel, postCommand(cmd, NeedsStop | RebuildBreakpointModel,
CB(handleBreakInsert2), index); CB(handleBreakInsert2), index);
} }
@@ -2524,7 +2531,8 @@ void GdbEngine::attemptBreakpointSynchronization()
else // Because gdb won't do both changes at a time anyway. else // Because gdb won't do both changes at a time anyway.
if (data->ignoreCount != data->bpIgnoreCount) { if (data->ignoreCount != data->bpIgnoreCount) {
// Update ignorecount if needed. // Update ignorecount if needed.
postCommand("ignore " + data->bpNumber + ' ' + data->ignoreCount, QByteArray ic = QByteArray::number(data->ignoreCount.toInt());
postCommand("ignore " + data->bpNumber + ' ' + ic,
NeedsStop | RebuildBreakpointModel, NeedsStop | RebuildBreakpointModel,
CB(handleBreakIgnore), data->bpNumber.toInt()); CB(handleBreakIgnore), data->bpNumber.toInt());
continue; continue;
@@ -2536,6 +2544,17 @@ void GdbEngine::attemptBreakpointSynchronization()
data->bpEnabled = false; data->bpEnabled = false;
continue; continue;
} }
if (data->threadSpec != data->bpThreadSpec && !data->bpThreadSpec.isEmpty()) {
// The only way to change this seems to be to re-set the bp completely.
//qDebug() << "FIXME: THREAD: " << data->threadSpec << data->bpThreadSpec;
//data->bpThreadSpec = data->threadSpec;
if (!data->bpNumber.isEmpty()) {
postCommand("-break-delete " + data->bpNumber,
NeedsStop | RebuildBreakpointModel);
sendInsertBreakpoint(index);
}
continue;
}
if (data->bpAddress.startsWith("0x") if (data->bpAddress.startsWith("0x")
&& data->bpCorrectedLineNumber.isEmpty()) { && data->bpCorrectedLineNumber.isEmpty()) {
// Prevent endless loop. // Prevent endless loop.
@@ -3958,7 +3977,7 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr
} }
if (!foundPython) { if (!foundPython) {
debugMessage(_("UNSUPPORTED GDB %1 DOES NOT HAVE PYTHON.").arg(m_gdb)); debugMessage(_("UNSUPPORTED GDB %1 DOES NOT HAVE PYTHON.").arg(m_gdb));
showStatusMessage(_("Gdb at %1 does not have python.").arg(m_gdb)); showStatusMessage(_("Gdb at %1 does not have python").arg(m_gdb));
} }
#endif #endif

View File

@@ -348,7 +348,7 @@ private: ////////// View & Data Stuff //////////
void handleInfoLine(const GdbResponse &response); void handleInfoLine(const GdbResponse &response);
void extractDataFromInfoBreak(const QString &output, BreakpointData *data); void extractDataFromInfoBreak(const QString &output, BreakpointData *data);
void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt); void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt);
QByteArray breakpointLocation(int index); QByteArray breakpointLocation(const BreakpointData *data);
void sendInsertBreakpoint(int index); void sendInsertBreakpoint(int index);
QString breakLocation(const QString &file) const; QString breakLocation(const QString &file) const;
void reloadBreakListInternal(); void reloadBreakListInternal();

View File

@@ -114,8 +114,8 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
//qDebug() << "SECOND CHUNK: " << out; //qDebug() << "SECOND CHUNK: " << out;
int pos = out.indexOf("data="); int pos = out.indexOf("data=");
if (pos != 0) { if (pos != 0) {
qDebug() << "DISCARDING JUNK AT BEGIN OF RESPONSE: " debugMessage(_("DISCARDING JUNK AT BEGIN OF RESPONSE: "
<< out.left(pos); + out.left(pos)));
out = out.mid(pos); out = out.mid(pos);
} }
GdbMi all; GdbMi all;

View File

@@ -1218,10 +1218,13 @@ public:
void run() void run()
{ {
int j = 2;
++j;
for (int i = 0; i != 100000; ++i) { for (int i = 0; i != 100000; ++i) {
//sleep(1); //sleep(1);
std::cerr << m_id; std::cerr << m_id;
} }
std::cerr << j;
} }
private: private:
@@ -1655,7 +1658,7 @@ int main(int argc, char *argv[])
#endif #endif
testQStringList(); testQStringList();
testStruct(); testStruct();
//testThreads(); testQThread();
testQVariant1(); testQVariant1();
testQVariant2(); testQVariant2();
testQVariant3(); testQVariant3();