Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline

This commit is contained in:
Alessandro Portale
2009-04-15 16:35:22 +02:00
35 changed files with 1224 additions and 244 deletions

View File

@@ -1,9 +1,9 @@
#!/bin/sh #!/bin/sh
bindir=$(dirname $(readlink -nf $0)) bindir=$(dirname "$(readlink -nf $0)")
if test "$(uname -m)" = "x86_64" ; then if test "$(uname -m)" = "x86_64" ; then
libdir=$(cd ${bindir}/../lib64 ; pwd) libdir=$(cd "${bindir}/../lib64" ; pwd)
else else
libdir=$(cd ${bindir}/../lib ; pwd) libdir=$(cd "${bindir}/../lib" ; pwd)
fi fi
LD_LIBRARY_PATH="${libdir}/qtcreator:${LD_LIBRARY_PATH}" exec "${bindir}/qtcreator.bin" ${1+"$@"} LD_LIBRARY_PATH="${libdir}/qtcreator:${LD_LIBRARY_PATH}" exec "${bindir}/qtcreator.bin" ${1+"$@"}

View File

@@ -84,16 +84,17 @@ void BreakWindow::resizeEvent(QResizeEvent *ev)
void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
{ {
QMenu menu; QMenu menu;
QModelIndex index = indexAt(ev->pos()); const QModelIndex index = indexAt(ev->pos());
const bool indexIsValid = index.isValid();
QAction *act0 = new QAction(tr("Delete breakpoint"), &menu); QAction *act0 = new QAction(tr("Delete breakpoint"), &menu);
act0->setEnabled(index.isValid()); act0->setEnabled(indexIsValid);
QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu); QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu); QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
act2->setCheckable(true); act2->setCheckable(true);
act2->setChecked(m_alwaysResizeColumnsToContents); act2->setChecked(m_alwaysResizeColumnsToContents);
QAction *act3 = new QAction(tr("Edit condition..."), &menu); QAction *act3 = new QAction(tr("Edit condition..."), &menu);
act0->setEnabled(index.isValid()); act3->setEnabled(indexIsValid);
QAction *act4 = new QAction(tr("Syncronize breakpoints"), &menu); QAction *act4 = new QAction(tr("Synchronize breakpoints"), &menu);
menu.addAction(act0); menu.addAction(act0);
menu.addAction(act3); menu.addAction(act3);

View File

@@ -6,6 +6,10 @@ contains(QMAKE_CXX, cl) {
CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk" CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
!exists ($$CDB_PATH) {
CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk"
}
exists ($$CDB_PATH) { exists ($$CDB_PATH) {
message("Experimental: Adding support for $$CDB_PATH") message("Experimental: Adding support for $$CDB_PATH")
@@ -25,7 +29,9 @@ HEADERS += \
$$PWD/cdbdebugoutput.h \ $$PWD/cdbdebugoutput.h \
$$PWD/cdbsymbolgroupcontext.h \ $$PWD/cdbsymbolgroupcontext.h \
$$PWD/cdbstacktracecontext.h \ $$PWD/cdbstacktracecontext.h \
$$PWD/cdbbreakpoint.h $$PWD/cdbbreakpoint.h \
$$PWD/cdbmodules.h \
$$PWD/cdbassembler.h
SOURCES += \ SOURCES += \
$$PWD/cdbdebugengine.cpp \ $$PWD/cdbdebugengine.cpp \
@@ -33,7 +39,9 @@ SOURCES += \
$$PWD/cdbdebugoutput.cpp \ $$PWD/cdbdebugoutput.cpp \
$$PWD/cdbsymbolgroupcontext.cpp \ $$PWD/cdbsymbolgroupcontext.cpp \
$$PWD/cdbstacktracecontext.cpp \ $$PWD/cdbstacktracecontext.cpp \
$$PWD/cdbbreakpoint.cpp $$PWD/cdbbreakpoint.cpp \
$$PWD/cdbmodules.cpp \
$$PWD/cdbassembler.cpp
} else { } else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH") message("Debugging Tools for Windows could not be found in $$CDB_PATH")

View File

@@ -0,0 +1,234 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#include "cdbassembler.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,
QString *errorMessage, int base)
{
registers->clear();
ULONG count;
HRESULT hr = ireg->GetNumberRegisters(&count);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetNumberRegisters", hr);
return false;
}
if (!count)
return true;
// Retrieve names
WCHAR wszBuf[MAX_PATH];
for (ULONG r = 0; r < count; r++) {
hr = ireg->GetDescriptionWide(r, wszBuf, MAX_PATH - 1, 0, 0);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetDescriptionWide", hr);
return false;
}
Register reg;
reg.name = QString::fromUtf16(wszBuf);
registers->push_back(reg);
}
// get values
QVector<DEBUG_VALUE> values(count);
DEBUG_VALUE *valuesPtr = &(*values.begin());
memset(valuesPtr, 0, count * sizeof(DEBUG_VALUE));
hr = ireg->GetValues(count, 0, 0, valuesPtr);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetValues", hr);
return false;
}
if (base < 2)
base = 10;
for (ULONG r = 0; r < count; r++)
(*registers)[r].value = CdbSymbolGroupContext::debugValueToString(values.at(r), ctl, 0, base);
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;
}
} // namespace Internal
} // namespace Debugger

View File

@@ -0,0 +1,64 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#ifndef CDBASSEMBLER_H
#define CDBASSEMBLER_H
#include <QtCore/QList>
#include <QtCore/QString>
#include <windows.h>
#include <inc/dbgeng.h>
namespace Debugger {
namespace Internal {
class DisassemblerLine;
// Utilities related to assembler code.
class Register;
bool getRegisters(IDebugControl4 *ctl,
IDebugRegisters2 *ireg,
QList<Register> *registers,
QString *errorMessage,
int base = 10 /* 16 for hex, etc */);
bool dissassemble(IDebugClient5 *client,
IDebugControl4 *ctl,
ULONG64 offset,
unsigned long beforeLines,
unsigned long afterLines,
QList<DisassemblerLine> *lines,
QString *errorMessage);
} // namespace Internal
} // namespace Debugger
#endif // CDBASSEMBLER_H

View File

@@ -28,6 +28,7 @@
**************************************************************************/ **************************************************************************/
#include "cdbbreakpoint.h" #include "cdbbreakpoint.h"
#include "cdbmodules.h"
#include "breakhandler.h" #include "breakhandler.h"
#include "cdbdebugengine_p.h" #include "cdbdebugengine_p.h"
@@ -279,20 +280,48 @@ bool CDBBreakPoint::getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakP
return true; return true;
} }
// Synchronize (halted) engine breakpoints with those of the BreakHandler. // Synchronize (halted) engine breakpoints with those of the BreakHandler.
bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl, bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
IDebugSymbols3 *syms,
BreakHandler *handler, BreakHandler *handler,
QString *errorMessage) QString *errorMessage)
{ {
typedef QMap<CDBBreakPoint, int> BreakPointIndexMap; typedef QMap<CDBBreakPoint, int> BreakPointIndexMap;
BreakPointIndexMap breakPointIndexMap;
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
if (debugCDB) if (debugCDB)
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
BreakPointIndexMap breakPointIndexMap;
// convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index
// Ignore invalid functions (that could not be found) as they make
// the debugger hang.
const int handlerCount = handler->size(); const int handlerCount = handler->size();
for (int i=0; i < handlerCount; ++i) const QChar moduleDelimiter = QLatin1Char('!');
breakPointIndexMap.insert(CDBBreakPoint(*handler->at(i)), i); for (int i=0; i < handlerCount; ++i) {
BreakpointData *bd = handler->at(i);
// Function breakpoints: Are the module names specified?
bool breakPointOk = false;
if (bd->funcName.isEmpty()) {
breakPointOk = true;
} else {
switch (resolveSymbol(syms, &bd->funcName, errorMessage)) {
case ResolveSymbolOk:
breakPointOk = true;
break;
case ResolveSymbolAmbiguous:
qWarning("Warning: %s\n", qPrintable(*errorMessage));
breakPointOk = true;
break;
case ResolveSymbolNotFound:
case ResolveSymbolError:
qWarning("Warning: %s\n", qPrintable(*errorMessage));
break;
};
} // function breakpoint
if (breakPointOk)
breakPointIndexMap.insert(CDBBreakPoint(*bd), i);
}
errorMessage->clear();
// get number of engine breakpoints // get number of engine breakpoints
ULONG engineCount; ULONG engineCount;
if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) if (!getBreakPointCount(debugControl, &engineCount, errorMessage))
@@ -356,5 +385,5 @@ bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl,
return true; return true;
} }
} } // namespace Internal
} } // namespace Debugger

View File

@@ -49,7 +49,8 @@ class BreakpointData;
/* CDB Break point data structure with utilities to /* CDB Break point data structure with utilities to
* apply to engine and to retrieve them from the engine and comparison. */ * apply to engine and to retrieve them from the engine and comparison. */
struct CDBBreakPoint { struct CDBBreakPoint
{
CDBBreakPoint(); CDBBreakPoint();
CDBBreakPoint(const BreakpointData &bpd); CDBBreakPoint(const BreakpointData &bpd);
@@ -72,7 +73,8 @@ struct CDBBreakPoint {
static bool getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage = 0); static bool getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage = 0);
static bool getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage); static bool getBreakPoints(IDebugControl4* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage);
// Synchronize (halted) engine with BreakHandler. // Synchronize (halted) engine with BreakHandler.
static bool synchronizeBreakPoints(IDebugControl4* ctl, BreakHandler *bh, QString *errorMessage); static bool synchronizeBreakPoints(IDebugControl4* ctl, IDebugSymbols3 *syms,
BreakHandler *bh, QString *errorMessage);
// Return a 'canonical' file (using '/' and capitalized drive letter) // Return a 'canonical' file (using '/' and capitalized drive letter)
static QString canonicalSourceFile(const QString &f); static QString canonicalSourceFile(const QString &f);
@@ -93,7 +95,7 @@ inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2) inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
{ return b1.compare(b2) < 0; } { return b1.compare(b2) < 0; }
} } // namespace Internal
} } // namespace Debugger
#endif // CDBBREAKPOINTS_H #endif // CDBBREAKPOINTS_H

View File

