const BreakpointParameters &data = it->data;
const BreakpointResponse &response = it->response;
//qDebug() << "COMPARING " << data.toString() << " WITH " << needle.toString();
- if (response.number && response.number == needle.number)
+ if (response.id.isValid() && response.id.majorPart() == needle.id.majorPart())
return id;
if (isSimilarTo(data, needle))
{
ConstIterator it = m_storage.constBegin(), et = m_storage.constEnd();
for ( ; it != et; ++it)
- if (it->response.number == bpNumber)
+ if (it->response.id.majorPart() == bpNumber)
return it.key();
return BreakpointId();
}
case 1:
if (role == Qt::DisplayRole)
return res.functionName;
+ case 4:
+ if (role == Qt::DisplayRole)
+ if (res.address)
+ return QString::fromAscii("0x%1").arg(res.address, 0, 16);
}
return QVariant();
}
switch (mi.column()) {
case 0:
- if (role == Qt::DisplayRole) {
+ if (role == Qt::DisplayRole)
return id.toString();
- //return QString("%1 - %2").arg(id).arg(response.number);
- }
if (role == Qt::DecorationRole)
return it->icon();
break;
break;
case 4:
if (role == Qt::DisplayRole) {
- QString displayValue;
const quint64 address = orig ? data.address : response.address;
if (address)
- displayValue += QString::fromAscii("0x%1").arg(address, 0, 16);
- if (0 && !response.extra.isEmpty()) {
- if (!displayValue.isEmpty())
- displayValue += QLatin1Char(' ');
- displayValue += QString::fromAscii(response.extra);
- }
- return displayValue;
+ return QString::fromAscii("0x%1").arg(address, 0, 16);
+ return QVariant();
}
break;
case 5:
return -1;
}
-void BreakHandler::appendSubBreakpoint(BreakpointId id, const BreakpointResponse &data)
+void BreakHandler::insertSubBreakpoint(const BreakpointResponse &data)
{
- Iterator it = m_storage.find(id);
+ BreakpointId id = data.id;
+ QTC_ASSERT(id.isMinor(), return);
+ BreakpointId majorId = id.parent();
+ Iterator it = m_storage.find(majorId);
QTC_ASSERT(it != m_storage.end(), return);
- int row = indexOf(id);
+ int row = indexOf(majorId);
QTC_ASSERT(row != -1, return);
- QModelIndex idx = createIndex(row, 0, id.toInternalId());
- beginInsertRows(idx, it->subItems.size(), it->subItems.size());
- it->subItems.append(data);
- endInsertRows();
+ int minorPart = id.minorPart();
+ int pos = -1;
+ for (int i = 0; i != it->subItems.size(); ++i) {
+ if (it->subItems.at(i).id.minorPart() == minorPart) {
+ pos = i;
+ break;
+ }
+ }
+ if (pos == -1) {
+ // This is a new sub-breakpoint.
+ QModelIndex idx = createIndex(row, 0, id.toInternalId());
+ beginInsertRows(idx, it->subItems.size(), it->subItems.size());
+ it->subItems.append(data);
+ endInsertRows();
+ } else {
+ // This modifies an existing sub-breakpoint.
+ it->subItems[pos] = data;
+ layoutChanged();
+ }
}
void BreakHandler::saveSessionData()
}
if (!response.pending) {
str << "<tr><td>" << tr("Breakpoint Number:")
- << "</td><td>" << response.number << "</td></tr>";
+ << "</td><td>" << response.id.toString() << "</td></tr>";
}
str << "<tr><td>" << tr("Breakpoint Type:")
<< "</td><td>" << typeToString(data.type) << "</td></tr>";
<< "</th><th>" << tr("Requested")
<< "</th><th>" << tr("Obtained") << "</th></tr>"
<< "<tr><td>" << tr("Internal Number:")
- << "</td><td>—</td><td>" << response.number << "</td></tr>";
+ << "</td><td>—</td><td>" << response.id.toString() << "</td></tr>";
if (data.type == BreakpointByFunction) {
str << "<tr><td>" << tr("Function Name:")
<< "</td><td>" << data.functionName
str << "</td></tr>";
if (response.multiple) {
str << "<tr><td>" << tr("Multiple Addresses:")
- << "</td><td>";
- foreach (quint64 address, response.addresses) {
- formatAddress(str, address);
- str << " ";
- }
- str << "</td></tr>";
+ << "</td><td>"
+ << "</td></tr>";
}
if (!data.command.isEmpty() || !response.command.isEmpty()) {
str << "<tr><td>" << tr("Command:")
// The only way to add a new breakpoint.
void appendBreakpoint(const BreakpointParameters &data);
- void appendSubBreakpoint(BreakpointId id, const BreakpointResponse &data);
+ void insertSubBreakpoint(const BreakpointResponse &data);
BreakpointIds allBreakpointIds() const;
BreakpointIds engineBreakpointIds(DebuggerEngine *engine) const;
//
//////////////////////////////////////////////////////////////////
+BreakpointId::BreakpointId(const QByteArray &ba)
+{
+ int pos = ba.indexOf('.');
+ if (pos == -1) {
+ m_majorPart = ba.toInt();
+ m_minorPart = 0;
+ } else {
+ m_majorPart = ba.left(pos).toInt();
+ m_minorPart = ba.mid(pos + 1).toInt();
+ }
+}
+
QDebug operator<<(QDebug d, const BreakpointId &id)
{
d << qPrintable(id.toString());
return d;
}
+QByteArray BreakpointId::toByteArray() const
+{
+ if (!isValid())
+ return "<invalid bkpt>";
+ QByteArray ba = QByteArray::number(m_majorPart);
+ if (isMinor()) {
+ ba.append('.');
+ ba.append(QByteArray::number(m_minorPart));
+ }
+ return ba;
+}
+
QString BreakpointId::toString() const
{
if (!isValid())
BreakpointResponse::BreakpointResponse()
{
- number = 0;
- subNumber = 0;
pending = true;
+ hitCount = 0;
multiple = false;
correctedLineNumber = 0;
}
{
QString result = BreakpointParameters::toString();
QTextStream ts(&result);
- ts << " Number: " << number;
- if (subNumber)
- ts << "." << subNumber;
+ ts << " Number: " << id.toString();
if (pending)
ts << " [pending]";
if (!fullName.isEmpty())
ts << " Extra: " << extra;
if (correctedLineNumber)
ts << " CorrectedLineNumber: " << correctedLineNumber;
+ ts << " Hit: " << hitCount << " times";
ts << ' ';
return result + BreakpointParameters::toString();
}
void BreakpointResponse::fromParameters(const BreakpointParameters &p)
{
BreakpointParameters::operator=(p);
- number = 0;
- subNumber = 0;
+ id = BreakpointId();
fullName.clear();
multiple = false;
extra.clear();
correctedLineNumber = 0;
+ hitCount = 0;
}
} // namespace Internal
BreakpointId() { m_majorPart = m_minorPart = 0; }
explicit BreakpointId(quint16 ma) { m_majorPart = ma; m_minorPart = 0; }
BreakpointId(quint16 ma, quint16 mi) { m_majorPart = ma; m_minorPart = mi; }
+ explicit BreakpointId(const QByteArray &ba); // "21.2"
bool isValid() const { return m_majorPart != 0; }
bool isMajor() const { return m_majorPart != 0 && m_minorPart == 0; }
bool operator!() const { return !isValid(); }
operator const void*() const { return isValid() ? this : 0; }
quint32 toInternalId() const { return m_majorPart | (m_minorPart << 16); }
+ QByteArray toByteArray() const;
QString toString() const;
bool operator==(const BreakpointId &id) const
{ return m_majorPart == id.m_majorPart && m_minorPart == id.m_minorPart; }
public:
void fromParameters(const BreakpointParameters &p);
- int number; //!< Breakpoint number assigned by the debugger engine.
- int subNumber; //!< Breakpoint sub-number assigned by the engine.
+ BreakpointId id; //!< Breakpoint number assigned by the debugger engine.
bool pending; //!< Breakpoint not fully resolved.
+ int hitCount; //!< Number of times this has been hit.
QString fullName; //!< Full file name acknowledged by the debugger engine.
bool multiple; //!< Happens in constructors/gdb.
QByteArray extra; //!< gdb: <PENDING>, <MULTIPLE>
- QList<quint64> addresses;//!< Extra addresses for templated code.
int correctedLineNumber; //!< Line number as seen by gdb.
};
if (id && breakHandler()->engineBreakpointIds(this).contains(id)) {
const BreakpointResponse parameters = breakHandler()->response(id);
// Trace point? Just report.
- number = parameters.number;
+ number = parameters.id.majorPart();
if (parameters.tracepoint) {
*message = msgTracePointTriggered(id, number, QString::number(threadId));
return StopReportLog|StopIgnoreContinue;
static inline void formatCdbBreakPointResponse(BreakpointId id, const BreakpointResponse &r,
QTextStream &str)
{
- str << "Obtained breakpoint " << id << " (#" << r.number << ')';
+ str << "Obtained breakpoint " << id << " (#" << r.id.majorPart() << ')';
if (r.pending) {
str << ", pending";
} else {
if (it != m_pendingBreakpointMap.end()) {
// Complete the response and set on handler.
BreakpointResponse ¤tResponse = it.value();
- currentResponse.number = reportedResponse.number;
+ currentResponse.id = reportedResponse.id;
currentResponse.address = reportedResponse.address;
currentResponse.module = reportedResponse.module;
currentResponse.pending = reportedResponse.pending;
QString *expression /* = 0 */)
{
BreakpointId id = BreakpointId(-1);
- gdbmiChildToInt(gdbmi, "number", &(r->number));
+ int majorPart = 0;
+ gdbmiChildToInt(gdbmi, "number", &majorPart);
gdbmiChildToBool(gdbmi, "enabled", &(r->enabled));
gdbmiChildToBool(gdbmi, "deferred", &(r->pending));
+ r->id = BreakpointId(majorPart);
const GdbMi idG = gdbmi.findChild("id");
if (idG.isValid()) { // Might not be valid if there is not id
bool ok;
QDataStream &operator<<(QDataStream &stream, const BreakpointResponse &s)
{
- stream << s.number;
+ stream << s.id.majorPart();
stream << s.condition;
stream << s.ignoreCount;
stream << s.fileName;
stream << s.threadSpec;
stream << s.functionName;
stream << s.address;
+ stream << s.hitCount;
return stream;
}
QDataStream &operator>>(QDataStream &stream, BreakpointResponse &s)
{
- stream >> s.number;
+ int majorPart;
+ stream >> majorPart;
+ s.id = BreakpointId(majorPart);
stream >> s.condition;
stream >> s.ignoreCount;
stream >> s.fileName;
stream >> s.threadSpec;
stream >> s.functionName;
stream >> s.address;
+ stream >> s.hitCount;
return stream;
}
BreakpointResponse br;
foreach (const GdbMi &bkpt, result.children()) {
const QByteArray nr = bkpt.findChild("number").data();
- if (nr.contains(".")) {
+ if (nr.contains('.')) {
// A sub-breakpoint.
- int subNumber = nr.mid(nr.indexOf('.') + 1).toInt();
BreakpointResponse sub;
updateResponse(sub, bkpt);
- sub.number = br.number;
+ sub.id = BreakpointId(nr);
sub.type = br.type;
- sub.subNumber = subNumber;
sub.extra.clear();
- handler->appendSubBreakpoint(id, sub);
+ handler->insertSubBreakpoint(sub);
} else {
// A primary breakpoint.
id = handler->findBreakpointByNumber(nr.toInt());
updateResponse(br, bkpt);
}
}
- if (!isQmlStepBreakpoint(br.number)) {
+ if (!isQmlStepBreakpoint(br.id.majorPart())) {
handler->setResponse(id, br);
attemptAdjustBreakpointLocation(id);
}
}
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
QByteArray msg = response.data.findChild("msg").data();
- if (msg.startsWith("Cannot find bounds of current function")
+ if (msg.startsWith("Cannot find bounds of current function")
|| msg.contains("Error accessing memory address ")) {
if (!m_commandsToRunOnTemporaryBreak.isEmpty())
flushQueuedCommands();
QByteArray file, fullName;
foreach (const GdbMi &child, bkpt.children()) {
if (child.hasName("number")) {
- response.number = child.data().toInt();
+ response.id = BreakpointId(child.data());
} else if (child.hasName("func")) {
response.functionName = _(child.data());
} else if (child.hasName("addr")) {
if (wpt.isValid()) {
// Mac yields:
//>32^done,wpt={number="4",exp="*4355182176"}
- br.number = wpt.findChild("number").data().toInt();
+ br.id = BreakpointId(wpt.findChild("number").data());
QByteArray exp = wpt.findChild("exp").data();
if (exp.startsWith('*'))
br.address = exp.mid(1).toULongLong(0, 0);
const int end = ba.indexOf(':');
const int begin = ba.lastIndexOf(' ', end) + 1;
const QByteArray address = ba.mid(end + 2).trimmed();
- br.number = ba.mid(begin, end - begin).toInt();
+ br.id = BreakpointId(ba.mid(begin, end - begin));
if (address.startsWith('*'))
br.address = address.mid(1).toULongLong(0, 0);
handler->setResponse(id, br);
}
br = handler->response(id);
attemptAdjustBreakpointLocation(id);
- if (br.multiple && br.addresses.isEmpty())
- postCommand("info break " + QByteArray::number(br.number),
+ if (br.multiple)
+ postCommand("info break " + QByteArray::number(br.id.majorPart()),
NeedsStop, CB(handleBreakListMultiple), QVariant(id));
} else if (response.data.findChild("msg").data().contains("Unknown option")) {
// Older version of gdb don't know the -a option to set tracepoints
BreakHandler *handler = breakHandler();
foreach (const GdbMi &bkpt, bkpts) {
BreakpointResponse needle;
- needle.number = bkpt.findChild("number").data().toInt();
- if (isQmlStepBreakpoint2(needle.number))
+ needle.id = BreakpointId(bkpt.findChild("number").data());
+ if (isQmlStepBreakpoint2(needle.id.majorPart()))
continue;
- if (isQFatalBreakpoint(needle.number))
+ if (isQFatalBreakpoint(needle.id.majorPart()))
continue;
BreakpointId id = handler->findSimilarBreakpoint(needle);
if (id.isValid()) {
handler->setResponse(id, response);
attemptAdjustBreakpointLocation(id);
response = handler->response(id);
- if (response.multiple && response.addresses.isEmpty())
- postCommand("info break " + QByteArray::number(response.number),
+ if (response.multiple)
+ postCommand("info break " + response.id.toString().toLatin1(),
NeedsStop, CB(handleBreakListMultiple),
QVariant::fromValue(id));
} else {
// 2.1 y 0x0040168e in MainWindow::MainWindow(QWidget*) at mainwindow.cpp:7
// 2.2 y 0x00401792 in MainWindow::MainWindow(QWidget*) at mainwindow.cpp:7
- // tested in ../../../tests/auto/debugger/
- QRegExp re(_("MULTIPLE.*(0x[0-9a-f]+) in (.*)\\s+at (.*):([\\d]+)([^\\d]|$)"));
- re.setMinimal(true);
+ // "Num Type Disp Enb Address What
+ // 3 breakpoint keep y <MULTIPLE> \n"
+ // 3.1 y 0x0806094e in Vector<int>::Vector(int) at simple.cpp:141
+ // 3.2 y 0x08060994 in Vector<float>::Vector(int) at simple.cpp:141
+ // 3.3 y 0x080609da in Vector<double>::Vector(int) at simple.cpp:141
+ // 3.4 y 0x08060a1d in Vector<char>::Vector(int) at simple.cpp:141
- BreakpointResponse response = breakHandler()->response(id);
- response.fileName = _("<MULTIPLE>");
-
- QString requestedFileName = breakHandler()->fileName(id);
-
- if (re.indexIn(output) != -1) {
- response.address = re.cap(1).toULongLong(0, 16);
- response.functionName = re.cap(2).trimmed();
- response.lineNumber = re.cap(4).toInt();
- QString full = fullName(re.cap(3));
- if (full.isEmpty()) {
- // FIXME: This happens without UsePreciseBreakpoints regularly.
- // We need to revive that "fill full name mapping bit by bit"
- // approach of 1.2.x
- //qDebug() << "NO FULL NAME KNOWN FOR" << re.cap(3);
- full = cleanupFullName(re.cap(3));
- if (full.isEmpty()) {
- qDebug() << "FILE IS NOT RESOLVABLE" << re.cap(3);
- full = re.cap(3); // FIXME: wrong, but prevents recursion
+ BreakHandler *handler = breakHandler();
+ BreakpointResponse response = handler->response(id);
+ int posMultiple = output.indexOf(_("<MULTIPLE>"));
+ if (posMultiple != -1) {
+ QByteArray data = output.toUtf8();
+ data.replace('\n', ' ');
+ data.replace(" ", " ");
+ data.replace(" ", " ");
+ data.replace(" ", " ");
+ int majorPart = 0;
+ int minorPart = 0;
+ int hitCount = 0;
+ bool hitCountComing = false;
+ bool functionComing = false;
+ bool locationComing = false;
+ QByteArray location;
+ QByteArray function;
+ qulonglong address;
+ foreach (const QByteArray &part, data.split(' ')) {
+ if (part.isEmpty())
+ continue;
+ //qDebug() << "PART: " << part;
+ if (majorPart == 0) {
+ majorPart = part.toInt();
+ if (majorPart > 0)
+ continue;
+ }
+ if (part == "hit") {
+ hitCountComing = true;
+ continue;
+ }
+ if (hitCountComing) {
+ hitCountComing = false;
+ hitCount = part.toInt();
+ continue;
+ }
+ if (part == "at") {
+ locationComing = true;
+ continue;
+ }
+ if (locationComing) {
+ locationComing = false;
+ location = part;
+ continue;
+ }
+ if (part == "in") {
+ functionComing = true;
+ continue;
+ }
+ if (functionComing) {
+ functionComing = false;
+ function = part;
+ continue;
+ }
+ if (part.startsWith("0x")) {
+ address = part.toInt(0, 0);
+ continue;
+ }
+ if (part.size() >= 3 && part.count('.') == 1) {
+ BreakpointId subId(part);
+ int tmpMajor = subId.majorPart();
+ int tmpMinor = subId.minorPart();
+ if (tmpMajor == majorPart) {
+ if (minorPart) {
+ // Commit what we had before.
+ BreakpointResponse sub;
+ sub.address = address;
+ sub.functionName = QString::fromUtf8(function);
+ if (location.size()) {
+ int pos = location.indexOf(':');
+ sub.lineNumber = location.mid(pos + 1).toInt();
+ sub.fileName = QString::fromUtf8(location.left(pos));
+ }
+ sub.id = subId;
+ sub.type = response.type;
+ sub.address = address;
+ sub.extra.clear();
+ handler->insertSubBreakpoint(sub);
+ location.clear();
+ function.clear();
+ address = 0;
+ }
+
+ // Now start new.
+ minorPart = tmpMinor;
+ continue;
+ }
}
}
- // The variable full could still contain, say "foo.cpp" when we asked
- // for "/full/path/to/foo.cpp". In this case, using the requested
- // instead of the acknowledged name makes sense as it will allow setting
- // the marker in more cases.
- if (requestedFileName.endsWith(full))
- full = requestedFileName;
- response.fileName = full;
+ // Commit main data.
} else {
- qDebug() << "COULD NOT MATCH " << re.pattern() << " AND " << output;
- response.number = -1; // <unavailable>
+ qDebug() << "COULD NOT MATCH" << output;
+ response.id = BreakpointId(); // Unavailable.
}
- breakHandler()->setResponse(id, response);
+ //handler->setResponse(id, response);
}
void GdbEngine::handleInfoLine(const GdbResponse &response)
const BreakpointParameters &data = handler->breakpointData(id);
QTC_ASSERT(data.type != UnknownType, return);
const BreakpointResponse &response = handler->response(id);
- QTC_ASSERT(response.number > 0, return);
- const QByteArray bpnr = QByteArray::number(response.number);
- QTC_ASSERT(response.number > 0, return);
+ QTC_ASSERT(response.id.isValid(), return);
+ const QByteArray bpnr = response.id.toByteArray();
const BreakpointState state = handler->state(id);
if (state == BreakpointChangeRequested)
handler->notifyBreakpointChangeProceeding(id);
QTC_ASSERT(handler->state(id) == BreakpointRemoveRequested, /**/);
handler->notifyBreakpointRemoveProceeding(id);
BreakpointResponse br = handler->response(id);
- showMessage(_("DELETING BP %1 IN %2").arg(br.number)
+ showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString())
.arg(handler->fileName(id)));
- postCommand("-break-delete " + QByteArray::number(br.number),
+ postCommand("-break-delete " + br.id.toByteArray(),
NeedsStop | RebuildBreakpointModel);
// Pretend it succeeds without waiting for response. Feels better.
// FIXME: Really?
QByteArray file = response.data.mid(pos1 + 4, pos2 - pos1 - 4);
QByteArray line = response.data.mid(pos2 + 1);
BreakpointResponse br;
- br.number = bpnr.toInt();
+ br.id = BreakpointId(bpnr);
br.fileName = _(file);
br.lineNumber = line.toInt();
handler->setResponse(id, br);
QTC_ASSERT(handler->state(id) == BreakpointRemoveRequested, /**/);
handler->notifyBreakpointRemoveProceeding(id);
BreakpointResponse br = handler->response(id);
- showMessage(_("DELETING BP %1 IN %2").arg(br.number)
+ showMessage(_("DELETING BP %1 IN %2").arg(br.id.toString())
.arg(handler->fileName(id)));
- postCommand("clear " + QByteArray::number(br.number));
+ postCommand("clear " + br.id.toByteArray());
// Pretend it succeeds without waiting for response.
handler->notifyBreakpointRemoveOk(id);
}
// tests multiple breakpoints
-namespace multiple_breakpoints {
+namespace multibp {
template <typename T> class Vector
{
Vector<char> vc(10);
return vi.size() + vf.size() + vd.size() + vc.size();
}
-} // namespace multiple_breakpoints
+
+} // namespace multibp
#if USE_PRIVATE
{
qc41700::test();
qc42170::test();
- multiple_breakpoints::test();
+ multibp::test();
test842();
test842();
test3611();