forked from qt-creator/qt-creator
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: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
This commit is contained in:
@@ -478,6 +478,7 @@ void CdbEngine::init()
|
|||||||
m_extensionMessageBuffer.clear();
|
m_extensionMessageBuffer.clear();
|
||||||
m_pendingBreakpointMap.clear();
|
m_pendingBreakpointMap.clear();
|
||||||
m_customSpecialStopData.clear();
|
m_customSpecialStopData.clear();
|
||||||
|
m_symbolAddressCache.clear();
|
||||||
|
|
||||||
// Create local list of mappings in native separators
|
// Create local list of mappings in native separators
|
||||||
m_sourcePathMappings.clear();
|
m_sourcePathMappings.clear();
|
||||||
@@ -1532,16 +1533,149 @@ void CdbEngine::selectThread(int index)
|
|||||||
postBuiltinCommand(cmd, 0, &CdbEngine::dummyHandler, CommandListStack);
|
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)
|
void CdbEngine::fetchDisassembler(DisassemblerAgent *agent)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_accessible, return;)
|
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;
|
QByteArray cmd;
|
||||||
ByteArrayInputStream str(cmd);
|
ByteArrayInputStream str(cmd);
|
||||||
str << "u " << hex << hexPrefixOn << agent->address() << " L40";
|
str << "u " << hex <<hexPrefixOn << address << ' ' << endAddress;
|
||||||
const QVariant cookie = qVariantFromValue<DisassemblerAgent*>(agent);
|
|
||||||
postBuiltinCommand(cmd, 0, &CdbEngine::handleDisassembler, 0, cookie);
|
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"
|
// Parse: "00000000`77606060 cc int 3"
|
||||||
void CdbEngine::handleDisassembler(const CdbBuiltinCommandPtr &command)
|
void CdbEngine::handleDisassembler(const CdbBuiltinCommandPtr &command)
|
||||||
{
|
{
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
#include <QtCore/QProcess>
|
#include <QtCore/QProcess>
|
||||||
#include <QtCore/QVariantList>
|
#include <QtCore/QVariantList>
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
|
#include <QtCore/QMultiHash>
|
||||||
#include <QtCore/QTime>
|
#include <QtCore/QTime>
|
||||||
#include <QtCore/QPair>
|
#include <QtCore/QPair>
|
||||||
#include <QtCore/QList>
|
#include <QtCore/QList>
|
||||||
@@ -211,8 +212,12 @@ private:
|
|||||||
void postWidgetAtCommand();
|
void postWidgetAtCommand();
|
||||||
void handleCustomSpecialStop(const QVariant &v);
|
void handleCustomSpecialStop(const QVariant &v);
|
||||||
void postFetchMemory(const MemoryViewCookie &c);
|
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());
|
void evaluateExpression(QByteArray exp, const QVariant &cookie = QVariant());
|
||||||
|
|
||||||
// Builtin commands
|
// Builtin commands
|
||||||
void dummyHandler(const CdbBuiltinCommandPtr &);
|
void dummyHandler(const CdbBuiltinCommandPtr &);
|
||||||
void handleStackTrace(const CdbExtensionCommandPtr &);
|
void handleStackTrace(const CdbExtensionCommandPtr &);
|
||||||
@@ -220,7 +225,10 @@ private:
|
|||||||
void handleDisassembler(const CdbBuiltinCommandPtr &);
|
void handleDisassembler(const CdbBuiltinCommandPtr &);
|
||||||
void handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &);
|
void handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &);
|
||||||
void handleExpression(const CdbExtensionCommandPtr &);
|
void handleExpression(const CdbExtensionCommandPtr &);
|
||||||
|
void handleResolveSymbol(const CdbBuiltinCommandPtr &command);
|
||||||
|
void handleResolveSymbol(const QList<quint64> &addresses, const QVariant &cookie);
|
||||||
void jumpToAddress(quint64 address);
|
void jumpToAddress(quint64 address);
|
||||||
|
|
||||||
// Extension commands
|
// Extension commands
|
||||||
void handleThreads(const CdbExtensionCommandPtr &);
|
void handleThreads(const CdbExtensionCommandPtr &);
|
||||||
void handlePid(const CdbExtensionCommandPtr &reply);
|
void handlePid(const CdbExtensionCommandPtr &reply);
|
||||||
@@ -270,6 +278,7 @@ private:
|
|||||||
int m_watchPointY;
|
int m_watchPointY;
|
||||||
PendingBreakPointMap m_pendingBreakpointMap;
|
PendingBreakPointMap m_pendingBreakpointMap;
|
||||||
QHash<QString, QString> m_fileNameModuleHash;
|
QHash<QString, QString> m_fileNameModuleHash;
|
||||||
|
QMultiHash<QString, quint64> m_symbolAddressCache;
|
||||||
bool m_ignoreCdbOutput;
|
bool m_ignoreCdbOutput;
|
||||||
QVariantList m_customSpecialStopData;
|
QVariantList m_customSpecialStopData;
|
||||||
QList<SourcePathMapping> m_sourcePathMappings;
|
QList<SourcePathMapping> m_sourcePathMappings;
|
||||||
|
@@ -97,6 +97,7 @@ Internal::Location::Location(const StackFrame &frame, bool marker)
|
|||||||
m_functionName = frame.function;
|
m_functionName = frame.function;
|
||||||
m_hasDebugInfo = frame.isUsable();
|
m_hasDebugInfo = frame.isUsable();
|
||||||
m_address = frame.address;
|
m_address = frame.address;
|
||||||
|
m_from = frame.from;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug d, DebuggerState state)
|
QDebug operator<<(QDebug d, DebuggerState state)
|
||||||
|
@@ -100,6 +100,7 @@ public:
|
|||||||
Location(const StackFrame &frame, bool marker = true);
|
Location(const StackFrame &frame, bool marker = true);
|
||||||
QString fileName() const { return m_fileName; }
|
QString fileName() const { return m_fileName; }
|
||||||
QString functionName() const { return m_functionName; }
|
QString functionName() const { return m_functionName; }
|
||||||
|
QString from() const { return m_from; }
|
||||||
int lineNumber() const { return m_lineNumber; }
|
int lineNumber() const { return m_lineNumber; }
|
||||||
void setNeedsRaise(bool on) { m_needsRaise = on; }
|
void setNeedsRaise(bool on) { m_needsRaise = on; }
|
||||||
void setNeedsMarker(bool on) { m_needsMarker = on; }
|
void setNeedsMarker(bool on) { m_needsMarker = on; }
|
||||||
@@ -118,6 +119,7 @@ private:
|
|||||||
int m_lineNumber;
|
int m_lineNumber;
|
||||||
QString m_fileName;
|
QString m_fileName;
|
||||||
QString m_functionName;
|
QString m_functionName;
|
||||||
|
QString m_from;
|
||||||
quint64 m_address;
|
quint64 m_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user