@@ -32,11 +32,17 @@
#include "cdbsymbolgroupcontext.h" #include "cdbsymbolgroupcontext.h"
#include "cdbstacktracecontext.h" #include "cdbstacktracecontext.h"
#include "cdbbreakpoint.h" #include "cdbbreakpoint.h"
#include "cdbmodules.h"
#include "cdbassembler.h"
#include "debuggeractions.h"
#include "debuggermanager.h" #include "debuggermanager.h"
#include "breakhandler.h" #include "breakhandler.h"
#include "stackhandler.h" #include "stackhandler.h"
#include "watchhandler.h" #include "watchhandler.h"
#include "registerhandler.h"
#include "moduleshandler.h"
#include "disassemblerhandler.h"
#include "watchutils.h" #include "watchutils.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -51,6 +57,7 @@
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtGui/QMessageBox> #include <QtGui/QMessageBox>
#include <QtGui/QMainWindow> #include <QtGui/QMainWindow>
#include <QtGui/QApplication>
#define DBGHELP_TRANSLATE_TCHAR #define DBGHELP_TRANSLATE_TCHAR
#include <inc/Dbghelp.h> #include <inc/Dbghelp.h>
@@ -190,7 +197,6 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn
m_breakEventMode(BreakEventHandle), m_breakEventMode(BreakEventHandle),
m_watchTimer(-1), m_watchTimer(-1),
m_debugEventCallBack(engine), m_debugEventCallBack(engine),
m_debugOutputCallBack(engine),
m_pDebugClient(0), m_pDebugClient(0),
m_pDebugControl(0), m_pDebugControl(0),
m_pDebugSystemObjects(0), m_pDebugSystemObjects(0),
@@ -202,7 +208,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn
m_currentStackTrace(0), m_currentStackTrace(0),
m_firstActivatedFrame(true), m_firstActivatedFrame(true),
m_mode(AttachCore) m_mode(AttachCore)
{ {
} }
bool CdbDebugEnginePrivate::init(QString *errorMessage) bool CdbDebugEnginePrivate::init(QString *errorMessage)
@@ -220,7 +226,7 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage)
return false; return false;
} }
m_pDebugClient->SetOutputCallbacks(&m_debugOutputCallBack); m_pDebugClient->SetOutputCallbacksWide(&m_debugOutputCallBack);
m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack); m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack);
hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl)); hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl));
@@ -246,7 +252,7 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage)
hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters)); hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters));
if (FAILED(hr)) { if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr)); *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
return false; return false;
} }
if (debugCDB) if (debugCDB)
qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_pDebugControl)); qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_pDebugControl));
@@ -293,7 +299,7 @@ void CdbDebugEnginePrivate::clearForRun()
} }
void CdbDebugEnginePrivate::cleanStackTrace() void CdbDebugEnginePrivate::cleanStackTrace()
{ {
if (m_currentStackTrace) { if (m_currentStackTrace) {
delete m_currentStackTrace; delete m_currentStackTrace;
m_currentStackTrace = 0; m_currentStackTrace = 0;
@@ -308,6 +314,14 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) :
connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)), this, SLOT(slotConsoleStubError(QString))); connect(&m_d->m_consoleStubProc, SIGNAL(processError(QString)), this, SLOT(slotConsoleStubError(QString)));
connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), this, SLOT(slotConsoleStubStarted())); connect(&m_d->m_consoleStubProc, SIGNAL(processStarted()), this, SLOT(slotConsoleStubStarted()));
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), this, SLOT(slotConsoleStubTerminated())); connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()), this, SLOT(slotConsoleStubTerminated()));
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerOutput(QString,QString)),
m_d->m_debuggerManager, SLOT(showDebuggerOutput(QString,QString)));
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerInputPrompt(QString,QString)),
m_d->m_debuggerManager, SLOT(showDebuggerInput(QString,QString)));
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeOutput(QString)),
m_d->m_debuggerManager, SLOT(showApplicationOutput(QString)));
connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeInputPrompt(QString)),
m_d->m_debuggerManager, SLOT(showApplicationOutput(QString)));
} }
CdbDebugEngine::~CdbDebugEngine() CdbDebugEngine::~CdbDebugEngine()
@@ -344,8 +358,16 @@ void CdbDebugEngine::setToolTipExpression(const QPoint & /*pos*/, const QString
{ {
} }
void CdbDebugEnginePrivate::clearDisplay()
{
m_debuggerManagerAccess->threadsHandler()->removeAll();
m_debuggerManagerAccess->modulesHandler()->removeAll();
m_debuggerManagerAccess->registerHandler()->removeAll();
}
bool CdbDebugEngine::startDebugger() bool CdbDebugEngine::startDebugger()
{ {
m_d->clearDisplay();
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1); m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
QString errorMessage; QString errorMessage;
bool rc = false; bool rc = false;
@@ -467,7 +489,7 @@ void CdbDebugEngine::exitDebugger()
// Terminate or detach if we are running // Terminate or detach if we are running
HRESULT hr; HRESULT hr;
switch (m_d->m_mode) { switch (m_d->m_mode) {
case AttachExternal: case AttachExternal:
wasRunning = m_d->isDebuggeeRunning(); wasRunning = m_d->isDebuggeeRunning();
if (wasRunning) { // Process must be stopped in order to detach if (wasRunning) { // Process must be stopped in order to detach
m_d->interruptInterferiorProcess(&errorMessage); m_d->interruptInterferiorProcess(&errorMessage);
@@ -480,7 +502,7 @@ void CdbDebugEngine::exitDebugger()
qDebug() << Q_FUNC_INFO << "detached" << msgDebugEngineComResult(hr); qDebug() << Q_FUNC_INFO << "detached" << msgDebugEngineComResult(hr);
break; break;
case StartExternal: case StartExternal:
case StartInternal: case StartInternal:
wasRunning = m_d->isDebuggeeRunning(); wasRunning = m_d->isDebuggeeRunning();
if (wasRunning) { // Process must be stopped in order to terminate if (wasRunning) { // Process must be stopped in order to terminate
m_d->interruptInterferiorProcess(&errorMessage); m_d->interruptInterferiorProcess(&errorMessage);
@@ -547,7 +569,7 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
qDebug() << Q_FUNC_INFO << "\n " << frameIndex << formatWatchList(incompletes); qDebug() << Q_FUNC_INFO << "\n " << frameIndex << formatWatchList(incompletes);
m_engine->filterEvaluateWatchers(&incompletes, wh); m_engine->filterEvaluateWatchers(&incompletes, wh);
if (!incompletes.empty()) { if (!incompletes.empty()) {
const QString msg = QLatin1String("Warning: Locals left in incomplete list: ") + formatWatchList(incompletes); const QString msg = QLatin1String("Warning: Locals left in incomplete list: ") + formatWatchList(incompletes);
qWarning("%s\n", qPrintable(msg)); qWarning("%s\n", qPrintable(msg));
} }
@@ -591,7 +613,7 @@ void CdbDebugEngine::filterEvaluateWatchers(QList<WatchData> *wd, WatchHandler *
bool placeHolderSeen = false; bool placeHolderSeen = false;
for (WatchList::iterator it = wd->begin(); it != wd->end(); ) { for (WatchList::iterator it = wd->begin(); it != wd->end(); ) {
if (it->iname.startsWith(watcherPrefix)) { if (it->iname.startsWith(watcherPrefix)) {
const bool isPlaceHolder = it->exp.startsWith(lessThan) && it->exp.endsWith(greaterThan); const bool isPlaceHolder = it->exp.startsWith(lessThan) && it->exp.endsWith(greaterThan);
if (isPlaceHolder) { if (isPlaceHolder) {
if (!placeHolderSeen) { // Max one place holder if (!placeHolderSeen) { // Max one place holder
it->setChildCount(0); it->setChildCount(0);
@@ -602,7 +624,7 @@ void CdbDebugEngine::filterEvaluateWatchers(QList<WatchData> *wd, WatchHandler *
} else { } else {
evaluateWatcher(&(*it)); evaluateWatcher(&(*it));
wh->insertData(*it); wh->insertData(*it);
} }
it = wd->erase(it); it = wd->erase(it);
} else { } else {
++it; ++it;
@@ -756,7 +778,7 @@ bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessage)
// Continue process with notifications // Continue process with notifications
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage) bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
{ {
ULONG executionStatus; ULONG executionStatus;
if (!getExecutionStatus(m_pDebugControl, &executionStatus, errorMessage)) if (!getExecutionStatus(m_pDebugControl, &executionStatus, errorMessage))
return false; return false;
@@ -795,7 +817,7 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
*errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Core::Utils::winErrorMessage(GetLastError())); *errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Core::Utils::winErrorMessage(GetLastError()));
return false; return false;
} }
#if 0 #if 0
const HRESULT hr = m_pDebugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT); const HRESULT hr = m_pDebugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT);
if (FAILED(hr)) { if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2"). *errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2").
@@ -842,7 +864,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
if (debugCDB) if (debugCDB)
qDebug() << Q_FUNC_INFO << expr << value; qDebug() << Q_FUNC_INFO << expr << value;
const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex(); const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex();
QString errorMessage; QString errorMessage;
bool success = false; bool success = false;
do { do {
QString newValue; QString newValue;
@@ -850,7 +872,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
if (!sg) if (!sg)
break; break;
if (!sg->assignValue(expr, value, &newValue, &errorMessage)) if (!sg->assignValue(expr, value, &newValue, &errorMessage))
break; break;
// Update view // Update view
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
if (WatchData *fwd = watchHandler->findData(expr)) { if (WatchData *fwd = watchHandler->findData(expr)) {
@@ -1010,6 +1032,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
} }
return CDBBreakPoint::synchronizeBreakPoints(m_pDebugControl, return CDBBreakPoint::synchronizeBreakPoints(m_pDebugControl,
m_pDebugSymbols,
m_debuggerManagerAccess->breakHandler(), m_debuggerManagerAccess->breakHandler(),
errorMessage); errorMessage);
} }
@@ -1024,6 +1047,30 @@ void CdbDebugEngine::saveSessionData()
void CdbDebugEngine::reloadDisassembler() void CdbDebugEngine::reloadDisassembler()
{ {
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_pDebugClient, m_d->m_pDebugControl, offset,
ContextLines, ContextLines, &lines, &errorMessage);
QApplication::restoreOverrideCursor();
if (drc) {
dh->setLines(lines);
if (lines.size() > ContextLines)
dh->setCurrentLine(ContextLines);
} else {
qWarning("reloadDisassembler: %s\n", qPrintable(errorMessage));
}
} else {
dh->setLines(QList<DisassemblerLine>());
}
} }
void CdbDebugEngine::reloadModules() void CdbDebugEngine::reloadModules()
@@ -1042,8 +1089,54 @@ void CdbDebugEngine::loadAllSymbols()
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
} }
QList<Symbol> CdbDebugEngine::moduleSymbols(const QString &moduleName)
{
QList<Symbol> rc;
QString errorMessage;
bool success = false;
do {
if (m_d->isDebuggeeRunning()) {
errorMessage = tr("Cannot retrieve symbols while the debuggee is running.");
break;
}
if (!getModuleSymbols(m_d->m_pDebugSymbols, moduleName, &rc, &errorMessage))
break;
success = true;
} while (false);
if (!success)
qWarning("%s\n", qPrintable(errorMessage));
return rc;
}
static inline int registerFormatBase()
{
switch(checkedRegisterFormatAction()) {
case FormatHexadecimal:
return 16;
case FormatDecimal:
return 10;
case FormatOctal:
return 8;
case FormatBinary:
return 2;
break;
case FormatRaw:
case FormatNatural:
break;
}
return 10;
}
void CdbDebugEngine::reloadRegisters() void CdbDebugEngine::reloadRegisters()
{ {
const int intBase = registerFormatBase();
if (debugCDB)
qDebug() << Q_FUNC_INFO << intBase;
QList<Register> registers;
QString errorMessage;
if (!getRegisters(m_d->m_pDebugControl, m_d->m_pDebugRegisters, &registers, &errorMessage, intBase))
qWarning("reloadRegisters() failed: %s\n", qPrintable(errorMessage));
m_d->m_debuggerManagerAccess->registerHandler()->setRegisters(registers);
} }
void CdbDebugEngine::timerEvent(QTimerEvent* te) void CdbDebugEngine::timerEvent(QTimerEvent* te)
@@ -1067,7 +1160,7 @@ void CdbDebugEngine::timerEvent(QTimerEvent* te)
break; break;
case E_UNEXPECTED: // Occurs on ExitProcess. case E_UNEXPECTED: // Occurs on ExitProcess.
killWatchTimer(); killWatchTimer();
break; break;
} }
} }
@@ -1142,21 +1235,34 @@ void CdbDebugEnginePrivate::updateThreadList()
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler(); ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
QList<ThreadData> threads; QList<ThreadData> threads;
bool success = false;
QString errorMessage;
do {
ULONG numberOfThreads;
HRESULT hr= m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads);
if (FAILED(hr)) {
errorMessage= msgComFailed("GetNumberThreads", hr);
break;
}
const ULONG maxThreadIds = 256;
ULONG threadIds[maxThreadIds];
ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
hr = m_pDebugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
if (FAILED(hr)) {
errorMessage= msgComFailed("GetThreadIdsByIndex", hr);
break;
}
for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
ThreadData thread;
thread.id = threadId;
threads.append(thread);
}
HRESULT hr; th->setThreads(threads);
ULONG numberOfThreads; success = true;
hr = m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads); } while (false);
const ULONG maxThreadIds = 256; if (!success)
ULONG threadIds[maxThreadIds]; qWarning("updateThreadList() failed: %s\n", qPrintable(errorMessage));
ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
hr = m_pDebugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
ThreadData thread;
thread.id = threadId;
threads.append(thread);
}
th->setThreads(threads);
} }
void CdbDebugEnginePrivate::updateStackTrace() void CdbDebugEnginePrivate::updateStackTrace()
@@ -1166,6 +1272,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
// Create a new context // Create a new context
clearForRun(); clearForRun();
QString errorMessage; QString errorMessage;
m_engine->reloadRegisters();
m_currentStackTrace = m_currentStackTrace =
CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects, CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects,
m_pDebugSymbols, m_currentThreadId, &errorMessage); m_pDebugSymbols, m_currentThreadId, &errorMessage);
@@ -1173,6 +1280,10 @@ void CdbDebugEnginePrivate::updateStackTrace()
qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage)); qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
return; return;
} }
// Disassembling slows things down a bit. Assembler is still available via menu.
#if 0
m_engine->reloadDisassembler(); // requires stack trace
#endif
const QList<StackFrame> stackFrames = m_currentStackTrace->frames(); const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
// find the first usable frame and select it // find the first usable frame and select it
int current = -1; int current = -1;
@@ -1188,14 +1299,17 @@ void CdbDebugEnginePrivate::updateStackTrace()
if (current >= 0) { if (current >= 0) {
m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current); m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current);
m_engine->activateFrame(current); m_engine->activateFrame(current);
} }
} }
void CdbDebugEnginePrivate::handleDebugOutput(const char *szOutputString)
void CdbDebugEnginePrivate::updateModules()
{ {
if (debugCDB && strstr(szOutputString, "ModLoad:") == 0) QList<Module> modules;
qDebug() << Q_FUNC_INFO << szOutputString; QString errorMessage;
m_debuggerManagerAccess->showApplicationOutput(QString::fromLocal8Bit(szOutputString)); if (!getModuleList(m_pDebugSymbols, &modules, &errorMessage))
qWarning("updateModules() failed: %s\n", qPrintable(errorMessage));
m_debuggerManagerAccess->modulesHandler()->setModules(modules);
} }
void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP) void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP)

