Commit 59b2aac1 authored by Friedemann Kleint's avatar Friedemann Kleint

Debugger: Add 'command[s]' to breakpoints, polish BP dialogs.

Add commands (CDB, gdb with '\n' delimiter for multiple),
rearrange dialogs, make ignore count a spin box.
parent 9c48cd3b
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Debugger::Internal::BreakCondition</class>
<widget class="QDialog" name="BreakCondition">
<widget class="QDialog" name="Debugger::Internal::BreakCondition">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>283</width>
<height>141</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelCondition">
<property name="text">
<string>Condition:</string>
<string>&amp;Condition:</string>
</property>
<property name="buddy">
<cstring>lineEditCondition</cstring>
</property>
</widget>
</item>
......@@ -18,17 +29,23 @@
<item row="1" column="0">
<widget class="QLabel" name="labelIgnoreCount">
<property name="text">
<string>Ignore count:</string>
<string>&amp;Ignore count:</string>
</property>
<property name="buddy">
<cstring>spinBoxIgnoreCount</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditIgnoreCount"/>
<widget class="QSpinBox" name="spinBoxIgnoreCount"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelThreadSpec">
<property name="text">
<string>Thread specification:</string>
<string>&amp;Thread specification:</string>
</property>
<property name="buddy">
<cstring>lineEditThreadSpec</cstring>
</property>
</widget>
</item>
......@@ -54,7 +71,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BreakCondition</receiver>
<receiver>Debugger::Internal::BreakCondition</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
......@@ -70,7 +87,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BreakCondition</receiver>
<receiver>Debugger::Internal::BreakCondition</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
......
......@@ -276,6 +276,8 @@ void BreakHandler::saveBreakpoints()
map.insert(_("tracepoint"), one);
if (!data.module.isEmpty())
map.insert(_("module"), data.module);
if (!data.command.isEmpty())
map.insert(_("command"), data.command);
list.append(map);
}
debuggerCore()->setSessionValue("Breakpoints", list);
......@@ -328,6 +330,9 @@ void BreakHandler::loadBreakpoints()
v = map.value(_("module"));
if (v.isValid())
data.module = v.toString();
v = map.value(_("command"));
if (v.isValid())
data.command = v.toString();
appendBreakpoint(data);
}
//qDebug() << "LOADED BREAKPOINTS" << this << list.size();
......@@ -1102,6 +1107,8 @@ bool BreakHandler::BreakpointItem::needsChange() const
return true;
if (data.threadSpec != response.threadSpec)
return true;
if (data.command != response.command)
return true;
return false;
}
......@@ -1221,6 +1228,12 @@ QString BreakHandler::BreakpointItem::toToolTip() const
formatAddress(str, data.address);
str << "</td><td>";
formatAddress(str, response.address);
if (!data.command.isEmpty() || !response.command.isEmpty()) {
str << "</td></tr>"
<< "<tr><td>" << tr("Command:")
<< "</td><td>" << data.command
<< "</td><td>" << response.command<< "</td></tr>";
}
if (!data.condition.isEmpty() || !response.condition.isEmpty()) {
str << "</td></tr>"
<< "<tr><td>" << tr("Condition:")
......
......@@ -64,7 +64,8 @@ bool BreakpointParameters::equals(const BreakpointParameters &rhs) const
&& threadSpec == rhs.threadSpec
&& functionName == rhs.functionName
&& tracepoint == rhs.tracepoint
&& module == rhs.module;
&& module == rhs.module
&& command == rhs.command;
}
bool BreakpointParameters::conditionsMatch(const QByteArray &other) const
......@@ -90,6 +91,7 @@ QString BreakpointParameters::toString() const
ts << " UseFullPath: " << useFullPath;
ts << " Tracepoint: " << tracepoint;
ts << " Module: " << module;
ts << " Command: " << command;
return result;
}
......
......@@ -100,6 +100,7 @@ public:
int threadSpec; // Thread specification.
QString functionName;
QString module; // module for file name
QString command; // command to execute
bool tracepoint;
};
......
This diff is collapsed.
......@@ -106,6 +106,7 @@ private:
BreakpointDialog::BreakpointDialog(QWidget *parent)
: QDialog(parent), m_previousType(UnknownType), m_firstTypeChange(true)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
// Match BreakpointType (omitting unknown type).
m_ui.setupUi(this);
QStringList types;
......@@ -116,14 +117,19 @@ BreakpointDialog::BreakpointDialog(QWidget *parent)
m_ui.comboBoxType->addItems(types);
m_ui.pathChooserFileName->setExpectedKind(Utils::PathChooser::File);
connect(m_ui.comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int)));
m_ui.lineEditIgnoreCount->setValidator(
new QIntValidator(0, 2147483647, m_ui.lineEditIgnoreCount));
const QString moduleToolTip =
tr("Specifying the module (base name of the library or executable)\n"
"for function or file type breakpoints can significantly speed up\n"
"debugger start-up times (CDB, LLDB).");
m_ui.labelModule->setToolTip(moduleToolTip);
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'.");
m_ui.lineEditCommand->setToolTip(commandToolTip);
m_ui.labelCommand->setToolTip(commandToolTip);
m_ui.spinBoxIgnoreCount->setMinimum(0);
m_ui.spinBoxIgnoreCount->setMaximum(2147483647);
}
void BreakpointDialog::setType(BreakpointType type)
......@@ -175,7 +181,7 @@ void BreakpointDialog::setPartsEnabled(unsigned partsMask)
m_ui.labelIgnoreCount->setEnabled(partsMask & ConditionPart);
m_ui.labelThreadSpec->setEnabled(partsMask & ConditionPart);
m_ui.lineEditCondition->setEnabled(partsMask & ConditionPart);
m_ui.lineEditIgnoreCount->setEnabled(partsMask & ConditionPart);
m_ui.spinBoxIgnoreCount->setEnabled(partsMask & ConditionPart);
m_ui.lineEditThreadSpec->setEnabled(partsMask & ConditionPart);
m_ui.labelModule->setEnabled(partsMask & ModulePart);
......@@ -199,7 +205,7 @@ void BreakpointDialog::clearOtherParts(unsigned partsMask)
if (inversedPartsMask & ConditionPart) {
m_ui.lineEditCondition->clear();
m_ui.lineEditIgnoreCount->clear();
m_ui.spinBoxIgnoreCount->clear();
m_ui.lineEditThreadSpec->clear();
}
if (inversedPartsMask & ModulePart)
......@@ -210,6 +216,7 @@ void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data)
{
data->enabled = m_ui.checkBoxEnabled->isChecked();
data->tracepoint = m_ui.checkBoxTracepoint->isChecked();
data->command = m_ui.lineEditCommand->text().trimmed();
if (partsMask & FileAndLinePart) {
data->lineNumber = m_ui.lineEditLineNumber->text().toInt();
......@@ -224,7 +231,7 @@ void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data)
if (partsMask & ConditionPart) {
data->condition = m_ui.lineEditCondition->text().toUtf8();
data->ignoreCount = m_ui.lineEditIgnoreCount->text().toInt();
data->ignoreCount = m_ui.spinBoxIgnoreCount->text().toInt();
data->threadSpec =
BreakHandler::threadSpecFromDisplay(m_ui.lineEditThreadSpec->text());
}
......@@ -236,6 +243,7 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data)
{
m_ui.checkBoxEnabled->setChecked(data.enabled);
m_ui.checkBoxUseFullPath->setChecked(data.useFullPath);
m_ui.lineEditCommand->setText(data.command);
if (mask & FileAndLinePart) {
m_ui.pathChooserFileName->setPath(data.fileName);
......@@ -257,7 +265,7 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data)
if (mask & ConditionPart) {
m_ui.lineEditCondition->setText(QString::fromUtf8(data.condition));
m_ui.lineEditIgnoreCount->setText(QString::number(data.ignoreCount));
m_ui.spinBoxIgnoreCount->setValue(data.ignoreCount);
m_ui.lineEditThreadSpec->
setText(BreakHandler::displayFromThreadSpec(data.threadSpec));
}
......@@ -275,10 +283,10 @@ void BreakpointDialog::typeChanged(int)
case UnknownType:
break;
case BreakpointByFileAndLine:
getParts(FileAndLinePart|ModulePart, &m_savedParameters);
getParts(FileAndLinePart|ModulePart|ConditionPart, &m_savedParameters);
break;
case BreakpointByFunction:
getParts(FunctionPart|ModulePart, &m_savedParameters);
getParts(FunctionPart|ModulePart|ConditionPart, &m_savedParameters);
break;
case BreakpointAtThrow:
case BreakpointAtCatch:
......@@ -286,7 +294,7 @@ void BreakpointDialog::typeChanged(int)
break;
case BreakpointByAddress:
case Watchpoint:
getParts(AddressPart, &m_savedParameters);
getParts(AddressPart|ConditionPart, &m_savedParameters);
break;
}
......@@ -338,6 +346,35 @@ bool BreakpointDialog::showDialog(BreakpointParameters *data)
return true;
}
// Dialog allowing changing properties of multiple breakpoints at a time.
class MultiBreakPointsDialog : public QDialog {
Q_OBJECT
public:
explicit MultiBreakPointsDialog(QWidget *parent = 0);
QString condition() const { return m_ui.lineEditCondition->text(); }
int ignoreCount() const { return m_ui.spinBoxIgnoreCount->value(); }
int threadSpec() const
{ return BreakHandler::threadSpecFromDisplay(m_ui.lineEditThreadSpec->text()); }
void setCondition(const QString &c) { m_ui.lineEditCondition->setText(c); }
void setIgnoreCount(int i) { m_ui.spinBoxIgnoreCount->setValue(i); }
void setThreadSpec(int t)
{ return m_ui.lineEditThreadSpec->setText(BreakHandler::displayFromThreadSpec(t)); }
private:
Ui::BreakCondition m_ui;
};
MultiBreakPointsDialog::MultiBreakPointsDialog(QWidget *parent) :
QDialog(parent)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui.setupUi(this);
setWindowTitle(tr("Edit Breakpoint Properties"));
m_ui.spinBoxIgnoreCount->setMinimum(0);
m_ui.spinBoxIgnoreCount->setMaximum(2147483647);
}
///////////////////////////////////////////////////////////////////////
//
......@@ -579,6 +616,7 @@ void BreakWindow::addBreakpoint()
{
BreakpointParameters data(BreakpointByFileAndLine);
BreakpointDialog dialog(this);
dialog.setWindowTitle(tr("Add Breakpoint"));
if (dialog.showDialog(&data))
breakHandler()->appendBreakpoint(data);
}
......@@ -595,29 +633,21 @@ void BreakWindow::editBreakpoints(const BreakpointIds &ids)
}
// This allows to change properties of multiple breakpoints at a time.
QDialog dlg(this);
Ui::BreakCondition ui;
ui.setupUi(&dlg);
dlg.setWindowTitle(tr("Edit Breakpoint Properties"));
ui.lineEditIgnoreCount->setValidator(
new QIntValidator(0, 2147483647, ui.lineEditIgnoreCount));
MultiBreakPointsDialog dialog;
BreakHandler *handler = breakHandler();
const QString oldCondition = QString::fromLatin1(handler->condition(id));
const QString oldIgnoreCount = QString::number(handler->ignoreCount(id));
const QString oldThreadSpec =
BreakHandler::displayFromThreadSpec(handler->threadSpec(id));
ui.lineEditCondition->setText(oldCondition);
ui.lineEditIgnoreCount->setText(oldIgnoreCount);
ui.lineEditThreadSpec->setText(oldThreadSpec);
dialog.setCondition(oldCondition);
const int oldIgnoreCount = handler->ignoreCount(id);
dialog.setIgnoreCount(oldIgnoreCount);
const int oldThreadSpec = handler->threadSpec(id);
dialog.setThreadSpec(oldThreadSpec);
if (dlg.exec() == QDialog::Rejected)
if (dialog.exec() == QDialog::Rejected)
return;
const QString newCondition = ui.lineEditCondition->text();
const QString newIgnoreCount = ui.lineEditIgnoreCount->text();
const QString newThreadSpec = ui.lineEditThreadSpec->text();
const QString newCondition = dialog.condition();
const int newIgnoreCount = dialog.ignoreCount();
const int newThreadSpec = dialog.threadSpec();
if (newCondition == oldCondition && newIgnoreCount == oldIgnoreCount
&& newThreadSpec == oldThreadSpec)
......@@ -625,9 +655,8 @@ void BreakWindow::editBreakpoints(const BreakpointIds &ids)
foreach (const BreakpointId id, ids) {
handler->setCondition(id, newCondition.toLatin1());
handler->setIgnoreCount(id, newIgnoreCount.toInt());
handler->setThreadSpec(id,
BreakHandler::threadSpecFromDisplay(newThreadSpec));
handler->setIgnoreCount(id, newIgnoreCount);
handler->setThreadSpec(id, newThreadSpec);
}
}
......
......@@ -106,6 +106,8 @@ QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
if (bp.ignoreCount)
str << ' ' << (bp.ignoreCount + 1);
// Condition currently unsupported.
if (!bp.command.isEmpty())
str << " \"" << bp.command << '"';
return rc;
}
......
......@@ -187,6 +187,7 @@ QDataStream &operator<<(QDataStream &stream, const BreakpointParameters &s)
stream << s.useFullPath;
stream << s.tracepoint;
stream << s.module;
stream << s.command;
return stream;
}
......@@ -205,6 +206,7 @@ QDataStream &operator>>(QDataStream &stream, BreakpointParameters &s)
stream >> b; s.useFullPath = b;
stream >> b; s.tracepoint = b;
stream >> str ; s.module = str;
stream >> str ; s.command = str;
return stream;
}
......
......@@ -2453,7 +2453,9 @@ void GdbEngine::handleBreakIgnore(const GdbResponse &response)
//else if (msg.contains(__("Will ignore next")))
// response.ignoreCount = data->ignoreCount;
// FIXME: this assumes it is doing the right thing...
br.ignoreCount = handler->ignoreCount(id);
const BreakpointParameters &parameters = handler->breakpointData(id);
br.ignoreCount = parameters.ignoreCount;
br.command = parameters.command;
handler->setResponse(id, br);
changeBreakpoint(id); // Maybe there's more to do.
}
......@@ -2645,6 +2647,19 @@ void GdbEngine::changeBreakpoint(BreakpointId id)
CB(handleBreakThreadSpec), id);
return;
}
if (data.command != response.command) {
QByteArray breakCommand = "-break-commands " + bpnr;
foreach (const QString &command, data.command.split(QLatin1String("\\n"))) {
if (!command.isEmpty()) {
breakCommand.append(" \"");
breakCommand.append(command.toLatin1());
breakCommand.append('"');
}
}
postCommand(breakCommand, NeedsStop | RebuildBreakpointModel,
CB(handleBreakIgnore), id);
return;
}
if (!data.conditionsMatch(response.condition)) {
postCommand("condition " + bpnr + ' ' + data.condition,
NeedsStop | RebuildBreakpointModel,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment