Debugger[CDB]: Refactor breakpoint handling.

Add a command to list breakpoints enabling id access.
Implemented breakpoint handling similar to gdb using breakpoint
ids (no longer delete and re-set all breakpoints on a change).
Save the module that is reported back in the session so that
it can be re-used for the next start. Keep a per-debugger-session
cache of fileName->Module for adding breakpoints to accelerate
setting breakpoints in the same file.
Polish the breakpoint tooltip.
This commit is contained in:
Friedemann Kleint
2011-02-03 16:26:23 +01:00
parent d5a33d2860
commit 91ead6c818
12 changed files with 327 additions and 142 deletions

View File

@@ -54,7 +54,9 @@ namespace Debugger {
namespace Internal {
// Convert breakpoint in CDB syntax.
QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn, bool oneshot, int id)
QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn,
BreakpointId id /* = BreakpointId(-1) */,
bool oneshot)
{
#ifdef Q_OS_WIN
const BreakpointParameters bp = fixWinMSVCBreakpoint(bpIn);
@@ -68,8 +70,10 @@ QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn, bool onesho
if (bp.threadSpec >= 0)
str << '~' << bp.threadSpec << ' ';
str << (bp.type == Watchpoint ? "ba" : "bp");
if (id >= 0)
// Currently use 'bu' so that the offset expression (including file name)
// is kept when reporting back breakpoints (which is otherwise discarded when resolving).
str << (bp.type == Watchpoint ? "ba" : "bu");
if (id != BreakpointId(-1))
str << id;
str << ' ';
if (oneshot)
@@ -100,7 +104,7 @@ QByteArray cdbAddBreakpointCommand(const BreakpointParameters &bpIn, bool onesho
break;
}
if (bp.ignoreCount)
str << ' ' << bp.ignoreCount;
str << ' ' << (bp.ignoreCount + 1);
// Condition currently unsupported.
return rc;
}
@@ -181,6 +185,66 @@ static inline bool parseThread(QByteArray line, ThreadData *thread, bool *curren
return true;
}
// Helper to retrieve an int child from GDBMI
static inline bool gdbmiChildToInt(const GdbMi &parent, const char *childName, int *target)
{
const GdbMi childBA = parent.findChild(childName);
if (childBA.isValid()) {
bool ok;
const int v = childBA.data().toInt(&ok);
if (ok) {
*target = v;
return true;
}
}
return false;
}
// Helper to retrieve an bool child from GDBMI
static inline bool gdbmiChildToBool(const GdbMi &parent, const char *childName, bool *target)
{
const GdbMi childBA = parent.findChild(childName);
if (childBA.isValid()) {
*target = childBA.data() == "true";
return true;
}
return false;
}
// Parse extension command listing breakpoints.
// Note that not all fields are returned, since file, line, function are encoded
// in the expression (that is in addition deleted on resolving for a bp-type breakpoint).
BreakpointId parseBreakPoint(const GdbMi &gdbmi, BreakpointResponse *r,
QString *expression /* = 0 */)
{
BreakpointId id = BreakpointId(-1);
gdbmiChildToInt(gdbmi, "number", &(r->number));
gdbmiChildToBool(gdbmi, "enabled", &(r->enabled));
gdbmiChildToBool(gdbmi, "deferred", &(r->pending));
const GdbMi idG = gdbmi.findChild("id");
if (idG.isValid()) { // Might not be valid if there is not id
bool ok;
const BreakpointId cid = idG.data().toULongLong(&ok);
if (ok)
id = cid;
}
const GdbMi moduleG = gdbmi.findChild("module");
if (moduleG.isValid())
r->module = QString::fromLocal8Bit(moduleG.data());
if (expression) {
const GdbMi expressionG = gdbmi.findChild("expression");
if (expressionG.isValid())
*expression = QString::fromLocal8Bit(expressionG.data());
}
const GdbMi addressG = gdbmi.findChild("address");
if (addressG.isValid())
r->address = addressG.data().toULongLong(0, 0);
if (gdbmiChildToInt(gdbmi, "passcount", &(r->ignoreCount)))
r->ignoreCount--;
gdbmiChildToInt(gdbmi, "thread", &(r->threadSpec));
return id;
}
QString debugByteArray(const QByteArray &a)
{
QString rc;