View File

@@ -87,6 +87,7 @@ public:
virtual void reloadModules(); virtual void reloadModules();
virtual void loadSymbols(const QString &moduleName); virtual void loadSymbols(const QString &moduleName);
virtual void loadAllSymbols(); virtual void loadAllSymbols();
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
virtual void reloadRegisters(); virtual void reloadRegisters();
virtual void reloadSourceFiles(); virtual void reloadSourceFiles();

View File

@@ -48,7 +48,8 @@ class CdbStackTraceContext;
// Thin wrapper around the 'DBEng' debugger engine shared library // Thin wrapper around the 'DBEng' debugger engine shared library
// which is loaded at runtime. // which is loaded at runtime.
class DebuggerEngineLibrary { class DebuggerEngineLibrary
{
public: public:
DebuggerEngineLibrary(); DebuggerEngineLibrary();
bool init(QString *errorMessage); bool init(QString *errorMessage);
@@ -79,14 +80,16 @@ struct CdbDebugEnginePrivate
bool isDebuggeeRunning() const { return m_watchTimer != -1; } bool isDebuggeeRunning() const { return m_watchTimer != -1; }
void handleDebugEvent(); void handleDebugEvent();
void updateThreadList(); void updateThreadList();
void updateStackTrace(); void updateStackTrace();
bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage); bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage);
void handleDebugOutput(const char* szOutputString); void updateModules();
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP); void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
void cleanStackTrace(); void cleanStackTrace();
void clearForRun(); void clearForRun();
CdbSymbolGroupContext *getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const; CdbSymbolGroupContext *getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const;
void clearDisplay();
bool interruptInterferiorProcess(QString *errorMessage); bool interruptInterferiorProcess(QString *errorMessage);

View File

