Commit 53295db9 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Debugger[CDB]: Display more context in disassembly.

Emulate gdb's behaviour trying to disassemble the function.

Task-number: QTCREATORBUG-5205
Change-Id: I2f4dc9393e12324b0423734c5235758a25395fec
Reviewed-on: http://codereview.qt.nokia.com/1029

Reviewed-by: default avatarQt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: default avatarFriedemann Kleint <Friedemann.Kleint@nokia.com>
parent a8b248f4
......@@ -478,6 +478,7 @@ void CdbEngine::init()
m_extensionMessageBuffer.clear();
m_pendingBreakpointMap.clear();
m_customSpecialStopData.clear();
m_symbolAddressCache.clear();
// Create local list of mappings in native separators
m_sourcePathMappings.clear();
......@@ -1532,16 +1533,149 @@ void CdbEngine::selectThread(int index)
postBuiltinCommand(cmd, 0, &CdbEngine::dummyHandler, CommandListStack);
}
// Default address range for showing disassembly.
enum { DisassemblerRange = 512 };
/* Try to emulate gdb's behaviour: When passed an address, display
* the disassembled function. CDB's 'u' (disassemble) command takes a symbol,
* but does not display the whole function, only 10 lines per default.
* So, to ensure the agent's
* address is in that range, resolve the function symbol, cache it and
* request the disassembly for a range that contains the agent's address. */
void CdbEngine::fetchDisassembler(DisassemblerAgent *agent)
{
QTC_ASSERT(m_accessible, return;)
const QString function = agent->location().functionName();
const QString module = agent->location().from();
const QVariant cookie = qVariantFromValue<DisassemblerAgent*>(agent);
if (function.isEmpty() || module.isEmpty()) {
// No function, display a default range.
postDisassemblerCommand(agent->address(), cookie);
} else {
postResolveSymbol(module, function, cookie);
}
}
void CdbEngine::postDisassemblerCommand(quint64 address, const QVariant &cookie)
{
postDisassemblerCommand(address - DisassemblerRange / 2,
address + DisassemblerRange / 2, cookie);
}
void CdbEngine::postDisassemblerCommand(quint64 address, quint64 endAddress,
const QVariant &cookie)
{
QByteArray cmd;
ByteArrayInputStream str(cmd);
str << "u " << hex << hexPrefixOn << agent->address() << " L40";
const QVariant cookie = qVariantFromValue<DisassemblerAgent*>(agent);
str << "u " << hex <<hexPrefixOn << address << ' ' << endAddress;
postBuiltinCommand(cmd, 0, &CdbEngine::handleDisassembler, 0, cookie);
}
void CdbEngine::postResolveSymbol(const QString &module, const QString &function,
const QVariant &cookie)
{
const QString symbol = module + QLatin1Char('!') + function;
const QList<quint64> addresses = m_symbolAddressCache.values(symbol);
if (addresses.isEmpty()) {
QVariantList cookieList;
cookieList << QVariant(symbol) << cookie;
showMessage(QLatin1String("Resolving symbol: ") + symbol, LogMisc);
postBuiltinCommand(QByteArray("x ") + symbol.toLatin1(), 0,
&CdbEngine::handleResolveSymbol, 0,
QVariant(cookieList));
} else {
showMessage(QString::fromLatin1("Using cached addresses for %1.").
arg(symbol), LogMisc);
handleResolveSymbol(addresses, cookie);
}
}
// Parse address from 'x' response.
// "00000001`3f7ebe80 module!foo (void)"
static inline quint64 resolvedAddress(const QByteArray &line)
{
const int blankPos = line.indexOf(' ');
if (blankPos >= 0) {
QByteArray addressBA = line.left(blankPos);
if (addressBA.size() > 9 && addressBA.at(8) == '`')
addressBA.remove(8, 1);
bool ok;
const quint64 address = addressBA.toULongLong(&ok, 16);
if (ok)
return address;
}
return 0;
}
void CdbEngine::handleResolveSymbol(const CdbBuiltinCommandPtr &command)
{
QTC_ASSERT(command->cookie.type() == QVariant::List, return; );
const QVariantList cookieList = command->cookie.toList();
const QString symbol = cookieList.front().toString();
// Insert all matches of (potentially) ambiguous symbols
if (const int size = command->reply.size()) {
for (int i = 0; i < size; i++) {
if (const quint64 address = resolvedAddress(command->reply.at(i))) {
m_symbolAddressCache.insert(symbol, address);
showMessage(QString::fromLatin1("Obtained 0x%1 for %2 (#%3)").
arg(address, 0, 16).arg(symbol).arg(i + 1), LogMisc);
}
}
} else {
showMessage(QLatin1String("Symbol resolution failed: ")
+ QString::fromLatin1(command->joinedReply()),
LogError);
}
handleResolveSymbol(m_symbolAddressCache.values(symbol), cookieList.back());
}
// Find the function address matching needle in a list of function
// addresses obtained from the 'x' command. Check for the
// mimimum POSITIVE offset (needle >= function address.)
static inline quint64 findClosestFunctionAddress(const QList<quint64> &addresses,
quint64 needle)
{
const int size = addresses.size();
if (!size)
return 0;
if (size == 1)
return addresses.front();
int closestIndex = 0;
quint64 closestOffset = 0xFFFFFFFF;
for (int i = 0; i < size; i++) {
if (addresses.at(i) <= needle) {
const quint64 offset = needle - addresses.at(i);
if (offset < offset) {
closestOffset = offset;
closestIndex = i;
}
}
}
return addresses.at(closestIndex);
}
void CdbEngine::handleResolveSymbol(const QList<quint64> &addresses, const QVariant &cookie)
{
// Disassembly mode: Determine suitable range containing the
// agent's address within the function to display.
if (qVariantCanConvert<DisassemblerAgent*>(cookie)) {
DisassemblerAgent *agent = cookie.value<DisassemblerAgent *>();
const quint64 agentAddress = agent->address();
const quint64 functionAddress
= findClosestFunctionAddress(addresses, agentAddress);
if (functionAddress > 0 && functionAddress <= agentAddress) {
quint64 endAddress = agentAddress + DisassemblerRange / 2;
if (const quint64 remainder = endAddress % 8)
endAddress += 8 - remainder;
postDisassemblerCommand(functionAddress, endAddress, cookie);
} else {
postDisassemblerCommand(agentAddress, cookie);
}
return;
}
}
// Parse: "00000000`77606060 cc int 3"
void CdbEngine::handleDisassembler(const CdbBuiltinCommandPtr &command)
{
......
......@@ -40,6 +40,7 @@
#include <QtCore/QProcess>
#include <QtCore/QVariantList>
#include <QtCore/QMap>
#include <QtCore/QMultiHash>
#include <QtCore/QTime>
#include <QtCore/QPair>
#include <QtCore/QList>
......@@ -211,8 +212,12 @@ private:
void postWidgetAtCommand();
void handleCustomSpecialStop(const QVariant &v);
void postFetchMemory(const MemoryViewCookie &c);
inline void postDisassemblerCommand(quint64 address, const QVariant &cookie = QVariant());
void postDisassemblerCommand(quint64 address, quint64 endAddress,
const QVariant &cookie = QVariant());
void postResolveSymbol(const QString &module, const QString &function,
const QVariant &cookie = QVariant());
void evaluateExpression(QByteArray exp, const QVariant &cookie = QVariant());
// Builtin commands
void dummyHandler(const CdbBuiltinCommandPtr &);
void handleStackTrace(const CdbExtensionCommandPtr &);
......@@ -220,7 +225,10 @@ private:
void handleDisassembler(const CdbBuiltinCommandPtr &);
void handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &);
void handleExpression(const CdbExtensionCommandPtr &);
void handleResolveSymbol(const CdbBuiltinCommandPtr &command);
void handleResolveSymbol(const QList<quint64> &addresses, const QVariant &cookie);
void jumpToAddress(quint64 address);
// Extension commands
void handleThreads(const CdbExtensionCommandPtr &);
void handlePid(const CdbExtensionCommandPtr &reply);
......@@ -270,6 +278,7 @@ private:
int m_watchPointY;
PendingBreakPointMap m_pendingBreakpointMap;
QHash<QString, QString> m_fileNameModuleHash;
QMultiHash<QString, quint64> m_symbolAddressCache;
bool m_ignoreCdbOutput;
QVariantList m_customSpecialStopData;
QList<SourcePathMapping> m_sourcePathMappings;
......
......@@ -97,6 +97,7 @@ Internal::Location::Location(const StackFrame &frame, bool marker)
m_functionName = frame.function;
m_hasDebugInfo = frame.isUsable();
m_address = frame.address;
m_from = frame.from;
}
QDebug operator<<(QDebug d, DebuggerState state)
......
......@@ -100,6 +100,7 @@ public:
Location(const StackFrame &frame, bool marker = true);
QString fileName() const { return m_fileName; }
QString functionName() const { return m_functionName; }
QString from() const { return m_from; }
int lineNumber() const { return m_lineNumber; }
void setNeedsRaise(bool on) { m_needsRaise = on; }
void setNeedsMarker(bool on) { m_needsMarker = on; }
......@@ -118,6 +119,7 @@ private:
int m_lineNumber;
QString m_fileName;
QString m_functionName;
QString m_from;
quint64 m_address;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment