forked from qt-creator/qt-creator
Implement disassembler for cdb.
Filter debugging output correctly, some glitches. Extract base class for debugging output to be able to intercept debugging output for other purposes (such as disassembling).
This commit is contained in:
@@ -28,15 +28,20 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "cdbassembler.h"
|
||||
#include "registerhandler.h"
|
||||
#include "cdbdebugoutput.h"
|
||||
#include "cdbdebugengine_p.h"
|
||||
#include "cdbsymbolgroupcontext.h"
|
||||
|
||||
#include "disassemblerhandler.h"
|
||||
#include "registerhandler.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
typedef QList<DisassemblerLine> DisassemblerLineList;
|
||||
|
||||
bool getRegisters(IDebugControl4 *ctl,
|
||||
IDebugRegisters2 *ireg,
|
||||
QList<Register> *registers,
|
||||
@@ -79,5 +84,151 @@ bool getRegisters(IDebugControl4 *ctl,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Output parser for disassembler lines.
|
||||
// It uses the source file lines as symbol until it encounters
|
||||
// a C++ symbol (function entered), from which then on
|
||||
// it uses that symbol.
|
||||
class DisassemblerOutputParser
|
||||
{
|
||||
public:
|
||||
explicit DisassemblerOutputParser(DisassemblerLineList *list);
|
||||
|
||||
void parse(const QStringList &l);
|
||||
|
||||
private:
|
||||
enum ParseResult { ParseOk, ParseIgnore, ParseFailed };
|
||||
ParseResult parseDisassembled(const QString &in, DisassemblerLine* l);
|
||||
|
||||
DisassemblerLineList *m_list;
|
||||
QString m_sourceSymbol;
|
||||
int m_sourceSymbolOffset;
|
||||
};
|
||||
|
||||
DisassemblerOutputParser::DisassemblerOutputParser(DisassemblerLineList *list) :
|
||||
m_list(list),
|
||||
m_sourceSymbolOffset(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Parse a disassembler line:
|
||||
// module!class::foo:
|
||||
// 004017cf cc int 3
|
||||
// 77 mainwindow.cpp 004018ff 8d4da8 lea ecx,[ebp-0x58]
|
||||
DisassemblerOutputParser::ParseResult
|
||||
DisassemblerOutputParser::parseDisassembled(const QString &in, DisassemblerLine* l)
|
||||
{
|
||||
l->clear();
|
||||
|
||||
// Check if there is a source file
|
||||
if (in.size() < 7)
|
||||
return ParseIgnore;
|
||||
const bool hasSourceFile = !in.at(6).isSpace();
|
||||
|
||||
// Sometimes, empty lines occur
|
||||
const QString simplified = in.simplified();
|
||||
if (simplified.isEmpty())
|
||||
return ParseIgnore;
|
||||
|
||||
QStringList tokens = simplified.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
||||
// Check for symbols as 'module!class::foo:' (start of function encountered)
|
||||
if (tokens.size() == 1) {
|
||||
QString symbol = tokens.front();
|
||||
if (symbol.endsWith(QLatin1Char(':')) && symbol.contains(QLatin1Char('!'))) {
|
||||
symbol.truncate(symbol.size() - 1);
|
||||
m_sourceSymbol = symbol;
|
||||
m_sourceSymbolOffset = 0;
|
||||
}
|
||||
return ParseIgnore;
|
||||
}
|
||||
if (tokens.size() < 2)
|
||||
return ParseIgnore;
|
||||
// Symbol display: Do we know a symbol?
|
||||
if (!m_sourceSymbol.isEmpty()) {
|
||||
l->symbol = QString(QLatin1Char('<'));
|
||||
l->symbol += m_sourceSymbol;
|
||||
if (m_sourceSymbolOffset) {
|
||||
l->symbol += QLatin1Char('+');
|
||||
l->symbol += QString::number(m_sourceSymbolOffset);
|
||||
}
|
||||
l->symbol += QLatin1Char('>');
|
||||
m_sourceSymbolOffset++;
|
||||
}
|
||||
// Read source file information: If we don't know a symbol yet,
|
||||
// use the source file.
|
||||
if (hasSourceFile) {
|
||||
if (l->symbol.isEmpty()) {
|
||||
l->symbol = tokens.at(1);
|
||||
l->symbol += QLatin1Char('+');
|
||||
l->symbol += tokens.front();
|
||||
}
|
||||
tokens.pop_front();
|
||||
tokens.pop_front();
|
||||
}
|
||||
l->symbolDisplay = l->symbol;
|
||||
// Get offset address and instruction
|
||||
if (tokens.size() < 3)
|
||||
return ParseFailed;
|
||||
l->addressDisplay = l->address = tokens.front();
|
||||
tokens.pop_front();
|
||||
// The rest is effective address & instructions
|
||||
if (tokens.size() > 1)
|
||||
tokens.pop_front();
|
||||
l->mnemonic = tokens.join(QString(QLatin1Char(' ')));
|
||||
return ParseOk;
|
||||
}
|
||||
|
||||
void DisassemblerOutputParser::parse(const QStringList &l)
|
||||
{
|
||||
DisassemblerLine dLine;
|
||||
foreach(const QString &line, l) {
|
||||
switch (parseDisassembled(line, &dLine)) {
|
||||
case ParseOk:
|
||||
m_list->push_back(dLine);
|
||||
break;
|
||||
case ParseIgnore:
|
||||
break;
|
||||
case ParseFailed:
|
||||
qWarning("Failed to parse '%s'\n", qPrintable(line));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool dissassemble(IDebugClient5 *client,
|
||||
IDebugControl4 *ctl,
|
||||
ULONG64 offset,
|
||||
unsigned long beforeLines,
|
||||
unsigned long afterLines,
|
||||
QList<DisassemblerLine> *lines,
|
||||
QString *errorMessage)
|
||||
{
|
||||
if (debugCDB)
|
||||
qDebug() << Q_FUNC_INFO << offset;
|
||||
lines->clear();
|
||||
const ULONG flags = DEBUG_DISASM_MATCHING_SYMBOLS|DEBUG_DISASM_SOURCE_LINE_NUMBER|DEBUG_DISASM_SOURCE_FILE_NAME;
|
||||
// Catch the output by temporarily setting another handler.
|
||||
// We use the method that outputs to the output handler as it
|
||||
// conveniently provides the 'beforeLines' context (stepping back
|
||||
// in assembler code). We build a complete string first as line breaks
|
||||
// may occur in-between messages.
|
||||
StringOutputHandler stringHandler;
|
||||
IDebugOutputCallbacksWide *oldHandler = CdbDebugOutputBase::getOutputCallback(client);
|
||||
client->SetOutputCallbacksWide(&stringHandler);
|
||||
// For some reason, we need to output to "all clients"
|
||||
const HRESULT hr = ctl->OutputDisassemblyLines(DEBUG_OUTCTL_ALL_CLIENTS,
|
||||
beforeLines, beforeLines + afterLines,
|
||||
offset, flags, 0, 0, 0, 0);
|
||||
client->SetOutputCallbacksWide(oldHandler);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
*errorMessage= QString::fromLatin1("Unable to dissamble at 0x%1: %2").
|
||||
arg(QString::number(offset, 16), msgComFailed("OutputDisassemblyLines", hr));
|
||||
return false;
|
||||
}
|
||||
DisassemblerOutputParser parser(lines);
|
||||
parser.parse(stringHandler.result().split(QLatin1Char('\n')));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user