@@ -76,8 +76,9 @@ STDMETHODIMP_(ULONG) CdbDebugEventCallback::Release(THIS)
STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask) STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
{ {
*mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS *mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS
//| DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD | DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_UNLOAD_MODULE
| DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD
| DEBUG_EVENT_BREAKPOINT | DEBUG_EVENT_BREAKPOINT
| DEBUG_EVENT_EXCEPTION | DEBUG_EVENT_EXCEPTION
; ;
@@ -125,13 +126,9 @@ STDMETHODIMP CdbDebugEventCallback::CreateThread(
Q_UNUSED(Handle) Q_UNUSED(Handle)
Q_UNUSED(DataOffset) Q_UNUSED(DataOffset)
Q_UNUSED(StartOffset) Q_UNUSED(StartOffset)
if (debugCDB) if (debugCDB)
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
//Debugger::ThreadInfo ti; m_pEngine->m_d->updateThreadList();
//ti.handle = Handle;
//ti.dataOffset = DataOffset;
//ti.startOffset = StartOffset;
return S_OK; return S_OK;
} }
@@ -142,7 +139,8 @@ STDMETHODIMP CdbDebugEventCallback::ExitThread(
{ {
if (debugCDB) if (debugCDB)
qDebug() << Q_FUNC_INFO << ExitCode; qDebug() << Q_FUNC_INFO << ExitCode;
// @TODO: It seems the terminated thread is still in the list...
m_pEngine->m_d->updateThreadList();
return S_OK; return S_OK;
} }
@@ -211,14 +209,14 @@ STDMETHODIMP CdbDebugEventCallback::LoadModule(
{ {
Q_UNUSED(ImageFileHandle) Q_UNUSED(ImageFileHandle)
Q_UNUSED(BaseOffset) Q_UNUSED(BaseOffset)
Q_UNUSED(ModuleSize)
Q_UNUSED(ModuleName) Q_UNUSED(ModuleName)
Q_UNUSED(ModuleSize)
Q_UNUSED(ImageName) Q_UNUSED(ImageName)
Q_UNUSED(CheckSum) Q_UNUSED(CheckSum)
Q_UNUSED(TimeDateStamp) Q_UNUSED(TimeDateStamp)
if (debugCDB) if (debugCDB > 1)
qDebug() << Q_FUNC_INFO << ModuleName; qDebug() << Q_FUNC_INFO << ModuleName;
m_pEngine->m_d->updateModules();
return S_OK; return S_OK;
} }
@@ -230,9 +228,9 @@ STDMETHODIMP CdbDebugEventCallback::UnloadModule(
{ {
Q_UNUSED(ImageBaseName) Q_UNUSED(ImageBaseName)
Q_UNUSED(BaseOffset) Q_UNUSED(BaseOffset)
if (debugCDB) if (debugCDB > 1)
qDebug() << Q_FUNC_INFO << ImageBaseName; qDebug() << Q_FUNC_INFO << ImageBaseName;
m_pEngine->m_d->updateModules();
return S_OK; return S_OK;
} }

View File

@@ -27,7 +27,6 @@
** **
**************************************************************************/ **************************************************************************/
#include "cdbdebugoutput.h" #include "cdbdebugoutput.h"
#include "cdbdebugengine.h" #include "cdbdebugengine.h"
#include "cdbdebugengine_p.h" #include "cdbdebugengine_p.h"
@@ -38,12 +37,11 @@
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
CdbDebugOutput::CdbDebugOutput(CdbDebugEngine* engine) : CdbDebugOutputBase::CdbDebugOutputBase()
m_pEngine(engine)
{ {
} }
STDMETHODIMP CdbDebugOutput::QueryInterface( STDMETHODIMP CdbDebugOutputBase::QueryInterface(
THIS_ THIS_
IN REFIID InterfaceId, IN REFIID InterfaceId,
OUT PVOID* Interface OUT PVOID* Interface
@@ -52,9 +50,9 @@ STDMETHODIMP CdbDebugOutput::QueryInterface(
*Interface = NULL; *Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks))) IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacksWide)))
{ {
*Interface = (IDebugOutputCallbacks *)this; *Interface = (IDebugOutputCallbacksWide*)this;
AddRef(); AddRef();
return S_OK; return S_OK;
} else { } else {
@@ -62,30 +60,100 @@ STDMETHODIMP CdbDebugOutput::QueryInterface(
} }
} }
STDMETHODIMP_(ULONG) CdbDebugOutput::AddRef(THIS) STDMETHODIMP_(ULONG) CdbDebugOutputBase::AddRef(THIS)
{ {
// This class is designed to be static so // This class is designed to be static so
// there's no true refcount. // there's no true refcount.
return 1; return 1;
} }
STDMETHODIMP_(ULONG) CdbDebugOutput::Release(THIS) STDMETHODIMP_(ULONG) CdbDebugOutputBase::Release(THIS)
{ {
// This class is designed to be static so // This class is designed to be static so
// there's no true refcount. // there's no true refcount.
return 0; return 0;
} }
STDMETHODIMP CdbDebugOutput::Output( STDMETHODIMP CdbDebugOutputBase::Output(
THIS_ THIS_
IN ULONG mask, IN ULONG mask,
IN PCSTR text IN PCWSTR text
) )
{ {
UNREFERENCED_PARAMETER(mask); output(mask, QString::fromUtf16(text));
m_pEngine->m_d->handleDebugOutput(text);
return S_OK; return S_OK;
} }
IDebugOutputCallbacksWide *CdbDebugOutputBase::getOutputCallback(IDebugClient5 *client)
{
IDebugOutputCallbacksWide *rc;
if (FAILED(client->GetOutputCallbacksWide(&rc)))
return 0;
return rc;
}
// ------------------------- CdbDebugOutput
// Return a prefix for debugger messages
static QString prefix(ULONG mask)
{
if (mask & (DEBUG_OUTPUT_PROMPT_REGISTERS)) {
static const QString p = QLatin1String("registers:");
return p;
}
if (mask & (DEBUG_OUTPUT_EXTENSION_WARNING|DEBUG_OUTPUT_WARNING)) {
static const QString p = QLatin1String("warning:");
return p;
}
if (mask & (DEBUG_OUTPUT_ERROR)) {
static const QString p = QLatin1String("error:");
return p;
}
if (mask & DEBUG_OUTPUT_SYMBOLS) {
static const QString p = QLatin1String("symbols:");
return p;
}
static const QString commonPrefix = QLatin1String("cdb:");
return commonPrefix;
}
enum OutputKind { DebuggerOutput, DebuggerPromptOutput, DebuggeeOutput, DebuggeePromptOutput };
static inline OutputKind outputKind(ULONG mask)
{
if (mask & DEBUG_OUTPUT_DEBUGGEE)
return DebuggeeOutput;
if (mask & DEBUG_OUTPUT_DEBUGGEE_PROMPT)
return DebuggeePromptOutput;
if (mask & DEBUG_OUTPUT_PROMPT)
return DebuggerPromptOutput;
return DebuggerOutput;
}
CdbDebugOutput::CdbDebugOutput()
{
}
void CdbDebugOutput::output(ULONG mask, const QString &msg)
{
if (debugCDB > 1)
qDebug() << Q_FUNC_INFO << "\n " << msg;
switch (outputKind(mask)) {
case DebuggerOutput:
debuggerOutput(prefix(mask), msg);
break;
case DebuggerPromptOutput:
emit debuggerInputPrompt(prefix(mask), msg);
break;
case DebuggeeOutput:
emit debuggeeOutput(msg);
break;
case DebuggeePromptOutput:
emit debuggeeInputPrompt(msg);
break;
}
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -33,16 +33,17 @@
#include <windows.h> #include <windows.h>
#include <inc/dbgeng.h> #include <inc/dbgeng.h>
#include <QtCore/QObject>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class CdbDebugEngine; // CdbDebugOutputBase is a base class for output handlers
// that takes care of the Active X magic and conversion to QString.
class CdbDebugOutput : public IDebugOutputCallbacks class CdbDebugOutputBase : public IDebugOutputCallbacksWide
{ {
public: public:
explicit CdbDebugOutput(CdbDebugEngine* engine);
// IUnknown. // IUnknown.
STDMETHOD(QueryInterface)( STDMETHOD(QueryInterface)(
THIS_ THIS_
@@ -60,11 +61,48 @@ public:
STDMETHOD(Output)( STDMETHOD(Output)(
THIS_ THIS_
IN ULONG mask, IN ULONG mask,
IN PCSTR text IN PCWSTR text
); );
// Helpers to retrieve the output callbacks IF
static IDebugOutputCallbacksWide *getOutputCallback(IDebugClient5 *client);
protected:
CdbDebugOutputBase();
virtual void output(ULONG mask, const QString &message) = 0;
};
// Standard CDB output handler
class CdbDebugOutput : public QObject, public CdbDebugOutputBase
{
Q_OBJECT
public:
CdbDebugOutput();
protected:
virtual void output(ULONG mask, const QString &message);
signals:
void debuggerOutput(const QString &prefix, const QString &message);
void debuggerInputPrompt(const QString &prefix, const QString &message);
void debuggeeOutput(const QString &message);
void debuggeeInputPrompt(const QString &message);
};
// An output handler that adds lines to a string (to be
// used for cases in which linebreaks occur in-between calls
// to output).
class StringOutputHandler : public CdbDebugOutputBase
{
public:
StringOutputHandler() {}
QString result() const { return m_result; }
protected:
virtual void output(ULONG, const QString &message) { m_result += message; }
private: private:
CdbDebugEngine* m_pEngine; QString m_result;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -0,0 +1,163 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#include "cdbmodules.h"
#include "moduleshandler.h"
#include "cdbdebugengine_p.h"
#include <QtCore/QFileInfo>
namespace Debugger {
namespace Internal {
bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage)
{
modules->clear();
ULONG loadedCount, unloadedCount;
HRESULT hr = syms->GetNumberModules(&loadedCount, &unloadedCount);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetNumberModules", hr);
return false;
}
// retrieve array of parameters
const ULONG count = loadedCount + unloadedCount;
QVector<DEBUG_MODULE_PARAMETERS> parameters(count);
DEBUG_MODULE_PARAMETERS *parmPtr = &(*parameters.begin());
memset(parmPtr, 0, sizeof(DEBUG_MODULE_PARAMETERS) * count);
hr = syms->GetModuleParameters(count, 0, 0u, parmPtr);
// E_INVALIDARG indicates 'Partial results' according to docu
if (FAILED(hr) && hr != E_INVALIDARG) {
*errorMessage= msgComFailed("GetModuleParameters", hr);
return false;
}
// fill array
const QString hexPrefix = QLatin1String("0x");
WCHAR wszBuf[MAX_PATH];
for (ULONG m = 0; m < count; m++) {
const DEBUG_MODULE_PARAMETERS &p = parameters.at(m);
if (p.Base != DEBUG_INVALID_OFFSET) { // Partial results?
Module module;
module.symbolsRead = (p.Flags & DEBUG_MODULE_USER_MODE)
&& (p.SymbolType != DEBUG_SYMTYPE_NONE);
module.startAddress = hexPrefix + QString::number(p.Base, 16);
module.endAddress = hexPrefix + QString::number((p.Base + p.Size), 16);
hr = syms ->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, m, 0, wszBuf, MAX_PATH - 1, 0);
if (FAILED(hr) && hr != E_INVALIDARG) {
*errorMessage= msgComFailed("GetModuleNameStringWide", hr);
return false;
}
module.moduleName = QString::fromUtf16(wszBuf);
modules->push_back(module);
}
}
return true;
}
// Search symbols matching a pattern
bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
QStringList *matches, QString *errorMessage)
{
matches->clear();
ULONG64 handle = 0;
// E_NOINTERFACE means "no match". Apparently, it does not always
// set handle.
HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle);
if (hr == E_NOINTERFACE) {
if (handle)
syms->EndSymbolMatch(handle);
return true;
}
if (FAILED(hr)) {
*errorMessage= msgComFailed("StartSymbolMatchWide", hr);
return false;
}
WCHAR wszBuf[MAX_PATH];
while (true) {
hr = syms->GetNextSymbolMatchWide(handle, wszBuf, MAX_PATH - 1, 0, 0);
if (hr == E_NOINTERFACE)
break;
if (hr == S_OK)
matches->push_back(QString::fromUtf16(wszBuf));
}
syms->EndSymbolMatch(handle);
if (matches->empty())
*errorMessage = QString::fromLatin1("No symbol matches '%1'.").arg(pattern);
return true;
}
// Add missing the module specifier: "main" -> "project!main"
ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol,
QString *errorMessage)
{
// Is it an incomplete symbol?
if (symbol->contains(QLatin1Char('!')))
return ResolveSymbolOk;
// 'main' is a #define for gdb, but not for VS
if (*symbol == QLatin1String("qMain"))
*symbol = QLatin1String("main");
// resolve
QStringList matches;
if (!searchSymbols(syms, *symbol, &matches, errorMessage))
return ResolveSymbolError;
if (matches.empty())
return ResolveSymbolNotFound;
*symbol = matches.front();
if (matches.size() > 1) {
*errorMessage = QString::fromLatin1("Ambiguous symbol '%1': %2").
arg(*symbol, matches.join(QString(QLatin1Char(' '))));
return ResolveSymbolAmbiguous;
}
return ResolveSymbolOk;
}
// List symbols of a module
bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
QList<Symbol> *symbols, QString *errorMessage)
{
// Search all symbols and retrieve addresses
symbols->clear();
QStringList matches;
const QString pattern = QFileInfo(moduleName).baseName() + QLatin1String("!*");
if (!searchSymbols(syms, pattern, &matches, errorMessage))
return false;
const QString hexPrefix = QLatin1String("0x");
foreach (const QString &name, matches) {
Symbol symbol;
symbol.name = name;
ULONG64 offset = 0;
if (SUCCEEDED(syms->GetOffsetByNameWide(name.utf16(), &offset)))
symbol.address = hexPrefix + QString::number(offset, 16);
symbols->push_back(symbol);
}
return true;
}
} // namespace Internal
} // namespace Debugger

View File

@@ -0,0 +1,65 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#ifndef CDBMODULES_H
#define CDBMODULES_H
#include <QtCore/QList>
#include <QtCore/QString>
#include <windows.h>
#include <inc/dbgeng.h>
namespace Debugger {
namespace Internal {
class Module;
class Symbol;
bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage);
// Search symbols matching a pattern
bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
QStringList *matches, QString *errorMessage);
// ResolveSymbol: For symbols that are missing the module specifier,
// find the module and expand: "main" -> "project!main".
enum ResolveSymbolResult { ResolveSymbolOk, ResolveSymbolAmbiguous,
ResolveSymbolNotFound, ResolveSymbolError };
ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString *errorMessage);
// List symbols of a module
bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
QList<Symbol> *symbols, QString *errorMessage);
} // namespace Internal
} // namespace Debugger
#endif // CDBMODULES_H

View File

