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 "cdbdebugengine_p.h"
|
||||||
#include "cdbsymbolgroupcontext.h"
|
#include "cdbsymbolgroupcontext.h"
|
||||||
|
|
||||||
#include "disassemblerhandler.h"
|
|
||||||
#include "registerhandler.h"
|
#include "registerhandler.h"
|
||||||
|
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
@@ -40,8 +39,6 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
typedef QList<DisassemblerLine> DisassemblerLineList;
|
|
||||||
|
|
||||||
bool getRegisters(CIDebugControl *ctl,
|
bool getRegisters(CIDebugControl *ctl,
|
||||||
CIDebugRegisters *ireg,
|
CIDebugRegisters *ireg,
|
||||||
QList<Register> *registers,
|
QList<Register> *registers,
|
||||||
@@ -90,35 +87,39 @@ bool getRegisters(CIDebugControl *ctl,
|
|||||||
// it uses that symbol.
|
// it uses that symbol.
|
||||||
class DisassemblerOutputParser
|
class DisassemblerOutputParser
|
||||||
{
|
{
|
||||||
|
Q_DISABLE_COPY(DisassemblerOutputParser)
|
||||||
public:
|
public:
|
||||||
explicit DisassemblerOutputParser(DisassemblerLineList *list);
|
explicit DisassemblerOutputParser(QTextStream &str, int addressFieldWith = 0);
|
||||||
|
|
||||||
void parse(const QStringList &l);
|
void parse(const QStringList &l);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum ParseResult { ParseOk, ParseIgnore, ParseFailed };
|
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;
|
QString m_sourceSymbol;
|
||||||
int m_sourceSymbolOffset;
|
int m_sourceSymbolOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
DisassemblerOutputParser::DisassemblerOutputParser(DisassemblerLineList *list) :
|
DisassemblerOutputParser::DisassemblerOutputParser(QTextStream &str, int addressFieldWith) :
|
||||||
m_list(list),
|
m_addressFieldWith(addressFieldWith),
|
||||||
|
m_str(str),
|
||||||
m_sourceSymbolOffset(0)
|
m_sourceSymbolOffset(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a disassembler line:
|
/* Parse a disassembler line:
|
||||||
// module!class::foo:
|
* \code
|
||||||
// 004017cf cc int 3
|
module!class::foo:
|
||||||
// 77 mainwindow.cpp 004018ff 8d4da8 lea ecx,[ebp-0x58]
|
004017cf cc int 3
|
||||||
DisassemblerOutputParser::ParseResult
|
77 mainwindow.cpp 004018ff 8d4da8 lea ecx,[ebp-0x58]
|
||||||
DisassemblerOutputParser::parseDisassembled(const QString &in, DisassemblerLine* l)
|
\endcode */
|
||||||
{
|
|
||||||
l->clear();
|
|
||||||
|
|
||||||
|
DisassemblerOutputParser::ParseResult
|
||||||
|
DisassemblerOutputParser::parseDisassembled(const QString &in)
|
||||||
|
{
|
||||||
// Check if there is a source file
|
// Check if there is a source file
|
||||||
if (in.size() < 7)
|
if (in.size() < 7)
|
||||||
return ParseIgnore;
|
return ParseIgnore;
|
||||||
@@ -129,9 +130,11 @@ DisassemblerOutputParser::ParseResult
|
|||||||
if (simplified.isEmpty())
|
if (simplified.isEmpty())
|
||||||
return ParseIgnore;
|
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)
|
// 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();
|
QString symbol = tokens.front();
|
||||||
if (symbol.endsWith(QLatin1Char(':')) && symbol.contains(QLatin1Char('!'))) {
|
if (symbol.endsWith(QLatin1Char(':')) && symbol.contains(QLatin1Char('!'))) {
|
||||||
symbol.truncate(symbol.size() - 1);
|
symbol.truncate(symbol.size() - 1);
|
||||||
@@ -140,51 +143,49 @@ DisassemblerOutputParser::ParseResult
|
|||||||
}
|
}
|
||||||
return ParseIgnore;
|
return ParseIgnore;
|
||||||
}
|
}
|
||||||
if (tokens.size() < 2)
|
if (tokenCount < 2)
|
||||||
return ParseIgnore;
|
return ParseIgnore;
|
||||||
// Symbol display: Do we know a symbol?
|
if (tokenCount < 3)
|
||||||
if (!m_sourceSymbol.isEmpty()) {
|
return ParseFailed;
|
||||||
l->symbol = QString(QLatin1Char('<'));
|
// Format line. Start with address with the field width given,
|
||||||
l->symbol += m_sourceSymbol;
|
// which is important for setting the marker.
|
||||||
if (m_sourceSymbolOffset) {
|
const int addressToken = hasSourceFile ? 2 : 0;
|
||||||
l->symbol += QLatin1Char('+');
|
m_str << "0x";
|
||||||
l->symbol += QString::number(m_sourceSymbolOffset);
|
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);
|
||||||
}
|
}
|
||||||
l->symbol += QLatin1Char('>');
|
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++;
|
m_sourceSymbolOffset++;
|
||||||
}
|
}
|
||||||
// Read source file information: If we don't know a symbol yet,
|
for (int i = addressToken + 1; i < tokenCount; i++)
|
||||||
// use the source file.
|
m_str << ' ' << tokens.at(i);
|
||||||
if (hasSourceFile) {
|
m_str << '\n';
|
||||||
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;
|
return ParseOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblerOutputParser::parse(const QStringList &l)
|
void DisassemblerOutputParser::parse(const QStringList &l)
|
||||||
{
|
{
|
||||||
DisassemblerLine dLine;
|
|
||||||
foreach(const QString &line, l) {
|
foreach(const QString &line, l) {
|
||||||
switch (parseDisassembled(line, &dLine)) {
|
switch (parseDisassembled(line)) {
|
||||||
case ParseOk:
|
case ParseOk:
|
||||||
m_list->push_back(dLine);
|
|
||||||
break;
|
|
||||||
case ParseIgnore:
|
case ParseIgnore:
|
||||||
break;
|
break;
|
||||||
case ParseFailed:
|
case ParseFailed:
|
||||||
@@ -199,12 +200,13 @@ bool dissassemble(CIDebugClient *client,
|
|||||||
ULONG64 offset,
|
ULONG64 offset,
|
||||||
unsigned long beforeLines,
|
unsigned long beforeLines,
|
||||||
unsigned long afterLines,
|
unsigned long afterLines,
|
||||||
QList<DisassemblerLine> *lines,
|
int addressFieldWith,
|
||||||
|
QTextStream &str,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << offset;
|
qDebug() << Q_FUNC_INFO << offset;
|
||||||
lines->clear();
|
|
||||||
const ULONG flags = DEBUG_DISASM_MATCHING_SYMBOLS|DEBUG_DISASM_SOURCE_LINE_NUMBER|DEBUG_DISASM_SOURCE_FILE_NAME;
|
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.
|
// Catch the output by temporarily setting another handler.
|
||||||
// We use the method that outputs to the output handler as it
|
// 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);
|
offset, flags, 0, 0, 0, 0);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage= QString::fromLatin1("Unable to dissamble at 0x%1: %2").
|
*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;
|
return false;
|
||||||
}
|
}
|
||||||
DisassemblerOutputParser parser(lines);
|
DisassemblerOutputParser parser(str, addressFieldWith);
|
||||||
parser.parse(stringHandler.result().split(QLatin1Char('\n')));
|
parser.parse(stringHandler.result().split(QLatin1Char('\n')));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -35,11 +35,13 @@
|
|||||||
|
|
||||||
#include "cdbcom.h"
|
#include "cdbcom.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QTextStream;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class DisassemblerLine;
|
|
||||||
|
|
||||||
// Utilities related to assembler code.
|
// Utilities related to assembler code.
|
||||||
class Register;
|
class Register;
|
||||||
|
|
||||||
@@ -54,7 +56,8 @@ bool dissassemble(CIDebugClient *client,
|
|||||||
ULONG64 offset,
|
ULONG64 offset,
|
||||||
unsigned long beforeLines,
|
unsigned long beforeLines,
|
||||||
unsigned long afterLines,
|
unsigned long afterLines,
|
||||||
QList<DisassemblerLine> *lines,
|
int addressFieldWith /* = 0*/,
|
||||||
|
QTextStream &str,
|
||||||
QString *errorMessage);
|
QString *errorMessage);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#include "cdbassembler.h"
|
#include "cdbassembler.h"
|
||||||
#include "cdboptionspage.h"
|
#include "cdboptionspage.h"
|
||||||
#include "cdboptions.h"
|
#include "cdboptions.h"
|
||||||
|
#include "debuggeragents.h"
|
||||||
|
|
||||||
#include "debuggeractions.h"
|
#include "debuggeractions.h"
|
||||||
#include "debuggermanager.h"
|
#include "debuggermanager.h"
|
||||||
@@ -45,7 +46,6 @@
|
|||||||
#include "watchhandler.h"
|
#include "watchhandler.h"
|
||||||
#include "registerhandler.h"
|
#include "registerhandler.h"
|
||||||
#include "moduleshandler.h"
|
#include "moduleshandler.h"
|
||||||
#include "disassemblerhandler.h"
|
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -1260,35 +1260,48 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
|
|||||||
void CdbDebugEngine::fetchDisassembler(DisassemblerViewAgent *agent,
|
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 };
|
enum { ContextLines = 40 };
|
||||||
// Do we have a top stack frame?
|
bool ok = false;
|
||||||
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;
|
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;
|
||||||
|
}
|
||||||
|
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);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
const bool drc = dissassemble(m_d->m_cif.debugClient, m_d->m_cif.debugControl, offset,
|
ok = dissassemble(m_d->m_cif.debugClient, m_d->m_cif.debugControl, offset, addressFieldWith,
|
||||||
ContextLines, ContextLines, &lines, &errorMessage);
|
ContextLines, ContextLines, QTextStream(&disassembly), &errorMessage);
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
if (drc) {
|
if (!ok)
|
||||||
dh->setLines(lines);
|
break;
|
||||||
if (lines.size() > ContextLines)
|
agent->setContents(disassembly);
|
||||||
dh->setCurrentLine(ContextLines);
|
|
||||||
} else {
|
} while (false);
|
||||||
warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
|
|
||||||
|
if (!ok) {
|
||||||
|
agent->setContents(QString());
|
||||||
|
warning(errorMessage);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
dh->setLines(QList<DisassemblerLine>());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEngine::reloadModules()
|
void CdbDebugEngine::reloadModules()
|
||||||
|
@@ -81,7 +81,7 @@ STDMETHODIMP CdbDebugOutputBase::Output(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
const QString msg = QString::fromUtf16(reinterpret_cast<const ushort *>(text));
|
const QString msg = QString::fromUtf16(reinterpret_cast<const ushort *>(text));
|
||||||
output(mask, msg.trimmed());
|
output(mask, msg);
|
||||||
return S_OK;
|
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)
|
if (debugCDB > 1)
|
||||||
qDebug() << Q_FUNC_INFO << "\n " << msg;
|
qDebug() << Q_FUNC_INFO << "\n " << msg;
|
||||||
|
|
||||||
|
@@ -47,6 +47,7 @@
|
|||||||
#include "moduleshandler.h"
|
#include "moduleshandler.h"
|
||||||
#include "registerhandler.h"
|
#include "registerhandler.h"
|
||||||
#include "stackhandler.h"
|
#include "stackhandler.h"
|
||||||
|
#include "stackframe.h"
|
||||||
#include "watchhandler.h"
|
#include "watchhandler.h"
|
||||||
|
|
||||||
#include "debuggerdialogs.h"
|
#include "debuggerdialogs.h"
|
||||||
|
@@ -76,7 +76,7 @@ class BreakpointData;
|
|||||||
class ModulesHandler;
|
class ModulesHandler;
|
||||||
class RegisterHandler;
|
class RegisterHandler;
|
||||||
class SourceFilesWindow;
|
class SourceFilesWindow;
|
||||||
class StackFrame;
|
struct StackFrame;
|
||||||
class StackHandler;
|
class StackHandler;
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class ThreadsHandler;
|
class ThreadsHandler;
|
||||||
|
@@ -62,7 +62,7 @@ class DebuggerManager;
|
|||||||
class DebuggerRunner;
|
class DebuggerRunner;
|
||||||
class DebugMode;
|
class DebugMode;
|
||||||
class DisassemblerViewAgent;
|
class DisassemblerViewAgent;
|
||||||
class StackFrame;
|
struct StackFrame;
|
||||||
|
|
||||||
class DebuggerPlugin : public ExtensionSystem::IPlugin
|
class DebuggerPlugin : public ExtensionSystem::IPlugin
|
||||||
{
|
{
|
||||||
|
@@ -49,7 +49,7 @@ namespace Internal {
|
|||||||
class DebuggerStartParameters;
|
class DebuggerStartParameters;
|
||||||
class DisassemblerViewAgent;
|
class DisassemblerViewAgent;
|
||||||
class MemoryViewAgent;
|
class MemoryViewAgent;
|
||||||
class StackFrame;
|
struct StackFrame;
|
||||||
class Symbol;
|
class Symbol;
|
||||||
class WatchData;
|
class WatchData;
|
||||||
|
|
||||||
@@ -98,8 +98,8 @@ public:
|
|||||||
virtual void watchPoint(const QPoint &) {}
|
virtual void watchPoint(const QPoint &) {}
|
||||||
virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length)
|
virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length)
|
||||||
{ Q_UNUSED(addr); Q_UNUSED(length); }
|
{ Q_UNUSED(addr); Q_UNUSED(length); }
|
||||||
virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame &frame)
|
virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame & /* frame */)
|
||||||
{ Q_UNUSED(frame); }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -31,7 +31,7 @@
|
|||||||
#define DEBUGGER_STACKFRAME_H
|
#define DEBUGGER_STACKFRAME_H
|
||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QVariant>
|
#include <QtCore/QMetaType>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
Reference in New Issue
Block a user