Cdb: Replace CdbResponse with DebuggerResponse.

Change-Id: I2fddd5904de665bc7e6731ee4be69639d82258a0
Reviewed-by: Niels Weber <niels.weber@theqtcompany.com>
This commit is contained in:
David Schulz
2015-08-14 09:49:10 +02:00
parent be8290eefb
commit 845ee6a61d
2 changed files with 169 additions and 187 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 CdbResponse &r) { callback(r); } #define CB(callback) [this](const DebuggerResponse &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);
@@ -255,6 +255,7 @@ CdbEngine::CdbEngine(const DebuggerRunParameters &sp) :
m_accessible(false), m_accessible(false),
m_specialStopMode(NoSpecialStop), m_specialStopMode(NoSpecialStop),
m_nextCommandToken(0), m_nextCommandToken(0),
m_currentBuiltinResponseToken(-1),
m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."), m_extensionCommandPrefixBA("!" QT_CREATOR_CDB_EXT "."),
m_operateByInstructionPending(true), m_operateByInstructionPending(true),
m_operateByInstruction(true), // Default CDB setting m_operateByInstruction(true), // Default CDB setting
@@ -293,6 +294,7 @@ void CdbEngine::init()
m_accessible = false; m_accessible = false;
m_specialStopMode = NoSpecialStop; m_specialStopMode = NoSpecialStop;
m_nextCommandToken = 0; m_nextCommandToken = 0;
m_currentBuiltinResponseToken = -1;
m_operateByInstructionPending = action(OperateByInstruction)->isChecked(); m_operateByInstructionPending = action(OperateByInstruction)->isChecked();
m_verboseLogPending = boolSetting(VerboseLog); m_verboseLogPending = boolSetting(VerboseLog);
m_operateByInstruction = true; // Default CDB setting m_operateByInstruction = true; // Default CDB setting
@@ -306,6 +308,7 @@ void CdbEngine::init()
m_outputBuffer.clear(); m_outputBuffer.clear();
m_builtinCommandQueue.clear(); m_builtinCommandQueue.clear();
m_currentBuiltinResponse.clear();
m_extensionCommandQueue.clear(); m_extensionCommandQueue.clear();
m_extensionMessageBuffer.clear(); m_extensionMessageBuffer.clear();
m_pendingBreakpointMap.clear(); m_pendingBreakpointMap.clear();
@@ -495,9 +498,9 @@ void CdbEngine::createFullBacktrace()
postBuiltinCommand("~*kp", CB(handleCreateFullBackTrace)); postBuiltinCommand("~*kp", CB(handleCreateFullBackTrace));
} }
void CdbEngine::handleCreateFullBackTrace(const CdbResponse &response) void CdbEngine::handleCreateFullBackTrace(const DebuggerResponse &response)
{ {
Internal::openTextEditor(QLatin1String("Backtrace $"), QLatin1String(response.reply)); Internal::openTextEditor(QLatin1String("Backtrace $"), response.data.toLatin1());
} }
void CdbEngine::setupEngine() void CdbEngine::setupEngine()
@@ -688,7 +691,7 @@ void CdbEngine::setupInferior()
const BreakpointParameters bp(BreakpointAtMain); const BreakpointParameters bp(BreakpointAtMain);
BreakpointModelId id(quint16(-1)); BreakpointModelId id(quint16(-1));
postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true), postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, id, true),
[this, id](const CdbResponse &r){ handleBreakInsert(r, id); }); [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); });
} }
postCommand("sxn 0x4000001f"); // Do not break on WowX86 exceptions. postCommand("sxn 0x4000001f"); // Do not break on WowX86 exceptions.
postCommand("sxn ibp"); // Do not break on initial breakpoints. postCommand("sxn ibp"); // Do not break on initial breakpoints.
@@ -748,25 +751,25 @@ void CdbEngine::runEngine()
const QByteArray debugModule = module + 'D'; const QByteArray debugModule = module + 'D';
const QByteArray wideFunc = QByteArray(CdbOptionsPage::crtDbgReport).append('W'); const QByteArray wideFunc = QByteArray(CdbOptionsPage::crtDbgReport).append('W');
postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, module), postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, module),
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
postBuiltinCommand(breakAtFunctionCommand(wideFunc, module), postBuiltinCommand(breakAtFunctionCommand(wideFunc, module),
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, debugModule), postBuiltinCommand(breakAtFunctionCommand(CdbOptionsPage::crtDbgReport, debugModule),
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
postBuiltinCommand(breakAtFunctionCommand(wideFunc, debugModule), postBuiltinCommand(breakAtFunctionCommand(wideFunc, debugModule),
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
} }
if (boolSetting(BreakOnWarning)) { if (boolSetting(BreakOnWarning)) {
postBuiltinCommand("bm /( QtCored4!qWarning", // 'bm': All overloads. postBuiltinCommand("bm /( QtCored4!qWarning", // 'bm': All overloads.
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::warning", postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::warning",
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
} }
if (boolSetting(BreakOnFatal)) { if (boolSetting(BreakOnFatal)) {
postBuiltinCommand("bm /( QtCored4!qFatal", // 'bm': All overloads. postBuiltinCommand("bm /( QtCored4!qFatal", // 'bm': All overloads.
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::fatal", postBuiltinCommand("bm /( Qt5Cored!QMessageLogger::fatal",
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
} }
if (runParameters().startMode == AttachCore) { if (runParameters().startMode == AttachCore) {
QTC_ASSERT(!m_coreStopReason.isNull(), return; ); QTC_ASSERT(!m_coreStopReason.isNull(), return; );
@@ -1027,7 +1030,7 @@ void CdbEngine::executeRunToLine(const ContextData &data)
bp.lineNumber = data.lineNumber; bp.lineNumber = data.lineNumber;
} }
postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true),
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
continueInferior(); continueInferior();
} }
@@ -1038,7 +1041,7 @@ void CdbEngine::executeRunToFunction(const QString &functionName)
bp.functionName = functionName; bp.functionName = functionName;
postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true), postBuiltinCommand(cdbAddBreakpointCommand(bp, m_sourcePathMappings, BreakpointModelId(), true),
[this](const CdbResponse &r){ handleBreakInsert(r, BreakpointModelId()); }); [this](const DebuggerResponse &r) { handleBreakInsert(r, BreakpointModelId()); });
continueInferior(); continueInferior();
} }
@@ -1063,7 +1066,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, [this, data](const CdbResponse &r) { handleJumpToLineAddressResolution(r, data); }); postBuiltinCommand(cmd, [this, data](const DebuggerResponse &r) { handleJumpToLineAddressResolution(r, data); });
} }
} }
@@ -1080,13 +1083,13 @@ void CdbEngine::jumpToAddress(quint64 address)
postCommand(registerCmd); postCommand(registerCmd);
} }
void CdbEngine::handleJumpToLineAddressResolution(const CdbResponse &response, const ContextData &context) void CdbEngine::handleJumpToLineAddressResolution(const DebuggerResponse &response, const ContextData &context)
{ {
if (response.reply.isEmpty()) if (response.data.toLatin1().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 = response.reply.trimmed(); QByteArray answer = response.data.data().trimmed();
const int equalPos = answer.indexOf(" = "); const int equalPos = answer.indexOf(" = ");
if (equalPos == -1) if (equalPos == -1)
return; return;
@@ -1148,18 +1151,18 @@ void CdbEngine::assignValueInDebugger(WatchItem *w, const QString &expr, const Q
updateLocals(); updateLocals();
} }
void CdbEngine::handleThreads(const CdbResponse &response) void CdbEngine::handleThreads(const DebuggerResponse &response)
{ {
if (debug) if (debug) {
qDebug("CdbEngine::handleThreads success=%d", response.success); qDebug("CdbEngine::handleThreads %s",
if (response.success) { DebuggerResponse::stringFromResultClass(response.resultClass).data());
GdbMi data; }
data.fromString(response.reply); if (response.resultClass == ResultDone) {
threadsHandler()->updateThreads(data); threadsHandler()->updateThreads(response.data);
// Continue sequence // Continue sequence
reloadFullStack(); reloadFullStack();
} else { } else {
showMessage(QString::fromLatin1(response.errorMessage), LogError); showMessage(response.data["msg"].toLatin1(), LogError);
} }
} }
@@ -1359,7 +1362,7 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
str << blankSeparator << updateParameters.partialVariable; str << blankSeparator << updateParameters.partialVariable;
postExtensionCommand("locals", arguments, postExtensionCommand("locals", arguments,
[this, partialUpdate](const CdbResponse &r) { handleLocals(r, partialUpdate); }); [this, partialUpdate](const DebuggerResponse &r) { handleLocals(r, partialUpdate); });
} }
void CdbEngine::updateAll() void CdbEngine::updateAll()
@@ -1375,7 +1378,7 @@ void CdbEngine::selectThread(ThreadId threadId)
threadsHandler()->setCurrentThread(threadId); threadsHandler()->setCurrentThread(threadId);
const QByteArray cmd = '~' + QByteArray::number(threadId.raw()) + " s"; const QByteArray cmd = '~' + QByteArray::number(threadId.raw()) + " s";
postBuiltinCommand(cmd, [this](const CdbResponse &){ postBuiltinCommand(cmd, [this](const DebuggerResponse &) {
postExtensionCommand("stack", "unlimited", CB(handleStackTrace)); postExtensionCommand("stack", "unlimited", CB(handleStackTrace));
}); });
} }
@@ -1423,7 +1426,7 @@ void CdbEngine::postDisassemblerCommand(quint64 address, quint64 endAddress,
QByteArray cmd; QByteArray cmd;
ByteArrayInputStream str(cmd); ByteArrayInputStream str(cmd);
str << "u " << hex <<hexPrefixOn << address << ' ' << endAddress; str << "u " << hex <<hexPrefixOn << address << ' ' << endAddress;
postBuiltinCommand(cmd, [this, agent](const CdbResponse &r) { handleDisassembler(r, agent); }); postBuiltinCommand(cmd, [this, agent](const DebuggerResponse &r) { handleDisassembler(r, agent); });
} }
void CdbEngine::postResolveSymbol(const QString &module, const QString &function, void CdbEngine::postResolveSymbol(const QString &module, const QString &function,
@@ -1436,7 +1439,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(), postBuiltinCommand(QByteArray("x ") + symbol.toLatin1(),
[this, symbol, agent](const CdbResponse &r) { handleResolveSymbol(r, symbol, agent); }); [this, symbol, agent](const DebuggerResponse &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);
@@ -1461,12 +1464,12 @@ static inline quint64 resolvedAddress(const QByteArray &line)
return 0; return 0;
} }
void CdbEngine::handleResolveSymbol(const CdbResponse &response, const QString &symbol, void CdbEngine::handleResolveSymbol(const DebuggerResponse &response, const QString &symbol,
DisassemblerAgent *agent) DisassemblerAgent *agent)
{ {
// Insert all matches of (potentially) ambiguous symbols // Insert all matches of (potentially) ambiguous symbols
if (!response.reply.isEmpty()) { if (!response.data.data().isEmpty()) {
foreach (QByteArray line, response.reply.split('\n')) { foreach (QByteArray line, response.data.data().split('\n')) {
if (const quint64 address = resolvedAddress(line)) { if (const quint64 address = resolvedAddress(line)) {
m_symbolAddressCache.insert(symbol, address); m_symbolAddressCache.insert(symbol, address);
showMessage(QString::fromLatin1("Obtained 0x%1 for %2"). showMessage(QString::fromLatin1("Obtained 0x%1 for %2").
@@ -1475,7 +1478,7 @@ void CdbEngine::handleResolveSymbol(const CdbResponse &response, const QString &
} }
} else { } else {
showMessage(QLatin1String("Symbol resolution failed: ") showMessage(QLatin1String("Symbol resolution failed: ")
+ QString::fromLatin1(response.reply), + response.data["msg"].toLatin1(),
LogError); LogError);
} }
handleResolveSymbolHelper(m_symbolAddressCache.values(symbol), agent); handleResolveSymbolHelper(m_symbolAddressCache.values(symbol), agent);
@@ -1563,9 +1566,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 CdbResponse &response, DisassemblerAgent *agent) void CdbEngine::handleDisassembler(const DebuggerResponse &response, DisassemblerAgent *agent)
{ {
agent->setContents(parseCdbDisassembler(response.reply)); agent->setContents(parseCdbDisassembler(response.data.data()));
} }
void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length) void CdbEngine::fetchMemory(MemoryAgent *agent, QObject *editor, quint64 addr, quint64 length)
@@ -1585,7 +1588,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, postExtensionCommand("memory", args,
[this, cookie](const CdbResponse &r) { handleMemory(r, cookie); }); [this, cookie](const DebuggerResponse &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)
@@ -1599,15 +1602,15 @@ void CdbEngine::changeMemory(Internal::MemoryAgent *, QObject *, quint64 addr, c
} }
} }
void CdbEngine::handleMemory(const CdbResponse &response, const MemoryViewCookie &memViewCookie) void CdbEngine::handleMemory(const DebuggerResponse &response, const MemoryViewCookie &memViewCookie)
{ {
if (response.success && memViewCookie.agent) { if (response.resultClass == ResultDone && memViewCookie.agent) {
const QByteArray data = QByteArray::fromBase64(response.reply); const QByteArray data = QByteArray::fromBase64(response.data.data());
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(response.errorMessage), LogWarning); showMessage(response.data["msg"].toLatin1(), LogWarning);
} }
} }
@@ -1651,31 +1654,29 @@ void CdbEngine::listBreakpoints()
postExtensionCommand("breakpoints", QByteArray("-v"), CB(handleBreakPoints)); postExtensionCommand("breakpoints", QByteArray("-v"), CB(handleBreakPoints));
} }
void CdbEngine::handlePid(const CdbResponse &response) void CdbEngine::handlePid(const DebuggerResponse &response)
{ {
// Fails for core dumps. // Fails for core dumps.
if (response.success) if (response.resultClass == ResultDone)
notifyInferiorPid(response.reply.toULongLong()); notifyInferiorPid(response.data.data().toULongLong());
if (response.success || runParameters().startMode == AttachCore) { if (response.resultClass == ResultDone || runParameters().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(response.errorMessage)), LogError); arg(response.data["msg"].toLatin1()), LogError);
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupFailed") STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyInferiorSetupFailed")
notifyInferiorSetupFailed(); notifyInferiorSetupFailed();
} }
} }
void CdbEngine::handleModules(const CdbResponse &response) void CdbEngine::handleModules(const DebuggerResponse &response)
{ {
if (response.success) { if (response.resultClass == ResultDone) {
GdbMi value; if (response.data.type() == GdbMi::List) {
value.fromString(response.reply);
if (value.type() == GdbMi::List) {
ModulesHandler *handler = modulesHandler(); ModulesHandler *handler = modulesHandler();
handler->beginUpdateAll(); handler->beginUpdateAll();
foreach (const GdbMi &gdbmiModule, value.children()) { foreach (const GdbMi &gdbmiModule, response.data.children()) {
Module module; Module module;
module.moduleName = QString::fromLatin1(gdbmiModule["name"].data()); module.moduleName = QString::fromLatin1(gdbmiModule["name"].data());
module.modulePath = QString::fromLatin1(gdbmiModule["image"].data()); module.modulePath = QString::fromLatin1(gdbmiModule["image"].data());
@@ -1688,22 +1689,20 @@ void CdbEngine::handleModules(const CdbResponse &response)
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", response.reply.constData()); qWarning("Parse error in modules response:\n%s", response.data.data().data());
} }
} else { } else {
showMessage(QString::fromLatin1("Failed to determine modules: %1"). showMessage(QString::fromLatin1("Failed to determine modules: %1").
arg(QLatin1String(response.errorMessage)), LogError); arg(response.data["msg"].toLatin1()), LogError);
} }
} }
void CdbEngine::handleRegistersExt(const CdbResponse &response) void CdbEngine::handleRegistersExt(const DebuggerResponse &response)
{ {
if (response.success) { if (response.resultClass == ResultDone) {
GdbMi value; if (response.data.type() == GdbMi::List) {
value.fromString(response.reply);
if (value.type() == GdbMi::List) {
RegisterHandler *handler = registerHandler(); RegisterHandler *handler = registerHandler();
foreach (const GdbMi &item, value.children()) { foreach (const GdbMi &item, response.data.children()) {
Register reg; Register reg;
reg.name = item["name"].data(); reg.name = item["name"].data();
reg.description = item["description"].data(); reg.description = item["description"].data();
@@ -1715,43 +1714,38 @@ void CdbEngine::handleRegistersExt(const CdbResponse &response)
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", response.reply.constData()); qWarning("Parse error in registers response:\n%s", response.data.data().data());
} }
} else { } else {
showMessage(QString::fromLatin1("Failed to determine registers: %1"). showMessage(QString::fromLatin1("Failed to determine registers: %1").
arg(QLatin1String(response.errorMessage)), LogError); arg(response.data["msg"].toLatin1()), LogError);
} }
} }
void CdbEngine::handleLocals(const CdbResponse &response, bool partialUpdate) void CdbEngine::handleLocals(const DebuggerResponse &response, bool partialUpdate)
{ {
if (response.success) { if (response.resultClass == ResultDone) {
if (boolSetting(VerboseLog)) if (boolSetting(VerboseLog))
showMessage(QLatin1String("Locals: ") + QString::fromLatin1(response.reply), LogDebug); showMessage(QLatin1String(response.data.toString()), LogDebug);
GdbMi data;
data.fromString(response.reply);
QTC_ASSERT(data.type() == GdbMi::List, return);
data.m_name = "data";
GdbMi partial; GdbMi partial;
partial.m_name = "partial"; partial.m_name = "partial";
partial.m_data = QByteArray::number(partialUpdate ? 1 : 0); partial.m_data = QByteArray::number(partialUpdate ? 1 : 0);
GdbMi all; GdbMi all;
all.m_children.push_back(data); all.m_children.push_back(response.data);
all.m_children.push_back(partial); all.m_children.push_back(partial);
updateLocalsView(all); updateLocalsView(all);
} else { } else {
showMessage(QString::fromLatin1(response.errorMessage), LogWarning); showMessage(response.data["msg"].toLatin1(), LogWarning);
} }
watchHandler()->notifyUpdateFinished(); watchHandler()->notifyUpdateFinished();
} }
void CdbEngine::handleExpandLocals(const CdbResponse &response) void CdbEngine::handleExpandLocals(const DebuggerResponse &response)
{ {
if (!response.success) if (response.resultClass != ResultDone)
showMessage(QString::fromLatin1(response.errorMessage), LogError); showMessage(response.data["msg"].toLatin1(), LogError);
} }
enum CdbExecutionStatus { enum CdbExecutionStatus {
@@ -1886,7 +1880,7 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
exp.append('"'); exp.append('"');
} }
postExtensionCommand("expression", exp, postExtensionCommand("expression", exp,
[this, id, stopReason](const CdbResponse &r) { handleExpression(r, id, stopReason); }); [this, id, stopReason](const DebuggerResponse &r) { handleExpression(r, id, stopReason); });
return StopReportLog; return StopReportLog;
} }
@@ -2050,7 +2044,7 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
return; return;
case ParseStackWow64: case ParseStackWow64:
postBuiltinCommand("lm m wow64", postBuiltinCommand("lm m wow64",
[this, stack](const CdbResponse &r) { handleCheckWow64(r, stack); }); [this, stack](const DebuggerResponse &r) { handleCheckWow64(r, stack); });
break; break;
} }
} else { } else {
@@ -2079,9 +2073,9 @@ void CdbEngine::processStop(const GdbMi &stopReason, bool conditionalBreakPointT
showStoppedByExceptionMessageBox(exceptionBoxMessage); showStoppedByExceptionMessageBox(exceptionBoxMessage);
} }
void CdbEngine::handleBreakInsert(const CdbResponse &response, const BreakpointModelId &bpId) void CdbEngine::handleBreakInsert(const DebuggerResponse &response, const BreakpointModelId &bpId)
{ {
const QList<QByteArray> &reply = response.reply.split('\n'); const QList<QByteArray> &reply = response.data.data().split('\n');
if (reply.isEmpty()) if (reply.isEmpty())
return; return;
foreach (const QByteArray &line, reply) foreach (const QByteArray &line, reply)
@@ -2134,25 +2128,25 @@ void CdbEngine::handleBreakInsert(const CdbResponse &response, const BreakpointM
attemptBreakpointSynchronization(); attemptBreakpointSynchronization();
} }
void CdbEngine::handleCheckWow64(const CdbResponse &response, const GdbMi &stack) void CdbEngine::handleCheckWow64(const DebuggerResponse &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 (response.reply.contains("wow64")) { if (response.data.data().contains("wow64")) {
postBuiltinCommand("k", [this, stack](const CdbResponse &r) { ensureUsing32BitStackInWow64(r, stack); }); postBuiltinCommand("k", [this, stack](const DebuggerResponse &r) { ensureUsing32BitStackInWow64(r, stack); });
return; return;
} }
m_wow64State = noWow64Stack; m_wow64State = noWow64Stack;
parseStackTrace(stack, false); parseStackTrace(stack, false);
} }
void CdbEngine::ensureUsing32BitStackInWow64(const CdbResponse &response, const GdbMi &stack) void CdbEngine::ensureUsing32BitStackInWow64(const DebuggerResponse &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, response.reply.split('\n')) { foreach (const QByteArray &line, response.data.data().split('\n')) {
if (!line.startsWith("Child")) if (!line.startsWith("Child"))
continue; continue;
if (line.startsWith("ChildEBP")) { if (line.startsWith("ChildEBP")) {
@@ -2169,11 +2163,11 @@ void CdbEngine::ensureUsing32BitStackInWow64(const CdbResponse &response, const
parseStackTrace(stack, false); parseStackTrace(stack, false);
} }
void CdbEngine::handleSwitchWow64Stack(const CdbResponse &response) void CdbEngine::handleSwitchWow64Stack(const DebuggerResponse &response)
{ {
if (response.reply == "Switched to 32bit mode") if (response.data.data() == "Switched to 32bit mode")
m_wow64State = wow64Stack32Bit; m_wow64State = wow64Stack32Bit;
else if (response.reply == "Switched to 64bit mode") else if (response.data.data() == "Switched to 64bit mode")
m_wow64State = wow64Stack64Bit; m_wow64State = wow64Stack64Bit;
else else
m_wow64State = noWow64Stack; m_wow64State = noWow64Stack;
@@ -2272,13 +2266,23 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QByteArray &what
if (!command->handler) if (!command->handler)
return; return;
CdbResponse response; DebuggerResponse response;
response.data.m_name = "data";
if (t == 'R') { if (t == 'R') {
response.success = true; response.resultClass = ResultDone;
response.reply = message; response.data.fromString(message);
if (!response.data.isValid()) {
response.data.m_data = message;
response.data.m_type = GdbMi::Tuple;
}
} else { } else {
response.success = false; response.resultClass = ResultError;
response.errorMessage = message; GdbMi msg;
msg.m_name = "msg";
msg.m_data = message;
msg.m_type = GdbMi::Tuple;
response.data.m_type = GdbMi::Tuple;
response.data.m_children.push_back(msg);
} }
command->handler(response); command->handler(response);
return; return;
@@ -2432,35 +2436,42 @@ void CdbEngine::parseOutputLine(QByteArray line)
// If there is a current command, wait for end of output indicated by token, // If there is a current command, wait for end of output indicated by token,
// command, trigger handler and finish, else append to its output. // command, trigger handler and finish, else append to its output.
if (m_currentBuiltinResponse.token != -1) { if (m_currentBuiltinResponseToken != -1) {
QTC_ASSERT(!isStartToken, return); QTC_ASSERT(!isStartToken, return);
if (isCommandToken) { if (isCommandToken) {
// 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 for token=%d, %d lines, pending=%d", qDebug("### Completed builtin command for token=%d, %d lines, pending=%d",
m_currentBuiltinResponse.token, m_currentBuiltinResponse.reply.count('\n'), m_currentBuiltinResponseToken, m_currentBuiltinResponse.count('\n'),
m_builtinCommandQueue.size() - 1); m_builtinCommandQueue.size() - 1);
QTC_ASSERT(token == m_currentBuiltinResponse.token, return); QTC_ASSERT(token == m_currentBuiltinResponseToken, return);
if (boolSetting(VerboseLog)) if (boolSetting(VerboseLog))
showMessage(QLatin1String(m_currentBuiltinResponse.reply), LogMisc); showMessage(QLatin1String(m_currentBuiltinResponse), LogMisc);
const int commandIndex = indexOfCommand(m_builtinCommandQueue, m_currentBuiltinResponse.token); const int commandIndex = indexOfCommand(m_builtinCommandQueue, m_currentBuiltinResponseToken);
QTC_ASSERT(commandIndex >= 0 && commandIndex < m_builtinCommandQueue.size(), return); QTC_ASSERT(commandIndex >= 0 && commandIndex < m_builtinCommandQueue.size(), return);
const CdbCommandPtr &currentCommand = m_builtinCommandQueue.at(commandIndex); const CdbCommandPtr &currentCommand = m_builtinCommandQueue.at(commandIndex);
DebuggerResponse response;
response.token = token;
response.data.m_name = "data";
response.data.m_data = m_currentBuiltinResponse;
response.data.m_type = GdbMi::Tuple;
response.resultClass = ResultDone;
if (currentCommand->handler) if (currentCommand->handler)
currentCommand->handler(m_currentBuiltinResponse); currentCommand->handler(response);
m_builtinCommandQueue.removeAt(commandIndex); m_builtinCommandQueue.removeAt(commandIndex);
m_currentBuiltinResponseToken = -1;
m_currentBuiltinResponse.clear(); m_currentBuiltinResponse.clear();
} else { } else {
// Record output of current command // Record output of current command
if (!m_currentBuiltinResponse.reply.isEmpty()) if (!m_currentBuiltinResponse.isEmpty())
m_currentBuiltinResponse.reply.push_back('\n'); m_currentBuiltinResponse.push_back('\n');
m_currentBuiltinResponse.reply.push_back(line); m_currentBuiltinResponse.push_back(line);
} }
return; return;
} }
if (isCommandToken) { if (isCommandToken) {
// Beginning command token encountered, start to record output. // Beginning command token encountered, start to record output.
m_currentBuiltinResponse.token = token; m_currentBuiltinResponseToken = token;
if (debug) if (debug)
qDebug("### Gathering output for token %d", token); qDebug("### Gathering output for token %d", token);
return; return;
@@ -2700,11 +2711,11 @@ void CdbEngine::attemptBreakpointSynchronization()
response.lineNumber = lineCorrection->fixLineNumber(parameters.fileName, parameters.lineNumber); response.lineNumber = lineCorrection->fixLineNumber(parameters.fileName, parameters.lineNumber);
postBuiltinCommand( postBuiltinCommand(
cdbAddBreakpointCommand(response, m_sourcePathMappings, id, false), cdbAddBreakpointCommand(response, m_sourcePathMappings, id, false),
[this, id](const CdbResponse &r){ handleBreakInsert(r, id); }); [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); });
} else { } else {
postBuiltinCommand( postBuiltinCommand(
cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false),
[this, id](const CdbResponse &r){ handleBreakInsert(r, id); }); [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); });
} }
if (!parameters.enabled) if (!parameters.enabled)
postCommand("bd " + QByteArray::number(breakPointIdToCdbId(id))); postCommand("bd " + QByteArray::number(breakPointIdToCdbId(id)));
@@ -2737,7 +2748,7 @@ void CdbEngine::attemptBreakpointSynchronization()
postCommand(cdbClearBreakpointCommand(id)); postCommand(cdbClearBreakpointCommand(id));
postBuiltinCommand( postBuiltinCommand(
cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false), cdbAddBreakpointCommand(parameters, m_sourcePathMappings, id, false),
[this, id](const CdbResponse &r){ handleBreakInsert(r, id); }); [this, id](const DebuggerResponse &r) { handleBreakInsert(r, id); });
m_pendingBreakpointMap.insert(id, response); m_pendingBreakpointMap.insert(id, response);
} }
bp.notifyBreakpointChangeOk(); bp.notifyBreakpointChangeOk();
@@ -2885,21 +2896,19 @@ void CdbEngine::loadAdditionalQmlStack()
postExtensionCommand("qmlstack", QByteArray(), CB(handleAdditionalQmlStack)); postExtensionCommand("qmlstack", QByteArray(), CB(handleAdditionalQmlStack));
} }
void CdbEngine::handleAdditionalQmlStack(const CdbResponse &response) void CdbEngine::handleAdditionalQmlStack(const DebuggerResponse &response)
{ {
QString errorMessage; QString errorMessage;
do { do {
if (!response.success) { if (response.resultClass != ResultDone) {
errorMessage = QLatin1String(response.errorMessage); errorMessage = response.data["msg"].toLatin1();
break; break;
} }
GdbMi stackGdbMi; if (!response.data.isValid()) {
stackGdbMi.fromString(response.reply);
if (!stackGdbMi.isValid()) {
errorMessage = QLatin1String("GDBMI parser error"); errorMessage = QLatin1String("GDBMI parser error");
break; break;
} }
StackFrames qmlFrames = parseFrames(stackGdbMi); StackFrames qmlFrames = parseFrames(response.data);
const int qmlFrameCount = qmlFrames.size(); const int qmlFrameCount = qmlFrames.size();
if (!qmlFrameCount) { if (!qmlFrameCount) {
errorMessage = QLatin1String("Empty stack"); errorMessage = QLatin1String("Empty stack");
@@ -2924,27 +2933,26 @@ void CdbEngine::mergeStartParametersSourcePathMap()
} }
} }
void CdbEngine::handleStackTrace(const CdbResponse &response) void CdbEngine::handleStackTrace(const DebuggerResponse &response)
{ {
if (response.success) { GdbMi stack = response.data;
GdbMi stack; if (response.resultClass == ResultDone) {
stack.fromString(response.reply);
if (parseStackTrace(stack, false) == ParseStackWow64) { if (parseStackTrace(stack, false) == ParseStackWow64) {
postBuiltinCommand("lm m wow64", postBuiltinCommand("lm m wow64",
[this, stack](const CdbResponse &r) { handleCheckWow64(r, stack); }); [this, stack](const DebuggerResponse &r) { handleCheckWow64(r, stack); });
} }
} else { } else {
showMessage(QString::fromLocal8Bit(response.errorMessage), LogError); showMessage(stack["msg"].toLatin1(), LogError);
} }
} }
void CdbEngine::handleExpression(const CdbResponse &response, BreakpointModelId id, const GdbMi &stopReason) void CdbEngine::handleExpression(const DebuggerResponse &response, BreakpointModelId id, const GdbMi &stopReason)
{ {
int value = 0; int value = 0;
if (response.success) if (response.resultClass == ResultDone)
value = response.reply.toInt(); value = response.data.toInt();
else else
showMessage(QString::fromLocal8Bit(response.errorMessage), LogError); showMessage(response.data["msg"].toLatin1(), 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.").
@@ -2959,17 +2967,17 @@ void CdbEngine::handleExpression(const CdbResponse &response, BreakpointModelId
doContinueInferior(); doContinueInferior();
} }
void CdbEngine::handleWidgetAt(const CdbResponse &response) void CdbEngine::handleWidgetAt(const DebuggerResponse &response)
{ {
bool success = false; bool success = false;
QString message; QString message;
do { do {
if (!response.success) { if (response.resultClass != ResultDone) {
message = QString::fromLatin1(response.errorMessage); message = response.data["msg"].toLatin1();
break; break;
} }
// Should be "namespace::QWidget:0x555" // Should be "namespace::QWidget:0x555"
QString watchExp = QString::fromLatin1(response.reply); QString watchExp = response.data.toLatin1();
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);
@@ -3009,33 +3017,29 @@ static inline void formatCdbBreakPointResponse(BreakpointModelId id, const Break
str << '\n'; str << '\n';
} }
void CdbEngine::handleBreakPoints(const CdbResponse &response) void CdbEngine::handleBreakPoints(const DebuggerResponse &response)
{ {
if (debugBreakpoints) if (true) {
qDebug("CdbEngine::handleBreakPoints: success=%d: %s", response.success, response.reply.constData()); qDebug("CdbEngine::handleBreakPoints: success=%d: %s",
if (!response.success) { response.resultClass == ResultDone, QLatin1String(response.data.toString()).data());
showMessage(QString::fromLatin1(response.errorMessage), LogError); }
if (response.resultClass != ResultDone) {
showMessage(response.data["msg"].toLatin1(), LogError);
return; return;
} }
GdbMi value; if (response.data.type() != GdbMi::List) {
value.fromString(response.reply); showMessage(QString::fromLatin1("Unable to parse breakpoints reply"), LogError);
if (value.type() != GdbMi::List) {
showMessage(QString::fromLatin1("Unabled to parse breakpoints reply"), LogError);
return; return;
} }
handleBreakPoints(value);
}
void CdbEngine::handleBreakPoints(const GdbMi &value)
{
// Report all obtained parameters back. Note that not all parameters are reported // Report all obtained parameters back. Note that not all parameters are reported
// back, so, match by id and complete // back, so, match by id and complete
if (debugBreakpoints) if (debugBreakpoints)
qDebug("\nCdbEngine::handleBreakPoints with %d", value.childCount()); qDebug("\nCdbEngine::handleBreakPoints with %d", response.data.childCount());
QString message; QString message;
QTextStream str(&message); QTextStream str(&message);
BreakHandler *handler = breakHandler(); BreakHandler *handler = breakHandler();
foreach (const GdbMi &breakPointG, value.children()) { foreach (const GdbMi &breakPointG, response.data.children()) {
BreakpointResponse reportedResponse; BreakpointResponse reportedResponse;
parseBreakPoint(breakPointG, &reportedResponse); parseBreakPoint(breakPointG, &reportedResponse);
if (debugBreakpoints) if (debugBreakpoints)

View File

@@ -54,35 +54,13 @@ struct MemoryViewCookie;
class ByteArrayInputStream; class ByteArrayInputStream;
class GdbMi; class GdbMi;
class CdbResponse
{
// TODO: replace with DebuggerResponse
public:
CdbResponse()
: token(-1), success(false)
{}
void clear()
{
token = -1;
reply.clear();
errorMessage.clear();
success = false;
}
int token;
QByteArray reply;
QByteArray errorMessage;
bool success;
};
class CdbEngine : public DebuggerEngine class CdbEngine : public DebuggerEngine
{ {
Q_OBJECT Q_OBJECT
public: public:
typedef QSharedPointer<CdbCommand> CdbCommandPtr; typedef QSharedPointer<CdbCommand> CdbCommandPtr;
typedef std::function<void(const CdbResponse &)> CommandHandler; typedef std::function<void(const DebuggerResponse &)> CommandHandler;
CdbEngine(const DebuggerRunParameters &sp); CdbEngine(const DebuggerRunParameters &sp);
~CdbEngine(); ~CdbEngine();
@@ -224,32 +202,31 @@ 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 handleStackTrace(const CdbResponse &); void handleStackTrace(const DebuggerResponse &);
void handleRegisters(const CdbResponse &); void handleRegisters(const DebuggerResponse &);
void handleDisassembler(const CdbResponse &, DisassemblerAgent *agent); void handleDisassembler(const DebuggerResponse &, DisassemblerAgent *agent);
void handleJumpToLineAddressResolution(const CdbResponse &response, const ContextData &context); void handleJumpToLineAddressResolution(const DebuggerResponse &response, const ContextData &context);
void handleExpression(const CdbResponse &command, BreakpointModelId id, const GdbMi &stopReason); void handleExpression(const DebuggerResponse &command, BreakpointModelId id, const GdbMi &stopReason);
void handleResolveSymbol(const CdbResponse &command, const QString &symbol, DisassemblerAgent *agent); void handleResolveSymbol(const DebuggerResponse &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 CdbResponse &response, const BreakpointModelId &bpId); void handleBreakInsert(const DebuggerResponse &response, const BreakpointModelId &bpId);
void handleCheckWow64(const CdbResponse &response, const GdbMi &stack); void handleCheckWow64(const DebuggerResponse &response, const GdbMi &stack);
void ensureUsing32BitStackInWow64(const CdbResponse &response, const GdbMi &stack); void ensureUsing32BitStackInWow64(const DebuggerResponse &response, const GdbMi &stack);
void handleSwitchWow64Stack(const CdbResponse &response); void handleSwitchWow64Stack(const DebuggerResponse &response);
void jumpToAddress(quint64 address); void jumpToAddress(quint64 address);
void handleCreateFullBackTrace(const CdbResponse &response); void handleCreateFullBackTrace(const DebuggerResponse &response);
// Extension commands // Extension commands
void handleThreads(const CdbResponse &response); void handleThreads(const DebuggerResponse &response);
void handlePid(const CdbResponse &response); void handlePid(const DebuggerResponse &response);
void handleLocals(const CdbResponse &response, bool partialUpdate); void handleLocals(const DebuggerResponse &response, bool partialUpdate);
void handleExpandLocals(const CdbResponse &response); void handleExpandLocals(const DebuggerResponse &response);
void handleRegistersExt(const CdbResponse &response); void handleRegistersExt(const DebuggerResponse &response);
void handleModules(const CdbResponse &response); void handleModules(const DebuggerResponse &response);
void handleMemory(const CdbResponse &response, const MemoryViewCookie &memViewCookie); void handleMemory(const DebuggerResponse &response, const MemoryViewCookie &memViewCookie);
void handleWidgetAt(const CdbResponse &response); void handleWidgetAt(const DebuggerResponse &response);
void handleBreakPoints(const CdbResponse &response); void handleBreakPoints(const DebuggerResponse &response);
void handleBreakPoints(const GdbMi &value); void handleAdditionalQmlStack(const DebuggerResponse &response);
void handleAdditionalQmlStack(const CdbResponse &response);
NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f); NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f);
void doUpdateLocals(const UpdateParameters &params) override; void doUpdateLocals(const UpdateParameters &params) override;
void updateAll() override; void updateAll() override;
@@ -269,7 +246,8 @@ private:
ProjectExplorer::DeviceProcessSignalOperation::Ptr m_signalOperation; ProjectExplorer::DeviceProcessSignalOperation::Ptr m_signalOperation;
int m_nextCommandToken; int m_nextCommandToken;
QList<CdbCommandPtr> m_builtinCommandQueue; QList<CdbCommandPtr> m_builtinCommandQueue;
CdbResponse m_currentBuiltinResponse; //!< Current command whose output is recorded. QByteArray m_currentBuiltinResponse;
int m_currentBuiltinResponseToken;
QList<CdbCommandPtr> m_extensionCommandQueue; QList<CdbCommandPtr> m_extensionCommandQueue;
QMap<QString, NormalizedSourceFileName> m_normalizedFileCache; QMap<QString, NormalizedSourceFileName> m_normalizedFileCache;
const QByteArray m_extensionCommandPrefixBA; //!< Library name used as prefix const QByteArray m_extensionCommandPrefixBA; //!< Library name used as prefix