@@ -40,7 +40,8 @@ namespace Internal {
CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects, CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects,
IDebugSymbols3* pDebugSymbols) : IDebugSymbols3* pDebugSymbols) :
m_pDebugSystemObjects(pDebugSystemObjects), m_pDebugSystemObjects(pDebugSystemObjects),
m_pDebugSymbols(pDebugSymbols) m_pDebugSymbols(pDebugSymbols),
m_instructionOffset(0)
{ {
} }
@@ -95,6 +96,8 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
for (ULONG i=0; i < frameCount; ++i) { for (ULONG i=0; i < frameCount; ++i) {
StackFrame frame(i); StackFrame frame(i);
const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset; const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset;
if (i == 0)
m_instructionOffset = instructionOffset;
frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16); frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16);
m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0); m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0);
@@ -163,5 +166,5 @@ IDebugSymbolGroup2 *CdbStackTraceContext::createSymbolGroup(int index, QString *
return sg; return sg;
} }
} } // namespace Internal
} } // namespace Debugger

View File

@@ -66,6 +66,9 @@ public:
QList<StackFrame> frames() const { return m_frames; } QList<StackFrame> frames() const { return m_frames; }
inline int frameCount() const { return m_frames.size(); } inline int frameCount() const { return m_frames.size(); }
// Top-Level instruction offset for disassembler
ULONG64 instructionOffset() const { return m_instructionOffset; }
CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage); CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage);
private: private:
@@ -78,9 +81,10 @@ private:
DEBUG_STACK_FRAME m_cdbFrames[maxFrames]; DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
QVector <CdbSymbolGroupContext*> m_symbolContexts; QVector <CdbSymbolGroupContext*> m_symbolContexts;
QList<StackFrame> m_frames; QList<StackFrame> m_frames;
ULONG64 m_instructionOffset;
}; };
} } // namespace Internal
} } // namespace Debugger
#endif // CDBSTACKTRACECONTEXT_H #endif // CDBSTACKTRACECONTEXT_H

View File

@@ -58,13 +58,13 @@ static inline void debugSymbolFlags(unsigned long f, QTextStream &str)
str << "|DEBUG_SYMBOL_IS_LOCAL"; str << "|DEBUG_SYMBOL_IS_LOCAL";
} }
QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS& p) QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS &p)
{ {
str << " Type=" << p.TypeId << " parent="; str << " Type=" << p.TypeId << " parent=";
if (isTopLevelSymbol(p)) { if (isTopLevelSymbol(p)) {
str << "<ROOT>"; str << "<ROOT>";
} else { } else {
str << p.ParentSymbol; str << p.ParentSymbol;
} }
str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/'; str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/';
debugSymbolFlags(p.Flags, str); debugSymbolFlags(p.Flags, str);
@@ -403,45 +403,67 @@ bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &val
// format an array of integers as "0x323, 0x2322, ..." // format an array of integers as "0x323, 0x2322, ..."
template <class Integer> template <class Integer>
static QString hexFormatArrayHelper(const Integer *array, int size) static QString formatArrayHelper(const Integer *array, int size, int base = 10)
{ {
QString rc; QString rc;
const QString hexPrefix = QLatin1String("0x"); const QString hexPrefix = QLatin1String("0x");
const QString separator= QLatin1String(", "); const QString separator= QLatin1String(", ");
const bool hex = base == 16;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (i) if (i)
rc += separator; rc += separator;
rc += hexPrefix; if (hex)
rc += QString::number(array[i], 16); rc += hexPrefix;
rc += QString::number(array[i], base);
} }
return rc; return rc;
} }
QString CdbSymbolGroupContext::hexFormatArray(const unsigned short *array, int size) QString CdbSymbolGroupContext::hexFormatArray(const unsigned short *array, int size)
{ {
return hexFormatArrayHelper(array, size); return formatArrayHelper(array, size, 16);
} }
QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl, QString *type) // Helper to format an integer with
// a hex prefix in case base = 16
template <class Integer>
inline QString formatInteger(Integer value, int base)
{
QString rc;
if (base == 16)
rc = QLatin1String("0x");
rc += QString::number(value, base);
return rc;
}
QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl,
QString *qType,
int integerBase)
{ {
switch (dv.Type) { switch (dv.Type) {
case DEBUG_VALUE_INT8: case DEBUG_VALUE_INT8:
*type = QLatin1String("char"); if (qType)
return QString::number(dv.I8); *qType = QLatin1String("char");
return formatInteger(dv.I8, integerBase);
case DEBUG_VALUE_INT16: case DEBUG_VALUE_INT16:
*type = QLatin1String("short"); if (qType)
return QString::number(static_cast<short>(dv.I16)); *qType = QLatin1String("short");
return formatInteger(static_cast<short>(dv.I16), integerBase);
case DEBUG_VALUE_INT32: case DEBUG_VALUE_INT32:
*type = QLatin1String("long"); if (qType)
return QString::number(static_cast<long>(dv.I32)); *qType = QLatin1String("long");
return formatInteger(static_cast<long>(dv.I32), integerBase);
case DEBUG_VALUE_INT64: case DEBUG_VALUE_INT64:
*type = QLatin1String("long long"); if (qType)
return QString::number(static_cast<long long>(dv.I64)); *qType = QLatin1String("long long");
return formatInteger(static_cast<long long>(dv.I64), integerBase);
case DEBUG_VALUE_FLOAT32: case DEBUG_VALUE_FLOAT32:
*type = QLatin1String("float"); if (qType)
*qType = QLatin1String("float");
return QString::number(dv.F32); return QString::number(dv.F32);
case DEBUG_VALUE_FLOAT64: case DEBUG_VALUE_FLOAT64:
*type = QLatin1String("double"); if (qType)
*qType = QLatin1String("double");
return QString::number(dv.F64); return QString::number(dv.F64);
case DEBUG_VALUE_FLOAT80: case DEBUG_VALUE_FLOAT80:
case DEBUG_VALUE_FLOAT128: { // Convert to double case DEBUG_VALUE_FLOAT128: { // Convert to double
@@ -449,28 +471,32 @@ QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, IDebugC
double d = 0.0; double d = 0.0;
if (SUCCEEDED(ctl->CoerceValue(const_cast<DEBUG_VALUE*>(&dv), DEBUG_VALUE_FLOAT64, &doubleValue))) if (SUCCEEDED(ctl->CoerceValue(const_cast<DEBUG_VALUE*>(&dv), DEBUG_VALUE_FLOAT64, &doubleValue)))
d = dv.F64; d = dv.F64;
*type = dv.Type == DEBUG_VALUE_FLOAT80 ? QLatin1String("80bit-float") : QLatin1String("128bit-float"); if (qType)
*qType = QLatin1String(dv.Type == DEBUG_VALUE_FLOAT80 ? "80bit-float" : "128bit-float");
return QString::number(d); return QString::number(d);
} }
case DEBUG_VALUE_VECTOR64: { case DEBUG_VALUE_VECTOR64: {
*type = QLatin1String("64bit-vector"); if (qType)
QString rc = QLatin1String("bytes: "); *qType = QLatin1String("64bit-vector");
rc += hexFormatArrayHelper(dv.VI8, 8); QString rc = QLatin1String("bytes: ");
rc += QLatin1String(" long: "); rc += formatArrayHelper(dv.VI8, 8, integerBase);
rc += hexFormatArrayHelper(dv.VI32, 2); rc += QLatin1String(" long: ");
return rc; rc += formatArrayHelper(dv.VI32, 2, integerBase);
} return rc;
}
case DEBUG_VALUE_VECTOR128: { case DEBUG_VALUE_VECTOR128: {
*type = QLatin1String("128bit-vector"); if (qType)
QString rc = QLatin1String("bytes: "); *qType = QLatin1String("128bit-vector");
rc += hexFormatArrayHelper(dv.VI8, 16); QString rc = QLatin1String("bytes: ");
rc += QLatin1String(" long long: "); rc += formatArrayHelper(dv.VI8, 16, integerBase);
rc += hexFormatArrayHelper(dv.VI64, 2); rc += QLatin1String(" long long: ");
return rc; rc += formatArrayHelper(dv.VI64, 2, integerBase);
} return rc;
}
} }
*type = QString::fromLatin1("Unknown type #%1:").arg(dv.Type); if (qType)
return hexFormatArrayHelper(dv.RawBytes, 24); *qType = QString::fromLatin1("Unknown type #%1:").arg(dv.Type);
return formatArrayHelper(dv.RawBytes, 24, integerBase);
} }
// - Watch model functions // - Watch model functions
@@ -613,5 +639,5 @@ bool CdbSymbolGroupContext::completeModel(CdbSymbolGroupContext *sg,
return true; return true;
} }
} } // namespace Internal
} } // namespace Debugger

View File

@@ -41,7 +41,7 @@
#include <QtCore/QMap> #include <QtCore/QMap>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class WatchData; class WatchData;
class WatchHandler; class WatchHandler;
@@ -92,7 +92,7 @@ public:
inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; } inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; }
// Helper to convert a DEBUG_VALUE structure to a string representation // Helper to convert a DEBUG_VALUE structure to a string representation
static QString debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl, QString *type); static QString debugValueToString(const DEBUG_VALUE &dv, IDebugControl4 *ctl, QString *type = 0, int integerBase = 10);
// format an array of unsigned longs as "0x323, 0x2322, ..." // format an array of unsigned longs as "0x323, 0x2322, ..."
static QString hexFormatArray(const unsigned short *array, int size); static QString hexFormatArray(const unsigned short *array, int size);
@@ -145,6 +145,7 @@ bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterato
return true; return true;
} }
} } // namespace Internal
} } // namespace Debugger
#endif // CDBSYMBOLGROUPCONTEXT_H #endif // CDBSYMBOLGROUPCONTEXT_H

View File

