Debugger: Split CdbCommand into CdbCommand and CdbResponse

Move it closer to the GDB/LLDB setup.

Change-Id: Ifcada93ba9abff56c5523963c3ef9382277387e2
Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
hjk
2015-03-06 16:00:57 +01:00
parent 14a02d5081
commit 31b2ac85f4
2 changed files with 172 additions and 153 deletions

View File

@@ -85,7 +85,7 @@ enum { debugSourceMapping = 0 };
enum { debugWatches = 0 }; enum { debugWatches = 0 };
enum { debugBreakpoints = 0 }; enum { debugBreakpoints = 0 };
#define CB(callback) [this](const CdbCommandPtr &r) { callback(r); } #define CB(callback) [this](const CdbResponse &r) { callback(r); }
#if 0 #if 0
# define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line); # define STATE_DEBUG(state, func, line, notifyFunc) qDebug("%s in %s at %s:%d", notifyFunc, stateName(state), func, line);
@@ -124,7 +124,7 @@ enum { debugBreakpoints = 0 };
\list \list
\li postCommand(): Does not expect a reply \li postCommand(): Does not expect a response
\li postBuiltinCommand(): Run a builtin-command producing free-format, multiline output \li postBuiltinCommand(): Run a builtin-command producing free-format, multiline output
that is captured by enclosing it in special tokens using the 'echo' command and that is captured by enclosing it in special tokens using the 'echo' command and
then invokes a callback with a CdbBuiltinCommand structure. then invokes a callback with a CdbBuiltinCommand structure.
@@ -193,37 +193,52 @@ static inline bool isCreatorConsole(const DebuggerStartParameters &sp)
&& (sp.startMode == StartInternal || sp.startMode == StartExternal); && (sp.startMode == StartInternal || sp.startMode == StartExternal);
} }
// Base data structure for command queue entries with callback class CdbResponse
struct CdbCommand
{ {
CdbCommand() public:
: token(0), flags(0), commandSequence(0), isBuiltin(true), success(false) CdbResponse()
{} : commandSequence(0), success(false)
CdbCommand(bool builtin, const QByteArray &cmd, int token, unsigned flags,
CdbEngine::CommandHandler h, unsigned nc)
: token(token), flags(flags), command(cmd), commandSequence(nc),
isBuiltin(builtin), handler(h), success(false)
{} {}
QByteArray joinedReply() const; QByteArray joinedReply() const;
int token;
unsigned flags;
QByteArray command; QByteArray command;
// Continue with other commands as specified in CommandSequenceFlags // Continue with other commands as specified in CommandSequenceFlags
unsigned commandSequence; unsigned commandSequence;
bool isBuiltin;
CdbEngine::CommandHandler handler;
QList<QByteArray> builtinReply; QList<QByteArray> builtinReply;
QByteArray extensionReply; QByteArray extensionReply;
QByteArray errorMessage; QByteArray errorMessage;
bool success; bool success;
}; };
QByteArray CdbCommand::joinedReply() const // Base data structure for command queue entries with callback
class CdbCommand
{
public:
CdbCommand()
: token(0), flags(0), isBuiltin(true)
{}
CdbCommand(bool builtin, const QByteArray &cmd, int token, unsigned flags,
CdbEngine::CommandHandler h, unsigned nc)
: token(token), flags(flags), isBuiltin(builtin), handler(h)
{
response.command = cmd;
response.commandSequence = nc;
}
int token;
unsigned flags;
bool isBuiltin;
CdbEngine::CommandHandler handler;
CdbResponse response; // FIXME: remove.
};
QByteArray CdbResponse::joinedReply() const
{ {
if (builtinReply.isEmpty()) if (builtinReply.isEmpty())
return QByteArray(); return QByteArray();
@@ -526,9 +541,9 @@ void CdbEngine::createFullBacktrace()
postBuiltinCommand("~*kp", 0, CB(handleCreateFullBackTrace)); postBuiltinCommand("~*kp", 0, CB(handleCreateFullBackTrace));
} }
void CdbEngine::handleCreateFullBackTrace(const CdbEngine::CdbCommandPtr &cmd) void CdbEngine::handleCreateFullBackTrace(const CdbResponse &response)
{ {
Internal::openTextEditor(QLatin1String("Backtrace $"), QLatin1String(cmd->joinedReply())); Internal::openTextEditor(QLatin1String("Backtrace $"), QLatin1String(response.joinedReply()));
} }
void CdbEngine::setupEngine() void CdbEngine::setupEngine()
@@ -980,7 +995,7 @@ void CdbEngine::updateWatchData(const WatchData &dataIn)
if (!dataIn.name.isEmpty() && dataIn.name != QLatin1String(dataIn.exp)) if (!dataIn.name.isEmpty() && dataIn.name != QLatin1String(dataIn.exp))
m_watchInameToName.insert(dataIn.iname, dataIn.name); m_watchInameToName.insert(dataIn.iname, dataIn.name);
postExtensionCommand("addwatch", args, 0, postExtensionCommand("addwatch", args, 0,
[this, dataIn](const CdbCommandPtr &r) { handleAddWatch(r, dataIn); }); [this, dataIn](const CdbResponse &r) { handleAddWatch(r, dataIn); });
return; return;
} }
@@ -993,18 +1008,18 @@ void CdbEngine::updateWatchData(const WatchData &dataIn)
updateLocalVariable(dataIn.iname); updateLocalVariable(dataIn.iname);
} }
void CdbEngine::handleAddWatch(const CdbCommandPtr &reply, WatchData item) void CdbEngine::handleAddWatch(const CdbResponse &response, WatchData item)
{ {
if (debugWatches) if (debugWatches)
qDebug() << "handleAddWatch ok=" << reply->success << item.iname; qDebug() << "handleAddWatch ok=" << response.success << item.iname;
if (reply->success) { if (response.success) {
updateLocalVariable(item.iname); updateLocalVariable(item.iname);
} else { } else {
item.setError(tr("Unable to add expression")); item.setError(tr("Unable to add expression"));
watchHandler()->insertData(item); watchHandler()->insertData(item);
showMessage(QString::fromLatin1("Unable to add watch item \"%1\"/\"%2\": %3"). showMessage(QString::fromLatin1("Unable to add watch item \"%1\"/\"%2\": %3").
arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp), arg(QString::fromLatin1(item.iname), QString::fromLatin1(item.exp),
QString::fromLocal8Bit(reply->errorMessage)), LogError); QString::fromLocal8Bit(response.errorMessage)), LogError);
} }
} }
@@ -1040,7 +1055,7 @@ void CdbEngine::updateLocalVariable(const QByteArray &iname)
} }
str << blankSeparator << iname; str << blankSeparator << iname;
postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0, postExtensionCommand(isWatch ? "watches" : "locals", localsArguments, 0,
[this](const CdbCommandPtr &r) { handleLocals(r, false); }); [this](const CdbResponse &r) { handleLocals(r, false); });
} }
bool CdbEngine::hasCapability(unsigned cap) const bool CdbEngine::hasCapability(unsigned cap) const
@@ -1211,7 +1226,7 @@ void CdbEngine::executeJumpToLine(const ContextData &data)
QByteArray cmd; QByteArray cmd;
ByteArrayInputStream str(cmd); ByteArrayInputStream str(cmd);
str << "? `" << QDir::toNativeSeparators(data.fileName) << ':' << data.lineNumber << '`'; str << "? `" << QDir::toNativeSeparators(data.fileName) << ':' << data.lineNumber << '`';
postBuiltinCommand(cmd, 0, [this, data](const CdbCommandPtr &r) { handleJumpToLineAddressResolution(r, data); }); postBuiltinCommand(cmd, 0, [this, data](const CdbResponse &r) { handleJumpToLineAddressResolution(r, data); });
} }
} }
@@ -1228,13 +1243,13 @@ void CdbEngine::jumpToAddress(quint64 address)
postCommand(registerCmd, 0); postCommand(registerCmd, 0);
} }
void CdbEngine::handleJumpToLineAddressResolution(const CdbCommandPtr &cmd, const ContextData &context) void CdbEngine::handleJumpToLineAddressResolution(const CdbResponse &response, const ContextData &context)
{ {
if (cmd->builtinReply.isEmpty()) if (response.builtinReply.isEmpty())
return; return;
// Evaluate expression: 5365511549 = 00000001`3fcf357d // Evaluate expression: 5365511549 = 00000001`3fcf357d
// Set register 'rip' to hex address and goto lcoation // Set register 'rip' to hex address and goto lcoation
QByteArray answer = cmd->builtinReply.front().trimmed(); QByteArray answer = response.builtinReply.front().trimmed();
const int equalPos = answer.indexOf(" = "); const int equalPos = answer.indexOf(" = ");
if (equalPos == -1) if (equalPos == -1)
return; return;
@@ -1296,18 +1311,18 @@ void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, c
updateLocals(false); updateLocals(false);
} }
void CdbEngine::handleThreads(const CdbCommandPtr &reply) void CdbEngine::handleThreads(const CdbResponse &response)
{ {
if (debug) if (debug)
qDebug("CdbEngine::handleThreads success=%d", reply->success); qDebug("CdbEngine::handleThreads success=%d", response.success);
if (reply->success) { if (response.success) {
GdbMi data; GdbMi data;
data.fromString(reply->extensionReply); data.fromString(response.extensionReply);
threadsHandler()->updateThreads(data); threadsHandler()->updateThreads(data);
// Continue sequence // Continue sequence
postCommandSequence(reply->commandSequence); postCommandSequence(response.commandSequence);
} else { } else {
showMessage(QString::fromLatin1(reply->errorMessage), LogError); showMessage(QString::fromLatin1(response.errorMessage), LogError);
} }
} }
@@ -1491,7 +1506,7 @@ void CdbEngine::updateLocals(bool newFrame)
// Required arguments: frame // Required arguments: frame
str << blankSeparator << frameIndex; str << blankSeparator << frameIndex;
postExtensionCommand("locals", arguments, 0, postExtensionCommand("locals", arguments, 0,
[this, newFrame](const CdbCommandPtr &r) { handleLocals(r, newFrame); }); [this, newFrame](const CdbResponse &r) { handleLocals(r, newFrame); });
} }
void CdbEngine::selectThread(ThreadId threadId) void CdbEngine::selectThread(ThreadId threadId)
@@ -1549,7 +1564,7 @@ void CdbEngine::postDisassemblerCommand(quint64 address, quint64 endAddress,
ByteArrayInputStream str(cmd); ByteArrayInputStream str(cmd);
str << "u " << hex <<hexPrefixOn << address << ' ' << endAddress; str << "u " << hex <<hexPrefixOn << address << ' ' << endAddress;
postBuiltinCommand(cmd, 0, postBuiltinCommand(cmd, 0,
[this, agent](const CdbCommandPtr &r) { handleDisassembler(r, agent); }); [this, agent](const CdbResponse &r) { handleDisassembler(r, agent); });
} }
void CdbEngine::postResolveSymbol(const QString &module, const QString &function, void CdbEngine::postResolveSymbol(const QString &module, const QString &function,
@@ -1562,7 +1577,7 @@ void CdbEngine::postResolveSymbol(const QString &module, const QString &function
if (addresses.isEmpty()) { if (addresses.isEmpty()) {
showMessage(QLatin1String("Resolving symbol: ") + symbol + QLatin1String("..."), LogMisc); showMessage(QLatin1String("Resolving symbol: ") + symbol + QLatin1String("..."), LogMisc);
postBuiltinCommand(QByteArray("x ") + symbol.toLatin1(), 0, postBuiltinCommand(QByteArray("x ") + symbol.toLatin1(), 0,
[this, symbol, agent](const CdbCommandPtr &r) { handleResolveSymbol(r, symbol, agent); }); [this, symbol, agent](const CdbResponse &r) { handleResolveSymbol(r, symbol, agent); });
} else { } else {
showMessage(QString::fromLatin1("Using cached addresses for %1."). showMessage(QString::fromLatin1("Using cached addresses for %1.").
arg(symbol), LogMisc); arg(symbol), LogMisc);
@@ -1587,13 +1602,13 @@ static inline quint64 resolvedAddress(const QByteArray &line)
return 0; return 0;
} }
void CdbEngine::handleResolveSymbol(const CdbCommandPtr &command, const QString &symbol, void CdbEngine::handleResolveSymbol(const CdbResponse &response, const QString &symbol,
DisassemblerAgent *agent) DisassemblerAgent *agent)
{ {
// Insert all matches of (potentially) ambiguous symbols // Insert all matches of (potentially) ambiguous symbols
if (const int size = command->builtinReply.size()) { if (const int size = response.builtinReply.size()) {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (const quint64 address = resolvedAddress(command->builtinReply.at(i))) { if (const quint64 address = resolvedAddress(response.builtinReply.at(i))) {
m_symbolAddressCache.insert(symbol, address); m_symbolAddressCache.insert(symbol, address);
showMessage(QString::fromLatin1("Obtained 0x%1 for %2 (#%3)"). showMessage(QString::fromLatin1("Obtained 0x%1 for %2 (#%3)").
arg(address, 0, 16).arg(symbol).arg(i + 1), LogMisc); arg(address, 0, 16).arg(symbol).arg(i + 1), LogMisc);
@@ -1601,7 +1616,7 @@ void CdbEngine::handleResolveSymbol(const CdbCommandPtr &command, const QString
} }
} else { } else {
showMessage(QLatin1String("Symbol resolution failed: ") showMessage(QLatin1String("Symbol resolution failed: ")
+ QString::fromLatin1(command->joinedReply()), + QString::fromLatin1(response.joinedReply()),
LogError); LogError);
} }
handleResolveSymbolHelper(m_symbolAddressCache.values(symbol), agent); handleResolveSymbolHelper(m_symbolAddressCache.values(symbol), agent);
@@ -1689,9 +1704,9 @@ void CdbEngine::handleResolveSymbolHelper(const QList<quint64> &addresses, Disas
} }
// Parse: "00000000`77606060 cc int 3" // Parse: "00000000`77606060 cc int 3"
void CdbEngine::handleDisassembler(const CdbCommandPtr &command, DisassemblerAgent *agent) void CdbEngine::handleDisassembler(const CdbResponse &response, DisassemblerAgent *agent)
{ {
agent->setContents(parseCdbDisassembler(command->builtinReply)); agent->setContents(parseCdbDisassembler(response.builtinReply));
} }
void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length) void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length)
@@ -1711,7 +1726,7 @@ void CdbEngine::postFetchMemory(const MemoryViewCookie &cookie)
ByteArrayInputStream str(args); ByteArrayInputStream str(args);
str << cookie.address << ' ' << cookie.length; str << cookie.address << ' ' << cookie.length;
postExtensionCommand("memory", args, 0, postExtensionCommand("memory", args, 0,
[this, cookie](const CdbCommandPtr &r) { handleMemory(r, cookie); }); [this, cookie](const CdbResponse &r) { handleMemory(r, cookie); });
} }
void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data) void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, const QByteArray &data)
@@ -1725,15 +1740,15 @@ void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, c
} }
} }
void CdbEngine::handleMemory(const CdbCommandPtr &command, const MemoryViewCookie &memViewCookie) void CdbEngine::handleMemory(const CdbResponse &response, const MemoryViewCookie &memViewCookie)
{ {
if (command->success && memViewCookie.agent) { if (response.success && memViewCookie.agent) {
const QByteArray data = QByteArray::fromBase64(command->extensionReply); const QByteArray data = QByteArray::fromBase64(response.extensionReply);
if (unsigned(data.size()) == memViewCookie.length) if (unsigned(data.size()) == memViewCookie.length)
memViewCookie.agent->addLazyData(memViewCookie.editorToken, memViewCookie.agent->addLazyData(memViewCookie.editorToken,
memViewCookie.address, data); memViewCookie.address, data);
} else { } else {
showMessage(QString::fromLocal8Bit(command->errorMessage), LogWarning); showMessage(QString::fromLocal8Bit(response.errorMessage), LogWarning);
} }
} }
@@ -1771,27 +1786,27 @@ void CdbEngine::reloadFullStack()
postCommandSequence(CommandListStack); postCommandSequence(CommandListStack);
} }
void CdbEngine::handlePid(const CdbCommandPtr &reply) void CdbEngine::handlePid(const CdbResponse &response)
{ {
// Fails for core dumps. // Fails for core dumps.
if (reply->success) if (response.success)
notifyInferiorPid(reply->extensionReply.toULongLong()); notifyInferiorPid(response.extensionReply.toULongLong());
if (reply->success || startParameters().startMode == AttachCore) { if (response.success || startParameters().startMode == AttachCore) {
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupOk") STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupOk")
notifyInferiorSetupOk(); notifyInferiorSetupOk();
} else { } else {
showMessage(QString::fromLatin1("Failed to determine inferior pid: %1"). showMessage(QString::fromLatin1("Failed to determine inferior pid: %1").
arg(QLatin1String(reply->errorMessage)), LogError); arg(QLatin1String(response.errorMessage)), LogError);
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupFailed") STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupFailed")
notifyInferiorSetupFailed(); notifyInferiorSetupFailed();
} }
} }
void CdbEngine::handleModules(const CdbCommandPtr &reply) void CdbEngine::handleModules(const CdbResponse &response)
{ {
if (reply->success) { if (response.success) {
GdbMi value; GdbMi value;
value.fromString(reply->extensionReply); value.fromString(response.extensionReply);
if (value.type() == GdbMi::List) { if (value.type() == GdbMi::List) {
ModulesHandler *handler = modulesHandler(); ModulesHandler *handler = modulesHandler();
handler->beginUpdateAll(); handler->beginUpdateAll();
@@ -1808,21 +1823,21 @@ void CdbEngine::handleModules(const CdbCommandPtr &reply)
handler->endUpdateAll(); handler->endUpdateAll();
} else { } else {
showMessage(QString::fromLatin1("Parse error in modules response."), LogError); showMessage(QString::fromLatin1("Parse error in modules response."), LogError);
qWarning("Parse error in modules response:\n%s", reply->extensionReply.constData()); qWarning("Parse error in modules response:\n%s", response.extensionReply.constData());
} }
} else { } else {
showMessage(QString::fromLatin1("Failed to determine modules: %1"). showMessage(QString::fromLatin1("Failed to determine modules: %1").
arg(QLatin1String(reply->errorMessage)), LogError); arg(QLatin1String(response.errorMessage)), LogError);
} }
postCommandSequence(reply->commandSequence); postCommandSequence(response.commandSequence);
} }
void CdbEngine::handleRegistersExt(const CdbCommandPtr &reply) void CdbEngine::handleRegistersExt(const CdbResponse &response)
{ {
if (reply->success) { if (response.success) {
GdbMi value; GdbMi value;
value.fromString(reply->extensionReply); value.fromString(response.extensionReply);
if (value.type() == GdbMi::List) { if (value.type() == GdbMi::List) {
RegisterHandler *handler = registerHandler(); RegisterHandler *handler = registerHandler();
foreach (const GdbMi &item, value.children()) { foreach (const GdbMi &item, value.children()) {
@@ -1837,20 +1852,20 @@ void CdbEngine::handleRegistersExt(const CdbCommandPtr &reply)
handler->commitUpdates(); handler->commitUpdates();
} else { } else {
showMessage(QString::fromLatin1("Parse error in registers response."), LogError); showMessage(QString::fromLatin1("Parse error in registers response."), LogError);
qWarning("Parse error in registers response:\n%s", reply->extensionReply.constData()); qWarning("Parse error in registers response:\n%s", response.extensionReply.constData());
} }
} else { } else {
showMessage(QString::fromLatin1("Failed to determine registers: %1"). showMessage(QString::fromLatin1("Failed to determine registers: %1").
arg(QLatin1String(reply->errorMessage)), LogError); arg(QLatin1String(response.errorMessage)), LogError);
} }
postCommandSequence(reply->commandSequence); postCommandSequence(response.commandSequence);
} }
void CdbEngine::handleLocals(const CdbCommandPtr &reply, bool newFrame) void CdbEngine::handleLocals(const CdbResponse &response, bool newFrame)
{ {
if (reply->success) { if (response.success) {
if (boolSetting(VerboseLog)) if (boolSetting(VerboseLog))
showMessage(QLatin1String("Locals: ") + QString::fromLatin1(reply->extensionReply), LogDebug); showMessage(QLatin1String("Locals: ") + QString::fromLatin1(response.extensionReply), LogDebug);
QList<WatchData> watchData; QList<WatchData> watchData;
WatchHandler *handler = watchHandler(); WatchHandler *handler = watchHandler();
if (newFrame) { if (newFrame) {
@@ -1858,7 +1873,7 @@ void CdbEngine::handleLocals(const CdbCommandPtr &reply, bool newFrame)
watchData.append(*handler->findData("watch")); watchData.append(*handler->findData("watch"));
} }
GdbMi root; GdbMi root;
root.fromString(reply->extensionReply); root.fromString(response.extensionReply);
QTC_ASSERT(root.type() == GdbMi::List, return); QTC_ASSERT(root.type() == GdbMi::List, return);
if (debugLocals) if (debugLocals)
qDebug() << root.toString(true, 4); qDebug() << root.toString(true, 4);
@@ -1890,14 +1905,14 @@ void CdbEngine::handleLocals(const CdbCommandPtr &reply, bool newFrame)
DebuggerToolTipManager::updateEngine(this); DebuggerToolTipManager::updateEngine(this);
} }
} else { } else {
showMessage(QString::fromLatin1(reply->errorMessage), LogWarning); showMessage(QString::fromLatin1(response.errorMessage), LogWarning);
} }
} }
void CdbEngine::handleExpandLocals(const CdbCommandPtr &reply) void CdbEngine::handleExpandLocals(const CdbResponse &response)
{ {
if (!reply->success) if (!response.success)
showMessage(QString::fromLatin1(reply->errorMessage), LogError); showMessage(QString::fromLatin1(response.errorMessage), LogError);
} }
enum CdbExecutionStatus { enum CdbExecutionStatus {
@@ -2032,7 +2047,7 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
exp.append('"'); exp.append('"');
} }
postExtensionCommand("expression", exp, 0, postExtensionCommand("expression", exp, 0,
[this, id, stopReason](const CdbCommandPtr &r) { handleExpression(r, id, stopReason); }); [this, id, stopReason](const CdbResponse &r) { handleExpression(r, id, stopReason); });
return StopReportLog; return StopReportLog;
} }
@@ -2196,7 +2211,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
return; return;
case ParseStackWow64: case ParseStackWow64:
postBuiltinCommand("lm m wow64", 0, postBuiltinCommand("lm m wow64", 0,
[this, stack](const CdbCommandPtr &r) { handleCheckWow64(r, stack); }); [this, stack](const CdbResponse &r) { handleCheckWow64(r, stack); });
break; break;
} }
} else { } else {
@@ -2225,9 +2240,9 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
showStoppedByExceptionMessageBox(exceptionBoxMessage); showStoppedByExceptionMessageBox(exceptionBoxMessage);
} }
void CdbEngine::handleBreakInsert(const CdbCommandPtr &cmd) void CdbEngine::handleBreakInsert(const CdbResponse &response)
{ {
const QList<QByteArray> &reply = cmd->builtinReply; const QList<QByteArray> &reply = response.builtinReply;
if (reply.isEmpty()) if (reply.isEmpty())
return; return;
foreach (const QByteArray &line, reply) foreach (const QByteArray &line, reply)
@@ -2249,12 +2264,12 @@ void CdbEngine::handleBreakInsert(const CdbCommandPtr &cmd)
// extract break point model id from command // extract break point model id from command
QRegExp numberRegEx(QLatin1String("\\d")); QRegExp numberRegEx(QLatin1String("\\d"));
const int numberStart = numberRegEx.indexIn(QLatin1String(cmd->command)); const int numberStart = numberRegEx.indexIn(QLatin1String(response.command));
if (numberStart == -1) if (numberStart == -1)
return; return;
const int numberEnd = cmd->command.indexOf(' ', numberStart); const int numberEnd = response.command.indexOf(' ', numberStart);
bool ok = true; bool ok = true;
const int cdbBreakPointId = cmd->command.mid(numberStart, numberEnd - numberStart).toInt(&ok); const int cdbBreakPointId = response.command.mid(numberStart, numberEnd - numberStart).toInt(&ok);
if (!ok) if (!ok)
return; return;
const BreakpointModelId &originalId = cdbIdToBreakpointModelId(cdbBreakPointId); const BreakpointModelId &originalId = cdbIdToBreakpointModelId(cdbBreakPointId);
@@ -2289,26 +2304,26 @@ void CdbEngine::handleBreakInsert(const CdbCommandPtr &cmd)
attemptBreakpointSynchronization(); attemptBreakpointSynchronization();
} }
void CdbEngine::handleCheckWow64(const CdbCommandPtr &cmd, const GdbMi &stack) void CdbEngine::handleCheckWow64(const CdbResponse &response, const GdbMi &stack)
{ {
// Using the lm (list modules) command to check if there is a 32 bit subsystem in this debuggee. // Using the lm (list modules) command to check if there is a 32 bit subsystem in this debuggee.
// expected reply if there is a 32 bit stack: // expected reply if there is a 32 bit stack:
// start end module name // start end module name
// 00000000`77490000 00000000`774d5000 wow64 (deferred) // 00000000`77490000 00000000`774d5000 wow64 (deferred)
if (cmd->builtinReply.value(1).contains("wow64")) { if (response.builtinReply.value(1).contains("wow64")) {
postBuiltinCommand("k", 0, postBuiltinCommand("k", 0,
[this, stack](const CdbCommandPtr &r) { ensureUsing32BitStackInWow64(r, stack); }); [this, stack](const CdbResponse &r) { ensureUsing32BitStackInWow64(r, stack); });
return; return;
} }
m_wow64State = noWow64Stack; m_wow64State = noWow64Stack;
parseStackTrace(stack, false); parseStackTrace(stack, false);
} }
void CdbEngine::ensureUsing32BitStackInWow64(const CdbEngine::CdbCommandPtr &cmd, const GdbMi &stack) void CdbEngine::ensureUsing32BitStackInWow64(const CdbResponse &response, const GdbMi &stack)
{ {
// Parsing the header of the stack output to check which bitness // Parsing the header of the stack output to check which bitness
// the cdb is currently using. // the cdb is currently using.
foreach (const QByteArray &line, cmd->builtinReply) { foreach (const QByteArray &line, response.builtinReply) {
if (!line.startsWith("Child")) if (!line.startsWith("Child"))
continue; continue;
if (line.startsWith("ChildEBP")) { if (line.startsWith("ChildEBP")) {
@@ -2325,11 +2340,11 @@ void CdbEngine::ensureUsing32BitStackInWow64(const CdbEngine::CdbCommandPtr &cmd
parseStackTrace(stack, false); parseStackTrace(stack, false);
} }
void CdbEngine::handleSwitchWow64Stack(const CdbEngine::CdbCommandPtr &cmd) void CdbEngine::handleSwitchWow64Stack(const CdbResponse &response)
{ {
if (cmd->builtinReply.first() == "Switched to 32bit mode") if (response.builtinReply.first() == "Switched to 32bit mode")
m_wow64State = wow64Stack32Bit; m_wow64State = wow64Stack32Bit;
else if (cmd->builtinReply.first() == "Switched to 64bit mode") else if (response.builtinReply.first() == "Switched to 64bit mode")
m_wow64State = wow64Stack64Bit; m_wow64State = wow64Stack64Bit;
else else
m_wow64State = noWow64Stack; m_wow64State = noWow64Stack;
@@ -2423,17 +2438,18 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QByteArray &what
// Did the command finish? Take off queue and complete, invoke CB // Did the command finish? Take off queue and complete, invoke CB
const CdbCommandPtr command = m_extensionCommandQueue.takeAt(index); const CdbCommandPtr command = m_extensionCommandQueue.takeAt(index);
if (t == 'R') { if (t == 'R') {
command->success = true; command->response.success = true;
command->extensionReply = message; command->response.extensionReply = message;
} else { } else {
command->success = false; command->response.success = false;
command->errorMessage = message; command->response.errorMessage = message;
} }
if (debug) if (debug)
qDebug("### Completed extension command '%s', token=%d, pending=%d", qDebug("### Completed extension command '%s', token=%d, pending=%d",
command->command.constData(), command->token, m_extensionCommandQueue.size()); command->response.command.constData(), command->token, m_extensionCommandQueue.size());
if (command->handler) if (command->handler) {
command->handler(command); command->handler(command->response);
}
return; return;
} }
} }
@@ -2588,16 +2604,17 @@ void CdbEngine::parseOutputLine(QByteArray line)
// Did the command finish? Invoke callback and remove from queue. // Did the command finish? Invoke callback and remove from queue.
if (debug) if (debug)
qDebug("### Completed builtin command '%s', token=%d, %d lines, pending=%d", qDebug("### Completed builtin command '%s', token=%d, %d lines, pending=%d",
currentCommand->command.constData(), currentCommand->token, currentCommand->response.command.constData(), currentCommand->token,
currentCommand->builtinReply.size(), m_builtinCommandQueue.size() - 1); currentCommand->response.builtinReply.size(), m_builtinCommandQueue.size() - 1);
QTC_ASSERT(token == currentCommand->token, return; ); QTC_ASSERT(token == currentCommand->token, return; );
if (currentCommand->handler) if (currentCommand->handler) {
currentCommand->handler(currentCommand); currentCommand->handler(currentCommand->response);
}
m_builtinCommandQueue.removeAt(m_currentBuiltinCommandIndex); m_builtinCommandQueue.removeAt(m_currentBuiltinCommandIndex);
m_currentBuiltinCommandIndex = -1; m_currentBuiltinCommandIndex = -1;
} else { } else {
// Record output of current command // Record output of current command
currentCommand->builtinReply.push_back(line); currentCommand->response.builtinReply.push_back(line);
} }
return; return;
} // m_currentCommandIndex } // m_currentCommandIndex
@@ -2608,7 +2625,8 @@ void CdbEngine::parseOutputLine(QByteArray line)
m_currentBuiltinCommandIndex = index; m_currentBuiltinCommandIndex = index;
const CdbCommandPtr &currentCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex); const CdbCommandPtr &currentCommand = m_builtinCommandQueue.at(m_currentBuiltinCommandIndex);
if (debug) if (debug)
qDebug("### Gathering output for '%s' token %d", currentCommand->command.constData(), currentCommand->token); qDebug("### Gathering output for '%s' token %d",
currentCommand->response.command.constData(), currentCommand->token);
return; return;
} }
const char versionString[] = "Microsoft (R) Windows Debugger Version"; const char versionString[] = "Microsoft (R) Windows Debugger Version";
@@ -3018,16 +3036,16 @@ void CdbEngine::loadAdditionalQmlStack()
postExtensionCommand("qmlstack", QByteArray(), 0, CB(handleAdditionalQmlStack)); postExtensionCommand("qmlstack", QByteArray(), 0, CB(handleAdditionalQmlStack));
} }
void CdbEngine::handleAdditionalQmlStack(const CdbCommandPtr &reply) void CdbEngine::handleAdditionalQmlStack(const CdbResponse &response)
{ {
QString errorMessage; QString errorMessage;
do { do {
if (!reply->success) { if (!response.success) {
errorMessage = QLatin1String(reply->errorMessage); errorMessage = QLatin1String(response.errorMessage);
break; break;
} }
GdbMi stackGdbMi; GdbMi stackGdbMi;
stackGdbMi.fromString(reply->extensionReply); stackGdbMi.fromString(response.extensionReply);
if (!stackGdbMi.isValid()) { if (!stackGdbMi.isValid()) {
errorMessage = QLatin1String("GDBMI parser error"); errorMessage = QLatin1String("GDBMI parser error");
break; break;
@@ -3057,28 +3075,28 @@ void CdbEngine::mergeStartParametersSourcePathMap()
} }
} }
void CdbEngine::handleStackTrace(const CdbCommandPtr &command) void CdbEngine::handleStackTrace(const CdbResponse &response)
{ {
if (command->success) { if (response.success) {
GdbMi stack; GdbMi stack;
stack.fromString(command->extensionReply); stack.fromString(response.extensionReply);
if (parseStackTrace(stack, false) == ParseStackWow64) { if (parseStackTrace(stack, false) == ParseStackWow64) {
postBuiltinCommand("lm m wow64", 0, postBuiltinCommand("lm m wow64", 0,
[this, stack](const CdbCommandPtr &r) { handleCheckWow64(r, stack); }); [this, stack](const CdbResponse &r) { handleCheckWow64(r, stack); });
} }
postCommandSequence(command->commandSequence); postCommandSequence(response.commandSequence);
} else { } else {
showMessage(QString::fromLocal8Bit(command->errorMessage), LogError); showMessage(QString::fromLocal8Bit(response.errorMessage), LogError);
} }
} }
void CdbEngine::handleExpression(const CdbCommandPtr &command, BreakpointModelId id, const GdbMi &stopReason) void CdbEngine::handleExpression(const CdbResponse &response, BreakpointModelId id, const GdbMi &stopReason)
{ {
int value = 0; int value = 0;
if (command->success) if (response.success)
value = command->extensionReply.toInt(); value = response.extensionReply.toInt();
else else
showMessage(QString::fromLocal8Bit(command->errorMessage), LogError); showMessage(QString::fromLocal8Bit(response.errorMessage), LogError);
// Is this a conditional breakpoint? // Is this a conditional breakpoint?
const QString message = value ? const QString message = value ?
tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping."). tr("Value %1 obtained from evaluating the condition of breakpoint %2, stopping.").
@@ -3093,9 +3111,9 @@ void CdbEngine::handleExpression(const CdbCommandPtr &command, BreakpointModelId
doContinueInferior(); doContinueInferior();
} }
void CdbEngine::dummyHandler(const CdbCommandPtr &command) void CdbEngine::dummyHandler(const CdbResponse &command)
{ {
postCommandSequence(command->commandSequence); postCommandSequence(command.commandSequence);
} }
// Post a sequence of standard commands: Trigger next once one completes successfully // Post a sequence of standard commands: Trigger next once one completes successfully
@@ -3130,17 +3148,17 @@ void CdbEngine::postCommandSequence(unsigned mask)
} }
} }
void CdbEngine::handleWidgetAt(const CdbCommandPtr &reply) void CdbEngine::handleWidgetAt(const CdbResponse &response)
{ {
bool success = false; bool success = false;
QString message; QString message;
do { do {
if (!reply->success) { if (!response.success) {
message = QString::fromLatin1(reply->errorMessage); message = QString::fromLatin1(response.errorMessage);
break; break;
} }
// Should be "namespace::QWidget:0x555" // Should be "namespace::QWidget:0x555"
QString watchExp = QString::fromLatin1(reply->extensionReply); QString watchExp = QString::fromLatin1(response.extensionReply);
const int sepPos = watchExp.lastIndexOf(QLatin1Char(':')); const int sepPos = watchExp.lastIndexOf(QLatin1Char(':'));
if (sepPos == -1) { if (sepPos == -1) {
message = QString::fromLatin1("Invalid output: %1").arg(watchExp); message = QString::fromLatin1("Invalid output: %1").arg(watchExp);
@@ -3180,16 +3198,16 @@ static inline void formatCdbBreakPointResponse(BreakpointModelId id, const Break
str << '\n'; str << '\n';
} }
void CdbEngine::handleBreakPoints(const CdbCommandPtr &reply) void CdbEngine::handleBreakPoints(const CdbResponse &response)
{ {
if (debugBreakpoints) if (debugBreakpoints)
qDebug("CdbEngine::handleBreakPoints: success=%d: %s", reply->success, reply->extensionReply.constData()); qDebug("CdbEngine::handleBreakPoints: success=%d: %s", response.success, response.extensionReply.constData());
if (!reply->success) { if (!response.success) {
showMessage(QString::fromLatin1(reply->errorMessage), LogError); showMessage(QString::fromLatin1(response.errorMessage), LogError);
return; return;
} }
GdbMi value; GdbMi value;
value.fromString(reply->extensionReply); value.fromString(response.extensionReply);
if (value.type() != GdbMi::List) { if (value.type() != GdbMi::List) {
showMessage(QString::fromLatin1("Unabled to parse breakpoints reply"), LogError); showMessage(QString::fromLatin1("Unabled to parse breakpoints reply"), LogError);
return; return;

View File

@@ -49,7 +49,8 @@ namespace Debugger {
namespace Internal { namespace Internal {
class DisassemblerAgent; class DisassemblerAgent;
struct CdbCommand; class CdbCommand;
class CdbResponse;
struct MemoryViewCookie; struct MemoryViewCookie;
class ByteArrayInputStream; class ByteArrayInputStream;
class GdbMi; class GdbMi;
@@ -70,7 +71,7 @@ public:
}; };
typedef QSharedPointer<CdbCommand> CdbCommandPtr; typedef QSharedPointer<CdbCommand> CdbCommandPtr;
typedef std::function<void(const CdbCommandPtr &)> CommandHandler; typedef std::function<void(const CdbResponse &)> CommandHandler;
CdbEngine(const DebuggerStartParameters &sp); CdbEngine(const DebuggerStartParameters &sp);
~CdbEngine(); ~CdbEngine();
@@ -216,34 +217,34 @@ private:
void postResolveSymbol(const QString &module, const QString &function, void postResolveSymbol(const QString &module, const QString &function,
DisassemblerAgent *agent); DisassemblerAgent *agent);
// Builtin commands // Builtin commands
void dummyHandler(const CdbCommandPtr &); void dummyHandler(const CdbResponse &);
void handleStackTrace(const CdbCommandPtr &); void handleStackTrace(const CdbResponse &);
void handleRegisters(const CdbCommandPtr &); void handleRegisters(const CdbResponse &);
void handleDisassembler(const CdbCommandPtr &, DisassemblerAgent *agent); void handleDisassembler(const CdbResponse &, DisassemblerAgent *agent);
void handleJumpToLineAddressResolution(const CdbCommandPtr &, const ContextData &context); void handleJumpToLineAddressResolution(const CdbResponse &response, const ContextData &context);
void handleExpression(const CdbCommandPtr &command, BreakpointModelId id, const GdbMi &stopReason); void handleExpression(const CdbResponse &command, BreakpointModelId id, const GdbMi &stopReason);
void handleResolveSymbol(const CdbCommandPtr &command, const QString &symbol, DisassemblerAgent *agent); void handleResolveSymbol(const CdbResponse &command, const QString &symbol, DisassemblerAgent *agent);
void handleResolveSymbolHelper(const QList<quint64> &addresses, DisassemblerAgent *agent); void handleResolveSymbolHelper(const QList<quint64> &addresses, DisassemblerAgent *agent);
void handleBreakInsert(const CdbCommandPtr &cmd); void handleBreakInsert(const CdbResponse &response);
void handleCheckWow64(const CdbCommandPtr &cmd, const GdbMi &stack); void handleCheckWow64(const CdbResponse &response, const GdbMi &stack);
void ensureUsing32BitStackInWow64(const CdbCommandPtr &cmd, const GdbMi &stack); void ensureUsing32BitStackInWow64(const CdbResponse &response, const GdbMi &stack);
void handleSwitchWow64Stack(const CdbCommandPtr &cmd); void handleSwitchWow64Stack(const CdbResponse &response);
void jumpToAddress(quint64 address); void jumpToAddress(quint64 address);
void handleCreateFullBackTrace(const CdbCommandPtr &cmd); void handleCreateFullBackTrace(const CdbResponse &response);
// Extension commands // Extension commands
void handleThreads(const CdbCommandPtr &); void handleThreads(const CdbResponse &response);
void handlePid(const CdbCommandPtr &reply); void handlePid(const CdbResponse &response);
void handleLocals(const CdbCommandPtr &reply, bool newFrame); void handleLocals(const CdbResponse &response, bool newFrame);
void handleAddWatch(const CdbCommandPtr &reply, WatchData item); void handleAddWatch(const CdbResponse &response, WatchData item);
void handleExpandLocals(const CdbCommandPtr &reply); void handleExpandLocals(const CdbResponse &response);
void handleRegistersExt(const CdbCommandPtr &reply); void handleRegistersExt(const CdbResponse &response);
void handleModules(const CdbCommandPtr &reply); void handleModules(const CdbResponse &response);
void handleMemory(const CdbCommandPtr &, const MemoryViewCookie &memViewCookie); void handleMemory(const CdbResponse &response, const MemoryViewCookie &memViewCookie);
void handleWidgetAt(const CdbCommandPtr &); void handleWidgetAt(const CdbResponse &response);
void handleBreakPoints(const CdbCommandPtr &); void handleBreakPoints(const CdbResponse &response);
void handleBreakPoints(const GdbMi &value); void handleBreakPoints(const GdbMi &value);
void handleAdditionalQmlStack(const CdbCommandPtr &); void handleAdditionalQmlStack(const CdbResponse &response);
NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f); NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f);
void updateLocalVariable(const QByteArray &iname); void updateLocalVariable(const QByteArray &iname);
void updateLocals(bool forNewStackFrame); void updateLocals(bool forNewStackFrame);