forked from qt-creator/qt-creator
CDB: Compile, new Disassembler architecture.
This commit is contained in:
@@ -32,7 +32,6 @@
|
||||
#include "cdbdebugengine_p.h"
|
||||
#include "cdbsymbolgroupcontext.h"
|
||||
|
||||
#include "disassemblerhandler.h"
|
||||
#include "registerhandler.h"
|
||||
|
||||
#include <QtCore/QVector>
|
||||
@@ -40,8 +39,6 @@
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
typedef QList<DisassemblerLine> DisassemblerLineList;
|
||||
|
||||
bool getRegisters(CIDebugControl *ctl,
|
||||
CIDebugRegisters *ireg,
|
||||
QList<Register> *registers,
|
||||
@@ -90,35 +87,39 @@ bool getRegisters(CIDebugControl *ctl,
|
||||
// it uses that symbol.
|
||||
class DisassemblerOutputParser
|
||||
{
|
||||
Q_DISABLE_COPY(DisassemblerOutputParser)
|
||||
public:
|
||||
explicit DisassemblerOutputParser(DisassemblerLineList *list);
|
||||
explicit DisassemblerOutputParser(QTextStream &str, int addressFieldWith = 0);
|
||||
|
||||
void parse(const QStringList &l);
|
||||
|
||||
private:
|
||||
enum ParseResult { ParseOk, ParseIgnore, ParseFailed };
|
||||
ParseResult parseDisassembled(const QString &in, DisassemblerLine* l);
|
||||
ParseResult parseDisassembled(const QString &in);
|
||||
|
||||
DisassemblerLineList *m_list;
|
||||
const int m_addressFieldWith;
|
||||
QTextStream &m_str;
|
||||
QString m_sourceSymbol;
|
||||
int m_sourceSymbolOffset;
|
||||
};
|
||||
|
||||
DisassemblerOutputParser::DisassemblerOutputParser(DisassemblerLineList *list) :
|
||||
m_list(list),
|
||||
DisassemblerOutputParser::DisassemblerOutputParser(QTextStream &str, int addressFieldWith) :
|
||||
m_addressFieldWith(addressFieldWith),
|
||||
m_str(str),
|
||||
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();
|
||||
/* Parse a disassembler line:
|
||||
* \code
|
||||
module!class::foo:
|
||||
004017cf cc int 3
|
||||
77 mainwindow.cpp 004018ff 8d4da8 lea ecx,[ebp-0x58]
|
||||
\endcode */
|
||||
|
||||
DisassemblerOutputParser::ParseResult
|
||||
DisassemblerOutputParser::parseDisassembled(const QString &in)
|
||||
{
|
||||
// Check if there is a source file
|
||||
if (in.size() < 7)
|
||||
return ParseIgnore;
|
||||
@@ -129,9 +130,11 @@ DisassemblerOutputParser::ParseResult
|
||||
if (simplified.isEmpty())
|
||||
return ParseIgnore;
|
||||
|
||||
QStringList tokens = simplified.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
||||
const QStringList tokens = simplified.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
||||
const int tokenCount = tokens.size();
|
||||
// Check for symbols as 'module!class::foo:' (start of function encountered)
|
||||
if (tokens.size() == 1) {
|
||||
// and store as state.
|
||||
if (tokenCount == 1) {
|
||||
QString symbol = tokens.front();
|
||||
if (symbol.endsWith(QLatin1Char(':')) && symbol.contains(QLatin1Char('!'))) {
|
||||
symbol.truncate(symbol.size() - 1);
|
||||
@@ -140,51 +143,49 @@ DisassemblerOutputParser::ParseResult
|
||||
}
|
||||
return ParseIgnore;
|
||||
}
|
||||
if (tokens.size() < 2)
|
||||
if (tokenCount < 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('>');
|
||||
if (tokenCount < 3)
|
||||
return ParseFailed;
|
||||
// Format line. Start with address with the field width given,
|
||||
// which is important for setting the marker.
|
||||
const int addressToken = hasSourceFile ? 2 : 0;
|
||||
m_str << "0x";
|
||||
if (m_str.fieldWidth() == m_addressFieldWith) {
|
||||
m_str << tokens.at(addressToken);
|
||||
} else {
|
||||
const QChar oldPadChar = m_str.padChar();
|
||||
const int oldFieldWidth = m_str.fieldWidth();
|
||||
m_str.setFieldWidth(m_addressFieldWith);
|
||||
m_str.setPadChar(QLatin1Char('0'));
|
||||
m_str << tokens.at(addressToken);
|
||||
m_str.setFieldWidth(oldFieldWidth);
|
||||
m_str.setPadChar(oldPadChar);
|
||||
}
|
||||
m_str << ' ';
|
||||
// Symbol display: Do we know a symbol? -> Display with offset.
|
||||
// Else default to source file information.
|
||||
if (m_sourceSymbol.isEmpty()) {
|
||||
if (hasSourceFile)
|
||||
m_str << tokens.at(1) << '+' << tokens.front();
|
||||
} else {
|
||||
m_str << '<' << m_sourceSymbol;
|
||||
if (m_sourceSymbolOffset)
|
||||
m_str << '+' << m_sourceSymbolOffset;
|
||||
m_str << '>';
|
||||
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(' ')));
|
||||
for (int i = addressToken + 1; i < tokenCount; i++)
|
||||
m_str << ' ' << tokens.at(i);
|
||||
m_str << '\n';
|
||||
return ParseOk;
|
||||
}
|
||||
|
||||
void DisassemblerOutputParser::parse(const QStringList &l)
|
||||
{
|
||||
DisassemblerLine dLine;
|
||||
foreach(const QString &line, l) {
|
||||
switch (parseDisassembled(line, &dLine)) {
|
||||
switch (parseDisassembled(line)) {
|
||||
case ParseOk:
|
||||
m_list->push_back(dLine);
|
||||
break;
|
||||
case ParseIgnore:
|
||||
break;
|
||||
case ParseFailed:
|
||||
@@ -199,12 +200,13 @@ bool dissassemble(CIDebugClient *client,
|
||||
ULONG64 offset,
|
||||
unsigned long beforeLines,
|
||||
unsigned long afterLines,
|
||||
QList<DisassemblerLine> *lines,
|
||||
int addressFieldWith,
|
||||
QTextStream &str,
|
||||
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
|
||||
@@ -219,10 +221,10 @@ bool dissassemble(CIDebugClient *client,
|
||||
offset, flags, 0, 0, 0, 0);
|
||||
if (FAILED(hr)) {
|
||||
*errorMessage= QString::fromLatin1("Unable to dissamble at 0x%1: %2").
|
||||
arg(QString::number(offset, 16), msgComFailed("OutputDisassemblyLines", hr));
|
||||
arg(offset, 0, 16).arg(msgComFailed("OutputDisassemblyLines", hr));
|
||||
return false;
|
||||
}
|
||||
DisassemblerOutputParser parser(lines);
|
||||
DisassemblerOutputParser parser(str, addressFieldWith);
|
||||
parser.parse(stringHandler.result().split(QLatin1Char('\n')));
|
||||
return true;
|
||||
}
|
||||
|
@@ -35,11 +35,13 @@
|
||||
|
||||
#include "cdbcom.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTextStream;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class DisassemblerLine;
|
||||
|
||||
// Utilities related to assembler code.
|
||||
class Register;
|
||||
|
||||
@@ -54,7 +56,8 @@ bool dissassemble(CIDebugClient *client,
|
||||
ULONG64 offset,
|
||||
unsigned long beforeLines,
|
||||
unsigned long afterLines,
|
||||
QList<DisassemblerLine> *lines,
|
||||
int addressFieldWith /* = 0*/,
|
||||
QTextStream &str,
|
||||
QString *errorMessage);
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "cdbassembler.h"
|
||||
#include "cdboptionspage.h"
|
||||
#include "cdboptions.h"
|
||||
#include "debuggeragents.h"
|
||||
|
||||
#include "debuggeractions.h"
|
||||
#include "debuggermanager.h"
|
||||
@@ -45,7 +46,6 @@
|
||||
#include "watchhandler.h"
|
||||
#include "registerhandler.h"
|
||||
#include "moduleshandler.h"
|
||||
#include "disassemblerhandler.h"
|
||||
#include "watchutils.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
@@ -1258,37 +1258,50 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
|
||||
}
|
||||
|
||||
void CdbDebugEngine::fetchDisassembler(DisassemblerViewAgent *agent,
|
||||
const StackFrame &frame)
|
||||
const StackFrame & frame)
|
||||
{
|
||||
// was: void CdbDebugEngine::reloadDisassembler()
|
||||
// use agent->address() to create a listing
|
||||
|
||||
/*
|
||||
enum { ContextLines = 40 };
|
||||
// Do we have a top stack frame?
|
||||
const ULONG64 offset = m_d->m_currentStackTrace ? m_d->m_currentStackTrace->instructionOffset() : ULONG64(0);
|
||||
if (debugCDB)
|
||||
qDebug() << Q_FUNC_INFO << offset;
|
||||
|
||||
DisassemblerHandler *dh = m_d->m_debuggerManagerAccess->disassemblerHandler();
|
||||
if (offset) {
|
||||
QList<DisassemblerLine> lines;
|
||||
QString errorMessage;
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
const bool drc = dissassemble(m_d->m_cif.debugClient, m_d->m_cif.debugControl, offset,
|
||||
ContextLines, ContextLines, &lines, &errorMessage);
|
||||
QApplication::restoreOverrideCursor();
|
||||
if (drc) {
|
||||
dh->setLines(lines);
|
||||
if (lines.size() > ContextLines)
|
||||
dh->setCurrentLine(ContextLines);
|
||||
} else {
|
||||
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
||||
bool ok = false;
|
||||
QString errorMessage;
|
||||
do {
|
||||
// get address
|
||||
QString address;
|
||||
if (!frame.file.isEmpty())
|
||||
address = frame.address;
|
||||
if (address.isEmpty())
|
||||
address = agent->address();
|
||||
if (debugCDB)
|
||||
qDebug() << "fetchDisassembler" << address << " Agent: " << agent->address()
|
||||
<< " Frame" << frame.file << frame.line << frame.address;
|
||||
if (address.isEmpty()) { // Clear window
|
||||
agent->setContents(QString());
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
dh->setLines(QList<DisassemblerLine>());
|
||||
if (address.startsWith(QLatin1String("0x")))
|
||||
address.remove(0, 2);
|
||||
const int addressFieldWith = address.size(); // For the Marker
|
||||
|
||||
const ULONG64 offset = address.toULongLong(&ok, 16);
|
||||
if (!ok) {
|
||||
errorMessage = QString::fromLatin1("Internal error: Invalid address for disassembly: '%1'.").arg(agent->address());
|
||||
break;
|
||||
}
|
||||
QString disassembly;
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
ok = dissassemble(m_d->m_cif.debugClient, m_d->m_cif.debugControl, offset, addressFieldWith,
|
||||
ContextLines, ContextLines, QTextStream(&disassembly), &errorMessage);
|
||||
QApplication::restoreOverrideCursor();
|
||||
if (!ok)
|
||||
break;
|
||||
agent->setContents(disassembly);
|
||||
|
||||
} while (false);
|
||||
|
||||
if (!ok) {
|
||||
agent->setContents(QString());
|
||||
warning(errorMessage);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void CdbDebugEngine::reloadModules()
|
||||
|
@@ -81,7 +81,7 @@ STDMETHODIMP CdbDebugOutputBase::Output(
|
||||
)
|
||||
{
|
||||
const QString msg = QString::fromUtf16(reinterpret_cast<const ushort *>(text));
|
||||
output(mask, msg.trimmed());
|
||||
output(mask, msg);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -124,10 +124,8 @@ CdbDebugOutput::CdbDebugOutput()
|
||||
{
|
||||
}
|
||||
|
||||
void CdbDebugOutput::output(ULONG mask, const QString &_msg)
|
||||
void CdbDebugOutput::output(ULONG mask, const QString &msg)
|
||||
{
|
||||
QString msg = _msg + '\n';
|
||||
|
||||
if (debugCDB > 1)
|
||||
qDebug() << Q_FUNC_INFO << "\n " << msg;
|
||||
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include "moduleshandler.h"
|
||||
#include "registerhandler.h"
|
||||
#include "stackhandler.h"
|
||||
#include "stackframe.h"
|
||||
#include "watchhandler.h"
|
||||
|
||||
#include "debuggerdialogs.h"
|
||||
|
@@ -76,7 +76,7 @@ class BreakpointData;
|
||||
class ModulesHandler;
|
||||
class RegisterHandler;
|
||||
class SourceFilesWindow;
|
||||
class StackFrame;
|
||||
struct StackFrame;
|
||||
class StackHandler;
|
||||
class Symbol;
|
||||
class ThreadsHandler;
|
||||
|
@@ -62,7 +62,7 @@ class DebuggerManager;
|
||||
class DebuggerRunner;
|
||||
class DebugMode;
|
||||
class DisassemblerViewAgent;
|
||||
class StackFrame;
|
||||
struct StackFrame;
|
||||
|
||||
class DebuggerPlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
|
@@ -49,7 +49,7 @@ namespace Internal {
|
||||
class DebuggerStartParameters;
|
||||
class DisassemblerViewAgent;
|
||||
class MemoryViewAgent;
|
||||
class StackFrame;
|
||||
struct StackFrame;
|
||||
class Symbol;
|
||||
class WatchData;
|
||||
|
||||
@@ -98,8 +98,8 @@ public:
|
||||
virtual void watchPoint(const QPoint &) {}
|
||||
virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length)
|
||||
{ Q_UNUSED(addr); Q_UNUSED(length); }
|
||||
virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame &frame)
|
||||
{ Q_UNUSED(frame); }
|
||||
virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame & /* frame */)
|
||||
{ }
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#define DEBUGGER_STACKFRAME_H
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QMetaType>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
Reference in New Issue
Block a user