@@ -54,7 +54,7 @@ namespace Internal {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
DebuggerSettings::DebuggerSettings(QObject *parent) DebuggerSettings::DebuggerSettings(QObject *parent)
: QObject(parent) : QObject(parent), m_registerFormatGroup(0)
{} {}
DebuggerSettings::~DebuggerSettings() DebuggerSettings::~DebuggerSettings()
@@ -74,25 +74,25 @@ void DebuggerSettings::readSettings(QSettings *settings)
item->readSettings(settings); item->readSettings(settings);
} }
void DebuggerSettings::writeSettings(QSettings *settings) void DebuggerSettings::writeSettings(QSettings *settings) const
{ {
foreach (SavedAction *item, m_items) foreach (SavedAction *item, m_items)
item->writeSettings(settings); item->writeSettings(settings);
} }
SavedAction *DebuggerSettings::item(int code) SavedAction *DebuggerSettings::item(int code) const
{ {
QTC_ASSERT(m_items.value(code, 0), return 0); QTC_ASSERT(m_items.value(code, 0), return 0);
return m_items.value(code, 0); return m_items.value(code, 0);
} }
QString DebuggerSettings::dump() QString DebuggerSettings::dump() const
{ {
QString out; QString out;
QTextStream ts(&out); QTextStream ts(&out);
ts << "Debugger settings: "; ts << "Debugger settings: ";
foreach (SavedAction *item, m_items) foreach (SavedAction *item, m_items)
ts << "\n" << item->value().toString(); ts << '\n' << item->value().toString();
return out; return out;
} }
@@ -153,27 +153,27 @@ DebuggerSettings *DebuggerSettings::instance()
// //
// DebuggingHelper // DebuggingHelper
// const QString debugModeGroup = QLatin1String("DebugMode");
item = new SavedAction(instance); item = new SavedAction(instance);
instance->insertItem(UseDebuggingHelpers, item); instance->insertItem(UseDebuggingHelpers, item);
item->setDefaultValue(true); item->setDefaultValue(true);
item->setSettingsKey("DebugMode", "UseDebuggingHelper"); item->setSettingsKey(debugModeGroup, QLatin1String("UseDebuggingHelper"));
item->setText(tr("Use Debugging Helper")); item->setText(tr("Use Debugging Helper"));
item->setCheckable(true); item->setCheckable(true);
item->setDefaultValue(true); item->setDefaultValue(true);
item = new SavedAction(instance); item = new SavedAction(instance);
instance->insertItem(UseCustomDebuggingHelperLocation, item); instance->insertItem(UseCustomDebuggingHelperLocation, item);
item->setSettingsKey("DebugMode", "CustomDebuggingHelperLocation"); item->setSettingsKey(debugModeGroup, QLatin1String("CustomDebuggingHelperLocation"));
item->setCheckable(true); item->setCheckable(true);
item = new SavedAction(instance); item = new SavedAction(instance);
instance->insertItem(CustomDebuggingHelperLocation, item); instance->insertItem(CustomDebuggingHelperLocation, item);
item->setSettingsKey("DebugMode", "CustomDebuggingHelperLocation"); item->setSettingsKey(debugModeGroup, QLatin1String("CustomDebuggingHelperLocation"));
item = new SavedAction(instance); item = new SavedAction(instance);
instance->insertItem(DebugDebuggingHelpers, item); instance->insertItem(DebugDebuggingHelpers, item);
item->setSettingsKey("DebugMode", "DebugDebuggingHelpers"); item->setSettingsKey(debugModeGroup, QLatin1String("DebugDebuggingHelpers"));
item->setText(tr("Debug debugging helper")); item->setText(tr("Debug debugging helper"));
item->setCheckable(true); item->setCheckable(true);
@@ -193,115 +193,120 @@ DebuggerSettings *DebuggerSettings::instance()
// Registers // Registers
// //
QActionGroup *registerFormatGroup = new QActionGroup(instance); instance->m_registerFormatGroup = new QActionGroup(instance);
registerFormatGroup->setExclusive(true); instance->m_registerFormatGroup->setExclusive(true);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setText(tr("Hexadecimal")); item->setText(tr("Hexadecimal"));
item->setCheckable(true); item->setCheckable(true);
item->setSettingsKey("DebugMode", "FormatHexadecimal"); item->setSettingsKey(debugModeGroup, QLatin1String("FormatHexadecimal"));
item->setChecked(true); item->setChecked(true);
item->setData(FormatHexadecimal);
instance->insertItem(FormatHexadecimal, item); instance->insertItem(FormatHexadecimal, item);
registerFormatGroup->addAction(item); instance->m_registerFormatGroup->addAction(item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setText(tr("Decimal")); item->setText(tr("Decimal"));
item->setCheckable(true); item->setCheckable(true);
item->setSettingsKey("DebugMode", "FormatDecimal"); item->setSettingsKey(debugModeGroup, QLatin1String("FormatDecimal"));
item->setData(FormatDecimal);
instance->insertItem(FormatDecimal, item); instance->insertItem(FormatDecimal, item);
registerFormatGroup->addAction(item); instance->m_registerFormatGroup->addAction(item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setText(tr("Octal")); item->setText(tr("Octal"));
item->setCheckable(true); item->setCheckable(true);
item->setSettingsKey("DebugMode", "FormatOctal"); item->setSettingsKey(debugModeGroup, QLatin1String("FormatOctal"));
item->setData(FormatOctal);
instance->insertItem(FormatOctal, item); instance->insertItem(FormatOctal, item);
registerFormatGroup->addAction(item); instance->m_registerFormatGroup->addAction(item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setText(tr("Binary")); item->setText(tr("Binary"));
item->setCheckable(true); item->setCheckable(true);
item->setSettingsKey("DebugMode", "FormatBinary"); item->setSettingsKey(debugModeGroup, QLatin1String("FormatBinary"));
item->setData(FormatBinary);
instance->insertItem(FormatBinary, item); instance->insertItem(FormatBinary, item);
registerFormatGroup->addAction(item); instance->m_registerFormatGroup->addAction(item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setText(tr("Raw")); item->setText(tr("Raw"));
item->setCheckable(true); item->setCheckable(true);
item->setSettingsKey("DebugMode", "FormatRaw"); item->setSettingsKey(debugModeGroup, QLatin1String("FormatRaw"));
instance->insertItem(FormatRaw, item); instance->insertItem(FormatRaw, item);
registerFormatGroup->addAction(item); item->setData(FormatRaw);
instance->m_registerFormatGroup->addAction(item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setText(tr("Natural")); item->setText(tr("Natural"));
item->setCheckable(true); item->setCheckable(true);
item->setSettingsKey("DebugMode", "FormatNatural"); item->setSettingsKey(debugModeGroup, QLatin1String("FormatNatural"));
item->setData(FormatNatural);
instance->insertItem(FormatNatural, item); instance->insertItem(FormatNatural, item);
registerFormatGroup->addAction(item); instance->m_registerFormatGroup->addAction(item);
// //
// Settings // Settings
// //
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "Location"); item->setSettingsKey(debugModeGroup, QLatin1String("Location"));
instance->insertItem(GdbLocation, item); instance->insertItem(GdbLocation, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "Environment"); item->setSettingsKey(debugModeGroup, QLatin1String("Environment"));
instance->insertItem(GdbEnvironment, item); instance->insertItem(GdbEnvironment, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "ScriptFile"); item->setSettingsKey(debugModeGroup, QLatin1String("ScriptFile"));
instance->insertItem(GdbScriptFile, item); instance->insertItem(GdbScriptFile, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "AutoQuit"); item->setSettingsKey(debugModeGroup, QLatin1String("AutoQuit"));
item->setText(tr("Automatically quit debugger")); item->setText(tr("Automatically quit debugger"));
item->setCheckable(true); item->setCheckable(true);
instance->insertItem(AutoQuit, item); instance->insertItem(AutoQuit, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "UseToolTips"); item->setSettingsKey(debugModeGroup, QLatin1String("UseToolTips"));
item->setText(tr("Use tooltips when debugging")); item->setText(tr("Use tooltips when debugging"));
item->setCheckable(true); item->setCheckable(true);
instance->insertItem(UseToolTips, item); instance->insertItem(UseToolTips, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setDefaultValue("xterm"); item->setDefaultValue(QLatin1String("xterm"));
item->setSettingsKey("DebugMode", "Terminal"); item->setSettingsKey(debugModeGroup, QLatin1String("Terminal"));
instance->insertItem(TerminalApplication, item); instance->insertItem(TerminalApplication, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "ListSourceFiles"); item->setSettingsKey(debugModeGroup, QLatin1String("ListSourceFiles"));
item->setText(tr("List source files")); item->setText(tr("List source files"));
item->setCheckable(true); item->setCheckable(true);
instance->insertItem(ListSourceFiles, item); instance->insertItem(ListSourceFiles, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "SkipKnownFrames"); item->setSettingsKey(debugModeGroup, QLatin1String("SkipKnownFrames"));
item->setText(tr("Skip known frames")); item->setText(tr("Skip known frames"));
item->setCheckable(true); item->setCheckable(true);
instance->insertItem(SkipKnownFrames, item); instance->insertItem(SkipKnownFrames, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "AllPluginBreakpoints"); item->setSettingsKey(debugModeGroup, QLatin1String("AllPluginBreakpoints"));
instance->insertItem(AllPluginBreakpoints, item); instance->insertItem(AllPluginBreakpoints, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "SelectedPluginBreakpoints"); item->setSettingsKey(debugModeGroup, QLatin1String("SelectedPluginBreakpoints"));
instance->insertItem(SelectedPluginBreakpoints, item); instance->insertItem(SelectedPluginBreakpoints, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "NoPluginBreakpoints"); item->setSettingsKey(debugModeGroup, QLatin1String("NoPluginBreakpoints"));
instance->insertItem(NoPluginBreakpoints, item); instance->insertItem(NoPluginBreakpoints, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "SelectedPluginBreakpointsPattern"); item->setSettingsKey(debugModeGroup, QLatin1String("SelectedPluginBreakpointsPattern"));
instance->insertItem(SelectedPluginBreakpointsPattern, item); instance->insertItem(SelectedPluginBreakpointsPattern, item);
item = new SavedAction(instance); item = new SavedAction(instance);
item->setSettingsKey("DebugMode", "MaximalStackDepth"); item->setSettingsKey(debugModeGroup, QLatin1String("MaximalStackDepth"));
item->setDefaultValue(20); item->setDefaultValue(20);
instance->insertItem(MaximalStackDepth, item); instance->insertItem(MaximalStackDepth, item);
@@ -316,6 +321,11 @@ DebuggerSettings *DebuggerSettings::instance()
return instance; return instance;
} }
int DebuggerSettings::checkedRegisterFormatAction() const
{
return m_registerFormatGroup->checkedAction()->data().toInt();
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// //
// DebuggerActions // DebuggerActions
@@ -327,6 +337,11 @@ SavedAction *theDebuggerAction(int code)
return DebuggerSettings::instance()->item(code); return DebuggerSettings::instance()->item(code);
} }
int checkedRegisterFormatAction()
{
return DebuggerSettings::instance()->checkedRegisterFormatAction();
}
bool theDebuggerBoolSetting(int code) bool theDebuggerBoolSetting(int code)
{ {
return DebuggerSettings::instance()->item(code)->value().toBool(); return DebuggerSettings::instance()->item(code)->value().toBool();

View File

@@ -34,6 +34,9 @@
#include <utils/savedaction.h> #include <utils/savedaction.h>
QT_BEGIN_NAMESPACE
class QActionGroup;
QT_END_NAMESPACE
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -46,18 +49,22 @@ public:
~DebuggerSettings(); ~DebuggerSettings();
void insertItem(int code, Core::Utils::SavedAction *item); void insertItem(int code, Core::Utils::SavedAction *item);
Core::Utils::SavedAction *item(int code); Core::Utils::SavedAction *item(int code) const;
QString dump(); QString dump() const;
static DebuggerSettings *instance(); static DebuggerSettings *instance();
// Return one of FormatHexadecimal, FormatDecimal,...
int checkedRegisterFormatAction() const;
public slots: public slots:
void readSettings(QSettings *settings); void readSettings(QSettings *settings);
void writeSettings(QSettings *settings); void writeSettings(QSettings *settings) const;
private: private:
QHash<int, Core::Utils::SavedAction *> m_items; QHash<int, Core::Utils::SavedAction *> m_items;
QActionGroup *m_registerFormatGroup;
}; };
@@ -125,7 +132,10 @@ enum DebuggerActionCode
// singleton access // singleton access
Core::Utils::SavedAction *theDebuggerAction(int code); Core::Utils::SavedAction *theDebuggerAction(int code);
// convienience // Return one of FormatHexadecimal, FormatDecimal,...
int checkedRegisterFormatAction();
// convenience
bool theDebuggerBoolSetting(int code); bool theDebuggerBoolSetting(int code);
QString theDebuggerStringSetting(int code); QString theDebuggerStringSetting(int code);

View File

@@ -175,7 +175,7 @@ void DebuggerManager::init()
m_statusLabel = new QLabel; m_statusLabel = new QLabel;
m_breakWindow = new BreakWindow; m_breakWindow = new BreakWindow;
m_disassemblerWindow = new DisassemblerWindow; m_disassemblerWindow = new DisassemblerWindow;
m_modulesWindow = new ModulesWindow; m_modulesWindow = new ModulesWindow(this);
m_outputWindow = new DebuggerOutputWindow; m_outputWindow = new DebuggerOutputWindow;
m_registerWindow = new RegisterWindow; m_registerWindow = new RegisterWindow;
m_stackWindow = new StackWindow; m_stackWindow = new StackWindow;
@@ -213,6 +213,8 @@ void DebuggerManager::init()
QAbstractItemView *disassemblerView = QAbstractItemView *disassemblerView =
qobject_cast<QAbstractItemView *>(m_disassemblerWindow); qobject_cast<QAbstractItemView *>(m_disassemblerWindow);
disassemblerView->setModel(m_disassemblerHandler->model()); disassemblerView->setModel(m_disassemblerHandler->model());
connect(m_disassemblerWindow, SIGNAL(reloadDisassemblerRequested()),
this, SLOT(reloadDisassembler()));
// Breakpoints // Breakpoints
m_breakHandler = new BreakHandler; m_breakHandler = new BreakHandler;
@@ -996,6 +998,12 @@ void DebuggerManager::loadSymbols(const QString &module)
m_engine->loadSymbols(module); m_engine->loadSymbols(module);
} }
QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
{
QTC_ASSERT(m_engine, return QList<Symbol>());
return m_engine->moduleSymbols(moduleName);
}
void DebuggerManager::stepExec() void DebuggerManager::stepExec()
{ {
QTC_ASSERT(m_engine, return); QTC_ASSERT(m_engine, return);

View File

@@ -65,7 +65,7 @@ class WatchHandler;
class SourceFilesWindow; class SourceFilesWindow;
class WatchData; class WatchData;
class BreakpointData; class BreakpointData;
class Symbol;
// Note: the Debugger process itself is referred to as 'Debugger', // Note: the Debugger process itself is referred to as 'Debugger',
// whereas the debugged process is referred to as 'Inferior' or 'Debuggee'. // whereas the debugged process is referred to as 'Inferior' or 'Debuggee'.
@@ -309,6 +309,8 @@ public:
int status() const { return m_status; } int status() const { return m_status; }
DebuggerStartMode startMode() const { return m_startMode; } DebuggerStartMode startMode() const { return m_startMode; }
QList<Symbol> moduleSymbols(const QString &moduleName);
signals: signals:
void debuggingFinished(); void debuggingFinished();
void inferiorPidChanged(qint64 pid); void inferiorPidChanged(qint64 pid);

View File

@@ -650,6 +650,19 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
connect(resetToSimpleAction, SIGNAL(triggered()), connect(resetToSimpleAction, SIGNAL(triggered()),
m_manager, SLOT(setSimpleDockWidgetArrangement())); m_manager, SLOT(setSimpleDockWidgetArrangement()));
connect(theDebuggerAction(FormatHexadecimal), SIGNAL(triggered()),
m_manager, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatDecimal), SIGNAL(triggered()),
m_manager, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatOctal), SIGNAL(triggered()),
m_manager, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatBinary), SIGNAL(triggered()),
m_manager, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatRaw), SIGNAL(triggered()),
m_manager, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatNatural), SIGNAL(triggered()),
m_manager, SLOT(reloadRegisters()));
// FIXME: // FIXME:
m_generalOptionPage = new GdbOptionPage; m_generalOptionPage = new GdbOptionPage;
addObject(m_generalOptionPage); addObject(m_generalOptionPage);

View File

@@ -39,6 +39,14 @@
using namespace Debugger; using namespace Debugger;
using namespace Debugger::Internal; using namespace Debugger::Internal;
void DisassemblerLine::clear()
{
address.clear();
symbol.clear();
addressDisplay.clear();
symbolDisplay.clear();
mnemonic.clear();
}
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// //

View File

@@ -41,6 +41,8 @@ namespace Internal {
class DisassemblerLine class DisassemblerLine
{ {
public: public:
void clear();
QString address; QString address;
QString symbol; QString symbol;
QString addressDisplay; QString addressDisplay;

View File

@@ -221,19 +221,6 @@ void GdbEngine::initializeConnections()
connect(theDebuggerAction(RecheckDebuggingHelpers), SIGNAL(triggered()), connect(theDebuggerAction(RecheckDebuggingHelpers), SIGNAL(triggered()),
this, SLOT(recheckDebuggingHelperAvailability())); this, SLOT(recheckDebuggingHelperAvailability()));
connect(theDebuggerAction(FormatHexadecimal), SIGNAL(triggered()),
this, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatDecimal), SIGNAL(triggered()),
this, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatOctal), SIGNAL(triggered()),
this, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatBinary), SIGNAL(triggered()),
this, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatRaw), SIGNAL(triggered()),
this, SLOT(reloadRegisters()));
connect(theDebuggerAction(FormatNatural), SIGNAL(triggered()),
this, SLOT(reloadRegisters()));
connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()), connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()),
this, SLOT(reloadFullStack())); this, SLOT(reloadFullStack()));
connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()), connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()),
@@ -2402,6 +2389,40 @@ void GdbEngine::loadAllSymbols()
reloadModules(); reloadModules();
} }
QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
{
QList<Symbol> rc;
bool success = false;
QString errorMessage;
do {
const QString nmBinary = QLatin1String("nm");
QProcess proc;
proc.start(nmBinary, QStringList() << QLatin1String("-D") << moduleName);
if (!proc.waitForFinished()) {
errorMessage = tr("Unable to run '%1': %2").arg(nmBinary, proc.errorString());
break;
}
const QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
const QRegExp re(QLatin1String("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)"));
Q_ASSERT(re.isValid());
foreach (const QString &line, contents.split(QLatin1Char('\n'))) {
if (re.indexIn(line) != -1) {
Symbol symbol;
symbol.address = re.cap(1);
symbol.state = re.cap(2);
symbol.name = re.cap(3);
rc.push_back(symbol);
} else {
qWarning("moduleSymbols: unhandled: %s", qPrintable(line));
}
}
success = true;
} while (false);
if (!success)
qWarning("moduleSymbols: %s\n", qPrintable(errorMessage));
return rc;
}
void GdbEngine::reloadModules() void GdbEngine::reloadModules()
{ {
sendCommand("info shared", ModulesList, QVariant()); sendCommand("info shared", ModulesList, QVariant());
@@ -2619,22 +2640,28 @@ void GdbEngine::handleStackListThreads(const GdbResultRecord &record, int id)
// //
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
static inline char registerFormatChar()
{
switch(checkedRegisterFormatAction()) {
case FormatHexadecimal:
return 'x';
case FormatDecimal:
return 'd';
case FormatOctal:
return 'o';
case FormatBinary:
return 't';
case FormatRaw:
return 'r';
default:
break;
}
return 'N';
}
void GdbEngine::reloadRegisters() void GdbEngine::reloadRegisters()
{ {
QString format; sendCommand(QLatin1String("-data-list-register-values ") + QLatin1Char(registerFormatChar()), RegisterListValues);
if (theDebuggerAction(FormatHexadecimal)->isChecked())
format = "x";
else if (theDebuggerAction(FormatDecimal)->isChecked())
format = "d";
else if (theDebuggerAction(FormatOctal)->isChecked())
format = "o";
else if (theDebuggerAction(FormatBinary)->isChecked())
format = "t";
else if (theDebuggerAction(FormatRaw)->isChecked())
format = "r";
else
format = "N";
sendCommand("-data-list-register-values " + format, RegisterListValues);
} }
void GdbEngine::handleRegisterListNames(const GdbResultRecord &record) void GdbEngine::handleRegisterListNames(const GdbResultRecord &record)

View File

@@ -129,6 +129,7 @@ private:
void loadSymbols(const QString &moduleName); void loadSymbols(const QString &moduleName);
void loadAllSymbols(); void loadAllSymbols();
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
Q_SLOT void setUseDebuggingHelpers(const QVariant &on); Q_SLOT void setUseDebuggingHelpers(const QVariant &on);

View File

@@ -31,6 +31,7 @@
#define DEBUGGER_IDEBUGGERENGINE_H #define DEBUGGER_IDEBUGGERENGINE_H
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QList>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QPoint; class QPoint;
@@ -40,6 +41,8 @@ QT_END_NAMESPACE
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class Symbol;
class IDebuggerEngine : public QObject class IDebuggerEngine : public QObject
{ {
public: public:
@@ -79,6 +82,7 @@ public:
virtual void reloadModules() = 0; virtual void reloadModules() = 0;
virtual void loadSymbols(const QString &moduleName) = 0; virtual void loadSymbols(const QString &moduleName) = 0;
virtual void loadAllSymbols() = 0; virtual void loadAllSymbols() = 0;
virtual QList<Symbol> moduleSymbols(const QString &moduleName) = 0;
virtual void reloadRegisters() = 0; virtual void reloadRegisters() = 0;

View File

@@ -51,6 +51,19 @@ enum ModulesModelRoles
LoadAllSymbolsRole LoadAllSymbolsRole
}; };
//////////////////////////////////////////////////////////////////
//
// Symbol
//
//////////////////////////////////////////////////////////////////
class Symbol
{
public:
QString address;
QString state;
QString name;
};
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// //

View File

@@ -29,6 +29,7 @@
#include "moduleswindow.h" #include "moduleswindow.h"
#include "moduleshandler.h" // for model roles #include "moduleshandler.h" // for model roles
#include "debuggermanager.h"
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QProcess> #include <QtCore/QProcess>
@@ -40,7 +41,7 @@
#include <QtGui/QResizeEvent> #include <QtGui/QResizeEvent>
#include <QtGui/QToolButton> #include <QtGui/QToolButton>
#include <QtGui/QTreeWidget> #include <QtGui/QTreeWidget>
#include <QtGui/QApplication>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// //
@@ -48,10 +49,14 @@
// //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
using Debugger::Internal::ModulesWindow; namespace Debugger {
namespace Internal {
ModulesWindow::ModulesWindow(QWidget *parent) ModulesWindow::ModulesWindow(DebuggerManager *debuggerManager,
: QTreeView(parent), m_alwaysResizeColumnsToContents(false) QWidget *parent) :
QTreeView(parent),
m_alwaysResizeColumnsToContents(false),
m_debuggerManager(debuggerManager)
{ {
setWindowTitle(tr("Modules")); setWindowTitle(tr("Modules"));
setSortingEnabled(true); setSortingEnabled(true);
@@ -88,9 +93,12 @@ void ModulesWindow::resizeEvent(QResizeEvent *event)
void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev) void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
{ {
QString name;
QModelIndex index = indexAt(ev->pos()); QModelIndex index = indexAt(ev->pos());
index = index.sibling(index.row(), 0); if (index.isValid())
QString name = model()->data(index).toString(); index = index.sibling(index.row(), 0);
if (index.isValid())
name = model()->data(index).toString();
QMenu menu; QMenu menu;
QAction *act0 = new QAction(tr("Update module list"), &menu); QAction *act0 = new QAction(tr("Update module list"), &menu);
@@ -116,9 +124,6 @@ void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
act5->setDisabled(name.isEmpty()); act5->setDisabled(name.isEmpty());
act6->setDisabled(name.isEmpty()); act6->setDisabled(name.isEmpty());
act7->setDisabled(name.isEmpty()); act7->setDisabled(name.isEmpty());
#ifndef Q_OS_LINUX
act7->setDisabled(true);
#endif
menu.addAction(act0); menu.addAction(act0);
menu.addAction(act4); menu.addAction(act4);
@@ -178,28 +183,26 @@ void ModulesWindow::showSymbols(const QString &name)
{ {
if (name.isEmpty()) if (name.isEmpty())
return; return;
QProcess proc; QApplication::setOverrideCursor(Qt::WaitCursor);
proc.start("nm", QStringList() << "-D" << name); const QList<Symbol> symbols = m_debuggerManager->moduleSymbols(name);
proc.waitForFinished(); QApplication::restoreOverrideCursor();
if (symbols.empty())
return;
QTreeWidget *w = new QTreeWidget; QTreeWidget *w = new QTreeWidget;
w->setColumnCount(3); w->setColumnCount(3);
w->setRootIsDecorated(false); w->setRootIsDecorated(false);
w->setAlternatingRowColors(true); w->setAlternatingRowColors(true);
//w->header()->hide();
w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol")); w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
w->setWindowTitle(tr("Symbols in \"%1\"").arg(name)); w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput()); foreach (const Symbol &s, symbols) {
QRegExp re("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)"); QTreeWidgetItem *it = new QTreeWidgetItem;
foreach (QString line, contents.split('\n')) { it->setData(0, Qt::DisplayRole, s.address);
if (re.indexIn(line) != -1) { it->setData(1, Qt::DisplayRole, s.state);
QTreeWidgetItem *it = new QTreeWidgetItem; it->setData(2, Qt::DisplayRole, s.name);
it->setData(0, Qt::DisplayRole, re.cap(1)); w->addTopLevelItem(it);
it->setData(1, Qt::DisplayRole, re.cap(2));
it->setData(2, Qt::DisplayRole, re.cap(3));
w->addTopLevelItem(it);
} else {
qDebug() << "UNHANDLED LINE" << line;
}
} }
emit newDockRequested(w); emit newDockRequested(w);
} }
}
}

View File

@@ -35,12 +35,14 @@
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class DebuggerManager;
class ModulesWindow : public QTreeView class ModulesWindow : public QTreeView
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ModulesWindow(QWidget *parent = 0); explicit ModulesWindow(DebuggerManager *debuggerManager, QWidget *parent = 0);
signals: signals:
void reloadModulesRequested(); void reloadModulesRequested();
@@ -62,6 +64,7 @@ private:
void setModel(QAbstractItemModel *model); void setModel(QAbstractItemModel *model);
bool m_alwaysResizeColumnsToContents; bool m_alwaysResizeColumnsToContents;
DebuggerManager *m_debuggerManager;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -38,6 +38,7 @@
#include "registerhandler.h" #include "registerhandler.h"
#include "stackhandler.h" #include "stackhandler.h"
#include "watchhandler.h" #include "watchhandler.h"
#include "moduleshandler.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -405,6 +406,10 @@ void ScriptEngine::reloadModules()
{ {
} }
QList<Symbol> ScriptEngine::moduleSymbols(const QString & /*moduleName*/)
{
return QList<Symbol>();
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@@ -102,6 +102,7 @@ private:
void loadSymbols(const QString &moduleName); void loadSymbols(const QString &moduleName);
void loadAllSymbols(); void loadAllSymbols();
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
void reloadDisassembler(); void reloadDisassembler();
void reloadModules(); void reloadModules();
void reloadRegisters() {} void reloadRegisters() {}

View File

@@ -96,15 +96,16 @@ namespace Internal {
// //
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
#define StartOfLine QTextCursor::StartOfLine #define StartOfLine QTextCursor::StartOfLine
#define EndOfLine QTextCursor::EndOfLine #define EndOfLine QTextCursor::EndOfLine
#define MoveAnchor QTextCursor::MoveAnchor #define MoveAnchor QTextCursor::MoveAnchor
#define KeepAnchor QTextCursor::KeepAnchor #define KeepAnchor QTextCursor::KeepAnchor
#define Up QTextCursor::Up #define Up QTextCursor::Up
#define Down QTextCursor::Down #define Down QTextCursor::Down
#define Right QTextCursor::Right #define Right QTextCursor::Right
#define Left QTextCursor::Left #define Left QTextCursor::Left
#define EndOfDocument QTextCursor::End #define EndOfDocument QTextCursor::End
#define StartOfDocument QTextCursor::Start
#define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s) #define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s)
@@ -274,8 +275,6 @@ public:
void moveToWordBoundary(bool simple, bool forward); void moveToWordBoundary(bool simple, bool forward);
// to reduce line noise // to reduce line noise
typedef QTextCursor::MoveOperation MoveOperation;
typedef QTextCursor::MoveMode MoveMode;
void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); } void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); }
void moveToStartOfLine() { m_tc.movePosition(StartOfLine, MoveAnchor); } void moveToStartOfLine() { m_tc.movePosition(StartOfLine, MoveAnchor); }
void moveToEndOfLine(); void moveToEndOfLine();
@@ -1701,6 +1700,7 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
static QRegExp reNormal("^norm(al)?( (.*))?$"); static QRegExp reNormal("^norm(al)?( (.*))?$");
static QRegExp reSet("^set?( (.*))?$"); static QRegExp reSet("^set?( (.*))?$");
static QRegExp reWrite("^w!?( (.*))?$"); static QRegExp reWrite("^w!?( (.*))?$");
static QRegExp reSubstitute("^s(.)(.*)\\1(.*)\\1([gi]*)");
if (cmd.isEmpty()) { if (cmd.isEmpty()) {
setPosition(firstPositionInLine(beginLine)); setPosition(firstPositionInLine(beginLine));
@@ -1805,6 +1805,47 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
enterCommandMode(); enterCommandMode();
//qDebug() << "REPLAY: " << reNormal.cap(3); //qDebug() << "REPLAY: " << reNormal.cap(3);
replay(reNormal.cap(3), 1); replay(reNormal.cap(3), 1);
} else if (reSubstitute.indexIn(cmd) != -1) { // :substitute
QString needle = reSubstitute.cap(2);
const QString replacement = reSubstitute.cap(3);
QString flags = reSubstitute.cap(4);
const bool startOfLineOnly = needle.startsWith('^');
if (startOfLineOnly)
needle.remove(0, 1);
needle.replace('$', '\n');
needle.replace("\\\n", "\\$");
QRegExp pattern(needle);
if (flags.contains('i'))
pattern.setCaseSensitivity(Qt::CaseInsensitive);
const bool global = flags.contains('g');
m_tc.beginEditBlock();
for (int line = beginLine; line <= endLine; ++line) {
const int start = firstPositionInLine(line);
const int end = lastPositionInLine(line);
for (int position = start; position <= end && position >= start; ) {
position = pattern.indexIn(m_tc.document()->toPlainText(), position);
if (startOfLineOnly && position != start)
break;
if (position != -1) {
m_tc.setPosition(position);
m_tc.movePosition(QTextCursor::NextCharacter,
KeepAnchor, pattern.matchedLength());
QString text = m_tc.selectedText();
if (text.endsWith(ParagraphSeparator)) {
text = replacement + "\n";
} else {
text.replace(ParagraphSeparator, "\n");
text.replace(pattern, replacement);
}
m_tc.removeSelectedText();
m_tc.insertText(text);
}
if (!global)
break;
}
}
m_tc.endEditBlock();
enterCommandMode();
} else if (reSet.indexIn(cmd) != -1) { // :set } else if (reSet.indexIn(cmd) != -1) { // :set
showBlackMessage(QString()); showBlackMessage(QString());
QString arg = reSet.cap(2); QString arg = reSet.cap(2);
@@ -1927,7 +1968,7 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
if (!needle0.isEmpty()) { if (!needle0.isEmpty()) {
QTextCursor tc = m_tc; QTextCursor tc = m_tc;
tc.movePosition(QTextCursor::Start, MoveAnchor); tc.movePosition(StartOfDocument, MoveAnchor);
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively; QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
QString needle = needle0; QString needle = needle0;
@@ -2330,11 +2371,13 @@ void FakeVimHandler::Private::recordJump()
UNDO_DEBUG("jumps: " << m_jumpListUndo); UNDO_DEBUG("jumps: " << m_jumpListUndo);
} }
struct UndoBreaker : public QAbstractUndoItem class UndoBreaker : public QAbstractUndoItem
{ {
public:
UndoBreaker(FakeVimHandler::Private *doc) : m_doc(doc) {} UndoBreaker(FakeVimHandler::Private *doc) : m_doc(doc) {}
void undo() { m_doc->m_needMoreUndo = true; } void undo() { m_doc->m_needMoreUndo = true; }
void redo() { m_doc->m_needMoreUndo = true; } void redo() { m_doc->m_needMoreUndo = true; }
private:
FakeVimHandler::Private *m_doc; FakeVimHandler::Private *m_doc;
}; };