From 6d4d19dfa88e02e937967b91ab3f60bac1f41b3f Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 9 Apr 2009 16:51:13 +0200 Subject: [PATCH 01/11] Handle various CDB output windows. Add modules, threads and register view. Refactor register format code. --- src/plugins/debugger/cdb/cdb.pri | 8 +- src/plugins/debugger/cdb/cdbassembler.cpp | 83 ++++++++++++++++ src/plugins/debugger/cdb/cdbassembler.h | 54 +++++++++++ src/plugins/debugger/cdb/cdbdebugengine.cpp | 97 +++++++++++++++---- src/plugins/debugger/cdb/cdbdebugengine_p.h | 6 +- .../debugger/cdb/cdbdebugeventcallback.cpp | 24 +++-- src/plugins/debugger/cdb/cdbdebugoutput.cpp | 39 +++++++- src/plugins/debugger/cdb/cdbdebugoutput.h | 9 +- src/plugins/debugger/cdb/cdbmodules.cpp | 81 ++++++++++++++++ src/plugins/debugger/cdb/cdbmodules.h | 49 ++++++++++ .../debugger/cdb/cdbsymbolgroupcontext.cpp | 90 +++++++++++------ .../debugger/cdb/cdbsymbolgroupcontext.h | 2 +- src/plugins/debugger/debuggeractions.cpp | 93 ++++++++++-------- src/plugins/debugger/debuggeractions.h | 18 +++- src/plugins/debugger/debuggerplugin.cpp | 13 +++ src/plugins/debugger/gdbengine.cpp | 47 ++++----- 16 files changed, 572 insertions(+), 141 deletions(-) create mode 100644 src/plugins/debugger/cdb/cdbassembler.cpp create mode 100644 src/plugins/debugger/cdb/cdbassembler.h create mode 100644 src/plugins/debugger/cdb/cdbmodules.cpp create mode 100644 src/plugins/debugger/cdb/cdbmodules.h diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri index a9e9a5cddfa..6096f2f3e8d 100644 --- a/src/plugins/debugger/cdb/cdb.pri +++ b/src/plugins/debugger/cdb/cdb.pri @@ -25,7 +25,9 @@ HEADERS += \ $$PWD/cdbdebugoutput.h \ $$PWD/cdbsymbolgroupcontext.h \ $$PWD/cdbstacktracecontext.h \ - $$PWD/cdbbreakpoint.h + $$PWD/cdbbreakpoint.h \ + $$PWD/cdbmodules.h \ + $$PWD/cdbassembler.h SOURCES += \ $$PWD/cdbdebugengine.cpp \ @@ -33,7 +35,9 @@ SOURCES += \ $$PWD/cdbdebugoutput.cpp \ $$PWD/cdbsymbolgroupcontext.cpp \ $$PWD/cdbstacktracecontext.cpp \ - $$PWD/cdbbreakpoint.cpp + $$PWD/cdbbreakpoint.cpp \ + $$PWD/cdbmodules.cpp \ + $$PWD/cdbassembler.cpp } else { message("Debugging Tools for Windows could not be found in $$CDB_PATH") diff --git a/src/plugins/debugger/cdb/cdbassembler.cpp b/src/plugins/debugger/cdb/cdbassembler.cpp new file mode 100644 index 00000000000..3d01d6d54ee --- /dev/null +++ b/src/plugins/debugger/cdb/cdbassembler.cpp @@ -0,0 +1,83 @@ +/************************************************************************** +** +** 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 "registerhandler.h" +#include "cdbdebugengine_p.h" +#include "cdbsymbolgroupcontext.h" + +#include + +namespace Debugger { +namespace Internal { + +bool getRegisters(IDebugControl4 *ctl, + IDebugRegisters2 *ireg, + QList *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 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; +} + +} +} diff --git a/src/plugins/debugger/cdb/cdbassembler.h b/src/plugins/debugger/cdb/cdbassembler.h new file mode 100644 index 00000000000..e2386797e04 --- /dev/null +++ b/src/plugins/debugger/cdb/cdbassembler.h @@ -0,0 +1,54 @@ +/************************************************************************** +** +** 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 +#include + +#include +#include + +namespace Debugger { +namespace Internal { + +// Utilities related to assembler code. +class Register; + +bool getRegisters(IDebugControl4 *ctl, + IDebugRegisters2 *ireg, + QList *registers, + QString *errorMessage, + int base = 10 /* 16 for hex, etc */); +} +} + + +#endif // CDBASSEMBLER_H diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index a85069cc0ef..bdb692af941 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -32,11 +32,16 @@ #include "cdbsymbolgroupcontext.h" #include "cdbstacktracecontext.h" #include "cdbbreakpoint.h" +#include "cdbmodules.h" +#include "cdbassembler.h" +#include "debuggeractions.h" #include "debuggermanager.h" #include "breakhandler.h" #include "stackhandler.h" #include "watchhandler.h" +#include "registerhandler.h" +#include "moduleshandler.h" #include "watchutils.h" #include @@ -308,6 +313,10 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) : 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(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))); } CdbDebugEngine::~CdbDebugEngine() @@ -344,8 +353,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() { + m_d->clearDisplay(); m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1); QString errorMessage; bool rc = false; @@ -1042,8 +1059,35 @@ void CdbDebugEngine::loadAllSymbols() qDebug() << Q_FUNC_INFO; } +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() { + const int intBase = registerFormatBase(); + if (debugCDB) + qDebug() << Q_FUNC_INFO << intBase; + QList registers; + QString errorMessage; + if (!getRegisters(m_d->m_pDebugControl, m_d->m_pDebugRegisters, ®isters, &errorMessage, intBase)) + qWarning("reloadRegisters() failed: %s\n", qPrintable(errorMessage)); + m_d->m_debuggerManagerAccess->registerHandler()->setRegisters(registers); } void CdbDebugEngine::timerEvent(QTimerEvent* te) @@ -1142,21 +1186,34 @@ void CdbDebugEnginePrivate::updateThreadList() ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler(); QList 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; - ULONG numberOfThreads; - hr = m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads); - const ULONG maxThreadIds = 256; - ULONG threadIds[maxThreadIds]; - 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); + th->setThreads(threads); + success = true; + } while (false); + if (!success) + qWarning("updateThreadList() failed: %s\n", qPrintable(errorMessage)); } void CdbDebugEnginePrivate::updateStackTrace() @@ -1166,6 +1223,7 @@ void CdbDebugEnginePrivate::updateStackTrace() // Create a new context clearForRun(); QString errorMessage; + m_engine->reloadRegisters(); m_currentStackTrace = CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects, m_pDebugSymbols, m_currentThreadId, &errorMessage); @@ -1191,11 +1249,14 @@ void CdbDebugEnginePrivate::updateStackTrace() } } -void CdbDebugEnginePrivate::handleDebugOutput(const char *szOutputString) + +void CdbDebugEnginePrivate::updateModules() { - if (debugCDB && strstr(szOutputString, "ModLoad:") == 0) - qDebug() << Q_FUNC_INFO << szOutputString; - m_debuggerManagerAccess->showApplicationOutput(QString::fromLocal8Bit(szOutputString)); + QList modules; + QString errorMessage; + if (!getModuleList(m_pDebugSymbols, &modules, &errorMessage)) + qWarning("updateModules() failed: %s\n", qPrintable(errorMessage)); + m_debuggerManagerAccess->modulesHandler()->setModules(modules); } void CdbDebugEnginePrivate::handleBreakpointEvent(PDEBUG_BREAKPOINT pBP) diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index 98e725cfbfd..665ea28b09e 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -79,14 +79,16 @@ struct CdbDebugEnginePrivate bool isDebuggeeRunning() const { return m_watchTimer != -1; } void handleDebugEvent(); - void updateThreadList(); + void updateThreadList(); void updateStackTrace(); bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage); - void handleDebugOutput(const char* szOutputString); + void updateModules(); + void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP); void cleanStackTrace(); void clearForRun(); CdbSymbolGroupContext *getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const; + void clearDisplay(); bool interruptInterferiorProcess(QString *errorMessage); diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp index 14325f8ed55..526902e2c3d 100644 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp +++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp @@ -76,8 +76,9 @@ STDMETHODIMP_(ULONG) CdbDebugEventCallback::Release(THIS) STDMETHODIMP CdbDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask) { - *mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS - //| DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD + *mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS + | DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_UNLOAD_MODULE + | DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD | DEBUG_EVENT_BREAKPOINT | DEBUG_EVENT_EXCEPTION ; @@ -125,13 +126,9 @@ STDMETHODIMP CdbDebugEventCallback::CreateThread( Q_UNUSED(Handle) Q_UNUSED(DataOffset) Q_UNUSED(StartOffset) - if (debugCDB) qDebug() << Q_FUNC_INFO; - //Debugger::ThreadInfo ti; - //ti.handle = Handle; - //ti.dataOffset = DataOffset; - //ti.startOffset = StartOffset; + m_pEngine->m_d->updateThreadList(); return S_OK; } @@ -142,7 +139,8 @@ STDMETHODIMP CdbDebugEventCallback::ExitThread( { if (debugCDB) qDebug() << Q_FUNC_INFO << ExitCode; - + // @TODO: It seems the terminated thread is still in the list... + m_pEngine->m_d->updateThreadList(); return S_OK; } @@ -211,14 +209,14 @@ STDMETHODIMP CdbDebugEventCallback::LoadModule( { Q_UNUSED(ImageFileHandle) Q_UNUSED(BaseOffset) - Q_UNUSED(ModuleSize) Q_UNUSED(ModuleName) + Q_UNUSED(ModuleSize) Q_UNUSED(ImageName) Q_UNUSED(CheckSum) Q_UNUSED(TimeDateStamp) - if (debugCDB) + if (debugCDB > 1) qDebug() << Q_FUNC_INFO << ModuleName; - + m_pEngine->m_d->updateModules(); return S_OK; } @@ -230,9 +228,9 @@ STDMETHODIMP CdbDebugEventCallback::UnloadModule( { Q_UNUSED(ImageBaseName) Q_UNUSED(BaseOffset) - if (debugCDB) + if (debugCDB > 1) qDebug() << Q_FUNC_INFO << ImageBaseName; - + m_pEngine->m_d->updateModules(); return S_OK; } diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.cpp b/src/plugins/debugger/cdb/cdbdebugoutput.cpp index 0bfa568fc70..f0df999d28b 100644 --- a/src/plugins/debugger/cdb/cdbdebugoutput.cpp +++ b/src/plugins/debugger/cdb/cdbdebugoutput.cpp @@ -76,14 +76,49 @@ STDMETHODIMP_(ULONG) CdbDebugOutput::Release(THIS) return 0; } +// Return a prefix for debugger messages +static QString prefix(ULONG mask) +{ + if (mask & (DEBUG_OUTPUT_DEBUGGEE|DEBUG_OUTPUT_DEBUGGEE_PROMPT|DEBUG_OUTPUT_DEBUGGEE_PROMPT)) { + static const QString p = QLatin1String("target:"); + return p; + } + 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; +} + STDMETHODIMP CdbDebugOutput::Output( THIS_ IN ULONG mask, IN PCSTR text ) { - UNREFERENCED_PARAMETER(mask); - m_pEngine->m_d->handleDebugOutput(text); + const QString msg = QString::fromLocal8Bit(text); + + if (debugCDB > 1) + qDebug() << Q_FUNC_INFO << "\n " << msg; + + if (mask & (DEBUG_OUTPUT_PROMPT|DEBUG_OUTPUT_DEBUGGEE_PROMPT)) { + emit debuggerInputPrompt(prefix(mask), msg); + } else { + emit debuggerOutput(prefix(mask), msg); + } return S_OK; } diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.h b/src/plugins/debugger/cdb/cdbdebugoutput.h index ea36fb6c42b..827d85bbb28 100644 --- a/src/plugins/debugger/cdb/cdbdebugoutput.h +++ b/src/plugins/debugger/cdb/cdbdebugoutput.h @@ -33,13 +33,16 @@ #include #include +#include + namespace Debugger { namespace Internal { class CdbDebugEngine; -class CdbDebugOutput : public IDebugOutputCallbacks +class CdbDebugOutput : public QObject, public IDebugOutputCallbacks { + Q_OBJECT public: explicit CdbDebugOutput(CdbDebugEngine* engine); @@ -63,6 +66,10 @@ public: IN PCSTR text ); +signals: + void debuggerOutput(const QString &prefix, const QString &message); + void debuggerInputPrompt(const QString &prefix, const QString &message); + private: CdbDebugEngine* m_pEngine; }; diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp new file mode 100644 index 00000000000..6e97800e843 --- /dev/null +++ b/src/plugins/debugger/cdb/cdbmodules.cpp @@ -0,0 +1,81 @@ +/************************************************************************** +** +** 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" + +namespace Debugger { +namespace Internal { + +bool getModuleList(IDebugSymbols3 *syms, QList *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 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; +} + +} +} diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h new file mode 100644 index 00000000000..3a959b7f575 --- /dev/null +++ b/src/plugins/debugger/cdb/cdbmodules.h @@ -0,0 +1,49 @@ +/************************************************************************** +** +** 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 +#include + +#include +#include + +namespace Debugger { +namespace Internal { + +class Module; + +bool getModuleList(IDebugSymbols3 *syms, QList *modules, QString *errorMessage); + +} +} + +#endif // CDBMODULES_H diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index e381a5aa86d..c4895df333e 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -403,45 +403,67 @@ bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &val // format an array of integers as "0x323, 0x2322, ..." template -static QString hexFormatArrayHelper(const Integer *array, int size) +static QString formatArrayHelper(const Integer *array, int size, int base = 10) { QString rc; const QString hexPrefix = QLatin1String("0x"); const QString separator= QLatin1String(", "); + const bool hex = base == 16; for (int i = 0; i < size; i++) { if (i) rc += separator; - rc += hexPrefix; - rc += QString::number(array[i], 16); + if (hex) + rc += hexPrefix; + rc += QString::number(array[i], base); } return rc; } 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 + 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) { case DEBUG_VALUE_INT8: - *type = QLatin1String("char"); - return QString::number(dv.I8); + if (qType) + *qType = QLatin1String("char"); + return formatInteger(dv.I8, integerBase); case DEBUG_VALUE_INT16: - *type = QLatin1String("short"); - return QString::number(static_cast(dv.I16)); + if (qType) + *qType = QLatin1String("short"); + return formatInteger(static_cast(dv.I16), integerBase); case DEBUG_VALUE_INT32: - *type = QLatin1String("long"); - return QString::number(static_cast(dv.I32)); + if (qType) + *qType = QLatin1String("long"); + return formatInteger(static_cast(dv.I32), integerBase); case DEBUG_VALUE_INT64: - *type = QLatin1String("long long"); - return QString::number(static_cast(dv.I64)); + if (qType) + *qType = QLatin1String("long long"); + return formatInteger(static_cast(dv.I64), integerBase); case DEBUG_VALUE_FLOAT32: - *type = QLatin1String("float"); + if (qType) + *qType = QLatin1String("float"); return QString::number(dv.F32); case DEBUG_VALUE_FLOAT64: - *type = QLatin1String("double"); + if (qType) + *qType = QLatin1String("double"); return QString::number(dv.F64); case DEBUG_VALUE_FLOAT80: case DEBUG_VALUE_FLOAT128: { // Convert to double @@ -449,28 +471,32 @@ QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, IDebugC double d = 0.0; if (SUCCEEDED(ctl->CoerceValue(const_cast(&dv), DEBUG_VALUE_FLOAT64, &doubleValue))) 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); } case DEBUG_VALUE_VECTOR64: { - *type = QLatin1String("64bit-vector"); - QString rc = QLatin1String("bytes: "); - rc += hexFormatArrayHelper(dv.VI8, 8); - rc += QLatin1String(" long: "); - rc += hexFormatArrayHelper(dv.VI32, 2); - return rc; - } + if (qType) + *qType = QLatin1String("64bit-vector"); + QString rc = QLatin1String("bytes: "); + rc += formatArrayHelper(dv.VI8, 8, integerBase); + rc += QLatin1String(" long: "); + rc += formatArrayHelper(dv.VI32, 2, integerBase); + return rc; + } case DEBUG_VALUE_VECTOR128: { - *type = QLatin1String("128bit-vector"); - QString rc = QLatin1String("bytes: "); - rc += hexFormatArrayHelper(dv.VI8, 16); - rc += QLatin1String(" long long: "); - rc += hexFormatArrayHelper(dv.VI64, 2); - return rc; - } + if (qType) + *qType = QLatin1String("128bit-vector"); + QString rc = QLatin1String("bytes: "); + rc += formatArrayHelper(dv.VI8, 16, integerBase); + rc += QLatin1String(" long long: "); + rc += formatArrayHelper(dv.VI64, 2, integerBase); + return rc; + } } - *type = QString::fromLatin1("Unknown type #%1:").arg(dv.Type); - return hexFormatArrayHelper(dv.RawBytes, 24); + if (qType) + *qType = QString::fromLatin1("Unknown type #%1:").arg(dv.Type); + return formatArrayHelper(dv.RawBytes, 24, integerBase); } // - Watch model functions diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index 46254ce4e04..cf4fa2a9839 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -92,7 +92,7 @@ public: inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; } // 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, ..." static QString hexFormatArray(const unsigned short *array, int size); diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index a2e2b6f0614..6ade9b34fde 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -54,7 +54,7 @@ namespace Internal { ////////////////////////////////////////////////////////////////////////// DebuggerSettings::DebuggerSettings(QObject *parent) - : QObject(parent) + : QObject(parent), m_registerFormatGroup(0) {} DebuggerSettings::~DebuggerSettings() @@ -74,25 +74,25 @@ void DebuggerSettings::readSettings(QSettings *settings) item->readSettings(settings); } -void DebuggerSettings::writeSettings(QSettings *settings) +void DebuggerSettings::writeSettings(QSettings *settings) const { foreach (SavedAction *item, m_items) item->writeSettings(settings); } -SavedAction *DebuggerSettings::item(int code) +SavedAction *DebuggerSettings::item(int code) const { QTC_ASSERT(m_items.value(code, 0), return 0); return m_items.value(code, 0); } -QString DebuggerSettings::dump() +QString DebuggerSettings::dump() const { QString out; QTextStream ts(&out); ts << "Debugger settings: "; foreach (SavedAction *item, m_items) - ts << "\n" << item->value().toString(); + ts << '\n' << item->value().toString(); return out; } @@ -153,27 +153,27 @@ DebuggerSettings *DebuggerSettings::instance() // // DebuggingHelper - // + const QString debugModeGroup = QLatin1String("DebugMode"); item = new SavedAction(instance); instance->insertItem(UseDebuggingHelpers, item); item->setDefaultValue(true); - item->setSettingsKey("DebugMode", "UseDebuggingHelper"); + item->setSettingsKey(debugModeGroup, QLatin1String("UseDebuggingHelper")); item->setText(tr("Use Debugging Helper")); item->setCheckable(true); item->setDefaultValue(true); item = new SavedAction(instance); instance->insertItem(UseCustomDebuggingHelperLocation, item); - item->setSettingsKey("DebugMode", "CustomDebuggingHelperLocation"); + item->setSettingsKey(debugModeGroup, QLatin1String("CustomDebuggingHelperLocation")); item->setCheckable(true); item = new SavedAction(instance); instance->insertItem(CustomDebuggingHelperLocation, item); - item->setSettingsKey("DebugMode", "CustomDebuggingHelperLocation"); + item->setSettingsKey(debugModeGroup, QLatin1String("CustomDebuggingHelperLocation")); item = new SavedAction(instance); instance->insertItem(DebugDebuggingHelpers, item); - item->setSettingsKey("DebugMode", "DebugDebuggingHelpers"); + item->setSettingsKey(debugModeGroup, QLatin1String("DebugDebuggingHelpers")); item->setText(tr("Debug debugging helper")); item->setCheckable(true); @@ -193,115 +193,120 @@ DebuggerSettings *DebuggerSettings::instance() // Registers // - QActionGroup *registerFormatGroup = new QActionGroup(instance); - registerFormatGroup->setExclusive(true); + instance->m_registerFormatGroup = new QActionGroup(instance); + instance->m_registerFormatGroup->setExclusive(true); item = new SavedAction(instance); item->setText(tr("Hexadecimal")); item->setCheckable(true); - item->setSettingsKey("DebugMode", "FormatHexadecimal"); + item->setSettingsKey(debugModeGroup, QLatin1String("FormatHexadecimal")); item->setChecked(true); + item->setData(FormatHexadecimal); instance->insertItem(FormatHexadecimal, item); - registerFormatGroup->addAction(item); + instance->m_registerFormatGroup->addAction(item); item = new SavedAction(instance); item->setText(tr("Decimal")); item->setCheckable(true); - item->setSettingsKey("DebugMode", "FormatDecimal"); + item->setSettingsKey(debugModeGroup, QLatin1String("FormatDecimal")); + item->setData(FormatDecimal); instance->insertItem(FormatDecimal, item); - registerFormatGroup->addAction(item); + instance->m_registerFormatGroup->addAction(item); item = new SavedAction(instance); item->setText(tr("Octal")); item->setCheckable(true); - item->setSettingsKey("DebugMode", "FormatOctal"); + item->setSettingsKey(debugModeGroup, QLatin1String("FormatOctal")); + item->setData(FormatOctal); instance->insertItem(FormatOctal, item); - registerFormatGroup->addAction(item); + instance->m_registerFormatGroup->addAction(item); item = new SavedAction(instance); item->setText(tr("Binary")); item->setCheckable(true); - item->setSettingsKey("DebugMode", "FormatBinary"); + item->setSettingsKey(debugModeGroup, QLatin1String("FormatBinary")); + item->setData(FormatBinary); instance->insertItem(FormatBinary, item); - registerFormatGroup->addAction(item); + instance->m_registerFormatGroup->addAction(item); item = new SavedAction(instance); item->setText(tr("Raw")); item->setCheckable(true); - item->setSettingsKey("DebugMode", "FormatRaw"); + item->setSettingsKey(debugModeGroup, QLatin1String("FormatRaw")); instance->insertItem(FormatRaw, item); - registerFormatGroup->addAction(item); + item->setData(FormatRaw); + instance->m_registerFormatGroup->addAction(item); item = new SavedAction(instance); item->setText(tr("Natural")); item->setCheckable(true); - item->setSettingsKey("DebugMode", "FormatNatural"); + item->setSettingsKey(debugModeGroup, QLatin1String("FormatNatural")); + item->setData(FormatNatural); instance->insertItem(FormatNatural, item); - registerFormatGroup->addAction(item); - + instance->m_registerFormatGroup->addAction(item); // // Settings // item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "Location"); + item->setSettingsKey(debugModeGroup, QLatin1String("Location")); instance->insertItem(GdbLocation, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "Environment"); + item->setSettingsKey(debugModeGroup, QLatin1String("Environment")); instance->insertItem(GdbEnvironment, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "ScriptFile"); + item->setSettingsKey(debugModeGroup, QLatin1String("ScriptFile")); instance->insertItem(GdbScriptFile, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "AutoQuit"); + item->setSettingsKey(debugModeGroup, QLatin1String("AutoQuit")); item->setText(tr("Automatically quit debugger")); item->setCheckable(true); instance->insertItem(AutoQuit, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "UseToolTips"); + item->setSettingsKey(debugModeGroup, QLatin1String("UseToolTips")); item->setText(tr("Use tooltips when debugging")); item->setCheckable(true); instance->insertItem(UseToolTips, item); item = new SavedAction(instance); - item->setDefaultValue("xterm"); - item->setSettingsKey("DebugMode", "Terminal"); + item->setDefaultValue(QLatin1String("xterm")); + item->setSettingsKey(debugModeGroup, QLatin1String("Terminal")); instance->insertItem(TerminalApplication, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "ListSourceFiles"); + item->setSettingsKey(debugModeGroup, QLatin1String("ListSourceFiles")); item->setText(tr("List source files")); item->setCheckable(true); instance->insertItem(ListSourceFiles, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "SkipKnownFrames"); + item->setSettingsKey(debugModeGroup, QLatin1String("SkipKnownFrames")); item->setText(tr("Skip known frames")); item->setCheckable(true); instance->insertItem(SkipKnownFrames, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "AllPluginBreakpoints"); + item->setSettingsKey(debugModeGroup, QLatin1String("AllPluginBreakpoints")); instance->insertItem(AllPluginBreakpoints, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "SelectedPluginBreakpoints"); + item->setSettingsKey(debugModeGroup, QLatin1String("SelectedPluginBreakpoints")); instance->insertItem(SelectedPluginBreakpoints, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "NoPluginBreakpoints"); + item->setSettingsKey(debugModeGroup, QLatin1String("NoPluginBreakpoints")); instance->insertItem(NoPluginBreakpoints, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "SelectedPluginBreakpointsPattern"); + item->setSettingsKey(debugModeGroup, QLatin1String("SelectedPluginBreakpointsPattern")); instance->insertItem(SelectedPluginBreakpointsPattern, item); item = new SavedAction(instance); - item->setSettingsKey("DebugMode", "MaximalStackDepth"); + item->setSettingsKey(debugModeGroup, QLatin1String("MaximalStackDepth")); item->setDefaultValue(20); instance->insertItem(MaximalStackDepth, item); @@ -316,6 +321,11 @@ DebuggerSettings *DebuggerSettings::instance() return instance; } +int DebuggerSettings::checkedRegisterFormatAction() const +{ + return m_registerFormatGroup->checkedAction()->data().toInt(); +} + ////////////////////////////////////////////////////////////////////////// // // DebuggerActions @@ -327,6 +337,11 @@ SavedAction *theDebuggerAction(int code) return DebuggerSettings::instance()->item(code); } +int checkedRegisterFormatAction() +{ + return DebuggerSettings::instance()->checkedRegisterFormatAction(); +} + bool theDebuggerBoolSetting(int code) { return DebuggerSettings::instance()->item(code)->value().toBool(); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 4b0ebd66c86..6fc9366f7bf 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -34,6 +34,9 @@ #include +QT_BEGIN_NAMESPACE +class QActionGroup; +QT_END_NAMESPACE namespace Debugger { namespace Internal { @@ -46,18 +49,22 @@ public: ~DebuggerSettings(); 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(); + // Return one of FormatHexadecimal, FormatDecimal,... + int checkedRegisterFormatAction() const; + public slots: void readSettings(QSettings *settings); - void writeSettings(QSettings *settings); + void writeSettings(QSettings *settings) const; private: QHash m_items; + QActionGroup *m_registerFormatGroup; }; @@ -125,7 +132,10 @@ enum DebuggerActionCode // singleton access Core::Utils::SavedAction *theDebuggerAction(int code); -// convienience +// Return one of FormatHexadecimal, FormatDecimal,... +int checkedRegisterFormatAction(); + +// convenience bool theDebuggerBoolSetting(int code); QString theDebuggerStringSetting(int code); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index ea41b9854ea..8a1cb6baca7 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -650,6 +650,19 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess connect(resetToSimpleAction, SIGNAL(triggered()), 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: m_generalOptionPage = new GdbOptionPage; addObject(m_generalOptionPage); diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 906b38a72b1..af3bde01f31 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -221,19 +221,6 @@ void GdbEngine::initializeConnections() connect(theDebuggerAction(RecheckDebuggingHelpers), SIGNAL(triggered()), 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()), this, SLOT(reloadFullStack())); connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()), @@ -2619,22 +2606,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() { - QString format; - 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); + sendCommand(QLatin1String("-data-list-register-values ") + QLatin1Char(registerFormatChar()), RegisterListValues); } void GdbEngine::handleRegisterListNames(const GdbResultRecord &record) From f0794bd0d4d05baa2c44c1ee4a797f50985f6f24 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 14 Apr 2009 10:10:42 +0200 Subject: [PATCH 02/11] Fixes: Find CDB on 64 Bit Windows. --- src/plugins/debugger/cdb/cdb.pri | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri index 6096f2f3e8d..97932b31026 100644 --- a/src/plugins/debugger/cdb/cdb.pri +++ b/src/plugins/debugger/cdb/cdb.pri @@ -6,6 +6,10 @@ contains(QMAKE_CXX, cl) { CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk" +!exists ($$CDB_PATH) { + CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk" +} + exists ($$CDB_PATH) { message("Experimental: Adding support for $$CDB_PATH") From 07f1aafa38fc0a15ced67a94291b9ecf7f329588 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 14 Apr 2009 10:14:51 +0200 Subject: [PATCH 03/11] Fixes: Startup wrapper when Creator in directory with spaces. Bug reported and fix suggested by catanzag on Qt Labs blog. Thanks! Reviewed By: Thorbjorn Lindeijer --- bin/qtcreator | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/qtcreator b/bin/qtcreator index d00cfa0f582..f66b08778a6 100755 --- a/bin/qtcreator +++ b/bin/qtcreator @@ -1,9 +1,9 @@ #!/bin/sh -bindir=$(dirname $(readlink -nf $0)) +bindir=$(dirname "$(readlink -nf $0)") if test "$(uname -m)" = "x86_64" ; then - libdir=$(cd ${bindir}/../lib64 ; pwd) + libdir=$(cd "${bindir}/../lib64" ; pwd) else - libdir=$(cd ${bindir}/../lib ; pwd) + libdir=$(cd "${bindir}/../lib" ; pwd) fi LD_LIBRARY_PATH="${libdir}/qtcreator:${LD_LIBRARY_PATH}" exec "${bindir}/qtcreator.bin" ${1+"$@"} From b95af44c0dbdc9ff367e841cbe262cdc10fc292e Mon Sep 17 00:00:00 2001 From: Fred Emmott Date: Sat, 11 Apr 2009 08:52:03 +0100 Subject: [PATCH 04/11] work on substitution command in fakevim --- src/plugins/fakevim/fakevimhandler.cpp | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index f26d0ffcff4..ce35fea860d 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1701,6 +1701,7 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0) static QRegExp reNormal("^norm(al)?( (.*))?$"); static QRegExp reSet("^set?( (.*))?$"); static QRegExp reWrite("^w!?( (.*))?$"); + static QRegExp reSubstitute("^s(.)(.*)\\1(.*)\\1([gi]*)"); if (cmd.isEmpty()) { setPosition(firstPositionInLine(beginLine)); @@ -1805,6 +1806,47 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0) enterCommandMode(); //qDebug() << "REPLAY: " << reNormal.cap(3); 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, + QTextCursor::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 showBlackMessage(QString()); QString arg = reSet.cap(2); From d4ccc16f9fe5dcadeddf0a2d49cdeff409812deb Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 14 Apr 2009 15:04:19 +0200 Subject: [PATCH 05/11] Implement disassembler for cdb. Filter debugging output correctly, some glitches. Extract base class for debugging output to be able to intercept debugging output for other purposes (such as disassembling). --- src/plugins/debugger/breakwindow.cpp | 9 +- src/plugins/debugger/cdb/cdbassembler.cpp | 153 +++++++++++++++++- src/plugins/debugger/cdb/cdbassembler.h | 10 ++ src/plugins/debugger/cdb/cdbdebugengine.cpp | 35 +++- src/plugins/debugger/cdb/cdbdebugoutput.cpp | 79 ++++++--- src/plugins/debugger/cdb/cdbdebugoutput.h | 45 +++++- .../debugger/cdb/cdbstacktracecontext.cpp | 5 +- .../debugger/cdb/cdbstacktracecontext.h | 4 + src/plugins/debugger/debuggermanager.cpp | 2 + src/plugins/debugger/disassemblerhandler.cpp | 8 + src/plugins/debugger/disassemblerhandler.h | 2 + 11 files changed, 313 insertions(+), 39 deletions(-) diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index a571fafae50..a93885abcb1 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -84,16 +84,17 @@ void BreakWindow::resizeEvent(QResizeEvent *ev) void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) { 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); - act0->setEnabled(index.isValid()); + act0->setEnabled(indexIsValid); QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu); QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu); act2->setCheckable(true); act2->setChecked(m_alwaysResizeColumnsToContents); QAction *act3 = new QAction(tr("Edit condition..."), &menu); - act0->setEnabled(index.isValid()); - QAction *act4 = new QAction(tr("Syncronize breakpoints"), &menu); + act3->setEnabled(indexIsValid); + QAction *act4 = new QAction(tr("Synchronize breakpoints"), &menu); menu.addAction(act0); menu.addAction(act3); diff --git a/src/plugins/debugger/cdb/cdbassembler.cpp b/src/plugins/debugger/cdb/cdbassembler.cpp index 3d01d6d54ee..00c34415ea2 100644 --- a/src/plugins/debugger/cdb/cdbassembler.cpp +++ b/src/plugins/debugger/cdb/cdbassembler.cpp @@ -28,15 +28,20 @@ **************************************************************************/ #include "cdbassembler.h" -#include "registerhandler.h" +#include "cdbdebugoutput.h" #include "cdbdebugengine_p.h" #include "cdbsymbolgroupcontext.h" +#include "disassemblerhandler.h" +#include "registerhandler.h" + #include namespace Debugger { namespace Internal { +typedef QList DisassemblerLineList; + bool getRegisters(IDebugControl4 *ctl, IDebugRegisters2 *ireg, QList *registers, @@ -79,5 +84,151 @@ bool getRegisters(IDebugControl4 *ctl, return true; } +// Output parser for disassembler lines. +// It uses the source file lines as symbol until it encounters +// a C++ symbol (function entered), from which then on +// it uses that symbol. +class DisassemblerOutputParser +{ +public: + explicit DisassemblerOutputParser(DisassemblerLineList *list); + + void parse(const QStringList &l); + +private: + enum ParseResult { ParseOk, ParseIgnore, ParseFailed }; + ParseResult parseDisassembled(const QString &in, DisassemblerLine* l); + + DisassemblerLineList *m_list; + QString m_sourceSymbol; + int m_sourceSymbolOffset; +}; + +DisassemblerOutputParser::DisassemblerOutputParser(DisassemblerLineList *list) : + m_list(list), + m_sourceSymbolOffset(0) +{ +} + +// Parse a disassembler line: +// module!class::foo: +// 004017cf cc int 3 +// 77 mainwindow.cpp 004018ff 8d4da8 lea ecx,[ebp-0x58] +DisassemblerOutputParser::ParseResult + DisassemblerOutputParser::parseDisassembled(const QString &in, DisassemblerLine* l) +{ + l->clear(); + + // Check if there is a source file + if (in.size() < 7) + return ParseIgnore; + const bool hasSourceFile = !in.at(6).isSpace(); + + // Sometimes, empty lines occur + const QString simplified = in.simplified(); + if (simplified.isEmpty()) + return ParseIgnore; + + QStringList tokens = simplified.split(QLatin1Char(' '), QString::SkipEmptyParts); + // Check for symbols as 'module!class::foo:' (start of function encountered) + if (tokens.size() == 1) { + QString symbol = tokens.front(); + if (symbol.endsWith(QLatin1Char(':')) && symbol.contains(QLatin1Char('!'))) { + symbol.truncate(symbol.size() - 1); + m_sourceSymbol = symbol; + m_sourceSymbolOffset = 0; + } + return ParseIgnore; + } + if (tokens.size() < 2) + return ParseIgnore; + // Symbol display: Do we know a symbol? + if (!m_sourceSymbol.isEmpty()) { + l->symbol = QString(QLatin1Char('<')); + l->symbol += m_sourceSymbol; + if (m_sourceSymbolOffset) { + l->symbol += QLatin1Char('+'); + l->symbol += QString::number(m_sourceSymbolOffset); + } + l->symbol += QLatin1Char('>'); + m_sourceSymbolOffset++; + } + // Read source file information: If we don't know a symbol yet, + // use the source file. + if (hasSourceFile) { + if (l->symbol.isEmpty()) { + l->symbol = tokens.at(1); + l->symbol += QLatin1Char('+'); + l->symbol += tokens.front(); + } + tokens.pop_front(); + tokens.pop_front(); + } + l->symbolDisplay = l->symbol; + // Get offset address and instruction + if (tokens.size() < 3) + return ParseFailed; + l->addressDisplay = l->address = tokens.front(); + tokens.pop_front(); + // The rest is effective address & instructions + if (tokens.size() > 1) + tokens.pop_front(); + l->mnemonic = tokens.join(QString(QLatin1Char(' '))); + return ParseOk; +} + +void DisassemblerOutputParser::parse(const QStringList &l) +{ + DisassemblerLine dLine; + foreach(const QString &line, l) { + switch (parseDisassembled(line, &dLine)) { + case ParseOk: + m_list->push_back(dLine); + break; + case ParseIgnore: + break; + case ParseFailed: + qWarning("Failed to parse '%s'\n", qPrintable(line)); + break; + } + } +} + +bool dissassemble(IDebugClient5 *client, + IDebugControl4 *ctl, + ULONG64 offset, + unsigned long beforeLines, + unsigned long afterLines, + QList *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; +} + } } diff --git a/src/plugins/debugger/cdb/cdbassembler.h b/src/plugins/debugger/cdb/cdbassembler.h index e2386797e04..d065707db14 100644 --- a/src/plugins/debugger/cdb/cdbassembler.h +++ b/src/plugins/debugger/cdb/cdbassembler.h @@ -39,6 +39,8 @@ namespace Debugger { namespace Internal { +class DisassemblerLine; + // Utilities related to assembler code. class Register; @@ -47,6 +49,14 @@ bool getRegisters(IDebugControl4 *ctl, QList *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 *lines, + QString *errorMessage); } } diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index bdb692af941..77efd2d4d0b 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -42,6 +42,7 @@ #include "watchhandler.h" #include "registerhandler.h" #include "moduleshandler.h" +#include "disassemblerhandler.h" #include "watchutils.h" #include @@ -56,6 +57,7 @@ #include #include #include +#include #define DBGHELP_TRANSLATE_TCHAR #include @@ -195,7 +197,6 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn m_breakEventMode(BreakEventHandle), m_watchTimer(-1), m_debugEventCallBack(engine), - m_debugOutputCallBack(engine), m_pDebugClient(0), m_pDebugControl(0), m_pDebugSystemObjects(0), @@ -225,7 +226,7 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage) return false; } - m_pDebugClient->SetOutputCallbacks(&m_debugOutputCallBack); + m_pDebugClient->SetOutputCallbacksWide(&m_debugOutputCallBack); m_pDebugClient->SetEventCallbacks(&m_debugEventCallBack); hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast(&m_pDebugControl)); @@ -317,6 +318,10 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) : 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() @@ -1040,7 +1045,31 @@ void CdbDebugEngine::saveSessionData() } 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 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()); + } } void CdbDebugEngine::reloadModules() diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.cpp b/src/plugins/debugger/cdb/cdbdebugoutput.cpp index f0df999d28b..114c59c7712 100644 --- a/src/plugins/debugger/cdb/cdbdebugoutput.cpp +++ b/src/plugins/debugger/cdb/cdbdebugoutput.cpp @@ -27,7 +27,6 @@ ** **************************************************************************/ - #include "cdbdebugoutput.h" #include "cdbdebugengine.h" #include "cdbdebugengine_p.h" @@ -38,12 +37,11 @@ namespace Debugger { namespace Internal { -CdbDebugOutput::CdbDebugOutput(CdbDebugEngine* engine) : - m_pEngine(engine) +CdbDebugOutputBase::CdbDebugOutputBase() { } -STDMETHODIMP CdbDebugOutput::QueryInterface( +STDMETHODIMP CdbDebugOutputBase::QueryInterface( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface @@ -52,9 +50,9 @@ STDMETHODIMP CdbDebugOutput::QueryInterface( *Interface = NULL; if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || - IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks))) + IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacksWide))) { - *Interface = (IDebugOutputCallbacks *)this; + *Interface = (IDebugOutputCallbacksWide*)this; AddRef(); return S_OK; } else { @@ -62,27 +60,43 @@ STDMETHODIMP CdbDebugOutput::QueryInterface( } } -STDMETHODIMP_(ULONG) CdbDebugOutput::AddRef(THIS) +STDMETHODIMP_(ULONG) CdbDebugOutputBase::AddRef(THIS) { // This class is designed to be static so // there's no true refcount. return 1; } -STDMETHODIMP_(ULONG) CdbDebugOutput::Release(THIS) +STDMETHODIMP_(ULONG) CdbDebugOutputBase::Release(THIS) { // This class is designed to be static so // there's no true refcount. return 0; } +STDMETHODIMP CdbDebugOutputBase::Output( + THIS_ + IN ULONG mask, + IN PCWSTR text + ) +{ + output(mask, QString::fromUtf16(text)); + 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_DEBUGGEE|DEBUG_OUTPUT_DEBUGGEE_PROMPT|DEBUG_OUTPUT_DEBUGGEE_PROMPT)) { - static const QString p = QLatin1String("target:"); - return p; - } if (mask & (DEBUG_OUTPUT_PROMPT_REGISTERS)) { static const QString p = QLatin1String("registers:"); return p; @@ -103,23 +117,42 @@ static QString prefix(ULONG mask) return commonPrefix; } -STDMETHODIMP CdbDebugOutput::Output( - THIS_ - IN ULONG mask, - IN PCSTR text - ) -{ - const QString msg = QString::fromLocal8Bit(text); +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; - if (mask & (DEBUG_OUTPUT_PROMPT|DEBUG_OUTPUT_DEBUGGEE_PROMPT)) { + switch (outputKind(mask)) { + case DebuggerOutput: + debuggerOutput(prefix(mask), msg); + break; + case DebuggerPromptOutput: emit debuggerInputPrompt(prefix(mask), msg); - } else { - emit debuggerOutput(prefix(mask), msg); + break; + case DebuggeeOutput: + emit debuggeeOutput(msg); + break; + case DebuggeePromptOutput: + emit debuggeeInputPrompt(msg); + break; } - return S_OK; } } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.h b/src/plugins/debugger/cdb/cdbdebugoutput.h index 827d85bbb28..f13fedac35e 100644 --- a/src/plugins/debugger/cdb/cdbdebugoutput.h +++ b/src/plugins/debugger/cdb/cdbdebugoutput.h @@ -38,14 +38,12 @@ namespace Debugger { 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 QObject, public IDebugOutputCallbacks +class CdbDebugOutputBase : public IDebugOutputCallbacksWide { - Q_OBJECT public: - explicit CdbDebugOutput(CdbDebugEngine* engine); - // IUnknown. STDMETHOD(QueryInterface)( THIS_ @@ -63,15 +61,48 @@ public: STDMETHOD(Output)( THIS_ 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: - CdbDebugEngine* m_pEngine; + QString m_result; }; } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 0500657dc44..7d207fbba66 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -40,7 +40,8 @@ namespace Internal { CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects, IDebugSymbols3* pDebugSymbols) : 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) { StackFrame frame(i); const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset; + if (i == 0) + m_instructionOffset = instructionOffset; frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16); m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0); diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h index bb8286859ef..4f3be5c5fc1 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -66,6 +66,9 @@ public: QList frames() const { return m_frames; } 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); private: @@ -78,6 +81,7 @@ private: DEBUG_STACK_FRAME m_cdbFrames[maxFrames]; QVector m_symbolContexts; QList m_frames; + ULONG64 m_instructionOffset; }; } diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index cf2066c7909..9597c128c9b 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -213,6 +213,8 @@ void DebuggerManager::init() QAbstractItemView *disassemblerView = qobject_cast(m_disassemblerWindow); disassemblerView->setModel(m_disassemblerHandler->model()); + connect(m_disassemblerWindow, SIGNAL(reloadDisassemblerRequested()), + this, SLOT(reloadDisassembler())); // Breakpoints m_breakHandler = new BreakHandler; diff --git a/src/plugins/debugger/disassemblerhandler.cpp b/src/plugins/debugger/disassemblerhandler.cpp index 9ef9efec9c6..ee03f6cfd55 100644 --- a/src/plugins/debugger/disassemblerhandler.cpp +++ b/src/plugins/debugger/disassemblerhandler.cpp @@ -39,6 +39,14 @@ using namespace Debugger; using namespace Debugger::Internal; +void DisassemblerLine::clear() +{ + address.clear(); + symbol.clear(); + addressDisplay.clear(); + symbolDisplay.clear(); + mnemonic.clear(); +} ////////////////////////////////////////////////////////////////// // diff --git a/src/plugins/debugger/disassemblerhandler.h b/src/plugins/debugger/disassemblerhandler.h index 6c0a5b37bad..4b73e69ddbf 100644 --- a/src/plugins/debugger/disassemblerhandler.h +++ b/src/plugins/debugger/disassemblerhandler.h @@ -41,6 +41,8 @@ namespace Internal { class DisassemblerLine { public: + void clear(); + QString address; QString symbol; QString addressDisplay; From 7f84a96e3a9d6ca35a4494ab7831cfc2d8dff132 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 14 Apr 2009 15:22:52 +0200 Subject: [PATCH 06/11] Compile on Windows. --- src/plugins/fakevim/fakevimhandler.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index ce35fea860d..9991b34340a 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -1830,7 +1830,7 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0) if (position != -1) { m_tc.setPosition(position); m_tc.movePosition(QTextCursor::NextCharacter, - QTextCursor::KeepAnchor, pattern.matchedLength()); + KeepAnchor, pattern.matchedLength()); QString text = m_tc.selectedText(); if (text.endsWith(ParagraphSeparator)) { text = replacement + "\n"; @@ -2372,11 +2372,13 @@ void FakeVimHandler::Private::recordJump() UNDO_DEBUG("jumps: " << m_jumpListUndo); } -struct UndoBreaker : public QAbstractUndoItem +class UndoBreaker : public QAbstractUndoItem { +public: UndoBreaker(FakeVimHandler::Private *doc) : m_doc(doc) {} void undo() { m_doc->m_needMoreUndo = true; } void redo() { m_doc->m_needMoreUndo = true; } +private: FakeVimHandler::Private *m_doc; }; From 0c03179facec6256bec47064619cf3e55462b589 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 14 Apr 2009 15:47:25 +0200 Subject: [PATCH 07/11] fakevim: compile fix --- src/plugins/fakevim/fakevimhandler.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 9991b34340a..0b76cfc1de6 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -96,15 +96,16 @@ namespace Internal { // /////////////////////////////////////////////////////////////////////// -#define StartOfLine QTextCursor::StartOfLine -#define EndOfLine QTextCursor::EndOfLine -#define MoveAnchor QTextCursor::MoveAnchor -#define KeepAnchor QTextCursor::KeepAnchor -#define Up QTextCursor::Up -#define Down QTextCursor::Down -#define Right QTextCursor::Right -#define Left QTextCursor::Left -#define EndOfDocument QTextCursor::End +#define StartOfLine QTextCursor::StartOfLine +#define EndOfLine QTextCursor::EndOfLine +#define MoveAnchor QTextCursor::MoveAnchor +#define KeepAnchor QTextCursor::KeepAnchor +#define Up QTextCursor::Up +#define Down QTextCursor::Down +#define Right QTextCursor::Right +#define Left QTextCursor::Left +#define EndOfDocument QTextCursor::End +#define StartOfDocument QTextCursor::Start #define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s) @@ -274,8 +275,6 @@ public: void moveToWordBoundary(bool simple, bool forward); // to reduce line noise - typedef QTextCursor::MoveOperation MoveOperation; - typedef QTextCursor::MoveMode MoveMode; void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); } void moveToStartOfLine() { m_tc.movePosition(StartOfLine, MoveAnchor); } void moveToEndOfLine(); @@ -1969,7 +1968,7 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0) if (!needle0.isEmpty()) { QTextCursor tc = m_tc; - tc.movePosition(QTextCursor::Start, MoveAnchor); + tc.movePosition(StartOfDocument, MoveAnchor); QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively; QString needle = needle0; From d11242feba7feeb18979088df1f36f9b0d79f84b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 15 Apr 2009 10:05:40 +0200 Subject: [PATCH 08/11] Make break by function work for CDB. Add function to automagically resolve function symbol names that are missing the module name (module!foo). Kill some trailing whitespace. Add a hack to transform qMain->main for VS. --- src/plugins/debugger/cdb/cdbbreakpoint.cpp | 37 ++++++++++++-- src/plugins/debugger/cdb/cdbbreakpoint.h | 3 +- src/plugins/debugger/cdb/cdbdebugengine.cpp | 37 ++++++++------ src/plugins/debugger/cdb/cdbmodules.cpp | 56 +++++++++++++++++++++ src/plugins/debugger/cdb/cdbmodules.h | 11 ++++ 5 files changed, 123 insertions(+), 21 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp index 035c5d76fca..345ed2f9680 100644 --- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp +++ b/src/plugins/debugger/cdb/cdbbreakpoint.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include "cdbbreakpoint.h" +#include "cdbmodules.h" #include "breakhandler.h" #include "cdbdebugengine_p.h" @@ -279,20 +280,48 @@ bool CDBBreakPoint::getBreakPoints(IDebugControl4* debugControl, QList BreakPointIndexMap; - BreakPointIndexMap breakPointIndexMap; - // convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index if (debugCDB) 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(); - for (int i=0; i < handlerCount; ++i) - breakPointIndexMap.insert(CDBBreakPoint(*handler->at(i)), i); + const QChar moduleDelimiter = QLatin1Char('!'); + 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 ULONG engineCount; if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.h b/src/plugins/debugger/cdb/cdbbreakpoint.h index 2abdddcb942..3040c0895f0 100644 --- a/src/plugins/debugger/cdb/cdbbreakpoint.h +++ b/src/plugins/debugger/cdb/cdbbreakpoint.h @@ -72,7 +72,8 @@ struct CDBBreakPoint { static bool getBreakPointCount(IDebugControl4* debugControl, ULONG *count, QString *errorMessage = 0); static bool getBreakPoints(IDebugControl4* debugControl, QList *bps, QString *errorMessage); // 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) static QString canonicalSourceFile(const QString &f); diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 77efd2d4d0b..cf42ce3faf2 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -208,7 +208,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn m_currentStackTrace(0), m_firstActivatedFrame(true), m_mode(AttachCore) -{ +{ } bool CdbDebugEnginePrivate::init(QString *errorMessage) @@ -252,7 +252,7 @@ bool CdbDebugEnginePrivate::init(QString *errorMessage) hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast(&m_pDebugRegisters)); if (FAILED(hr)) { *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr)); - return false; + return false; } if (debugCDB) qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_pDebugControl)); @@ -299,7 +299,7 @@ void CdbDebugEnginePrivate::clearForRun() } void CdbDebugEnginePrivate::cleanStackTrace() -{ +{ if (m_currentStackTrace) { delete m_currentStackTrace; m_currentStackTrace = 0; @@ -366,7 +366,7 @@ void CdbDebugEnginePrivate::clearDisplay() } bool CdbDebugEngine::startDebugger() -{ +{ m_d->clearDisplay(); m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1); QString errorMessage; @@ -489,7 +489,7 @@ void CdbDebugEngine::exitDebugger() // Terminate or detach if we are running HRESULT hr; switch (m_d->m_mode) { - case AttachExternal: + case AttachExternal: wasRunning = m_d->isDebuggeeRunning(); if (wasRunning) { // Process must be stopped in order to detach m_d->interruptInterferiorProcess(&errorMessage); @@ -502,7 +502,7 @@ void CdbDebugEngine::exitDebugger() qDebug() << Q_FUNC_INFO << "detached" << msgDebugEngineComResult(hr); break; case StartExternal: - case StartInternal: + case StartInternal: wasRunning = m_d->isDebuggeeRunning(); if (wasRunning) { // Process must be stopped in order to terminate m_d->interruptInterferiorProcess(&errorMessage); @@ -569,7 +569,7 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex, qDebug() << Q_FUNC_INFO << "\n " << frameIndex << formatWatchList(incompletes); m_engine->filterEvaluateWatchers(&incompletes, wh); - if (!incompletes.empty()) { + if (!incompletes.empty()) { const QString msg = QLatin1String("Warning: Locals left in incomplete list: ") + formatWatchList(incompletes); qWarning("%s\n", qPrintable(msg)); } @@ -613,7 +613,7 @@ void CdbDebugEngine::filterEvaluateWatchers(QList *wd, WatchHandler * bool placeHolderSeen = false; for (WatchList::iterator it = wd->begin(); it != wd->end(); ) { 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 (!placeHolderSeen) { // Max one place holder it->setChildCount(0); @@ -624,7 +624,7 @@ void CdbDebugEngine::filterEvaluateWatchers(QList *wd, WatchHandler * } else { evaluateWatcher(&(*it)); wh->insertData(*it); - } + } it = wd->erase(it); } else { ++it; @@ -778,7 +778,7 @@ bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessage) // Continue process with notifications bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage) -{ +{ ULONG executionStatus; if (!getExecutionStatus(m_pDebugControl, &executionStatus, errorMessage)) return false; @@ -817,7 +817,7 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage) *errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Core::Utils::winErrorMessage(GetLastError())); return false; } -#if 0 +#if 0 const HRESULT hr = m_pDebugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT); if (FAILED(hr)) { *errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2"). @@ -864,7 +864,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v if (debugCDB) qDebug() << Q_FUNC_INFO << expr << value; const int frameIndex = m_d->m_debuggerManagerAccess->stackHandler()->currentIndex(); - QString errorMessage; + QString errorMessage; bool success = false; do { QString newValue; @@ -872,7 +872,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v if (!sg) break; if (!sg->assignValue(expr, value, &newValue, &errorMessage)) - break; + break; // Update view WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); if (WatchData *fwd = watchHandler->findData(expr)) { @@ -1032,6 +1032,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa } return CDBBreakPoint::synchronizeBreakPoints(m_pDebugControl, + m_pDebugSymbols, m_debuggerManagerAccess->breakHandler(), errorMessage); } @@ -1045,7 +1046,7 @@ void CdbDebugEngine::saveSessionData() } 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); @@ -1140,7 +1141,7 @@ void CdbDebugEngine::timerEvent(QTimerEvent* te) break; case E_UNEXPECTED: // Occurs on ExitProcess. killWatchTimer(); - break; + break; } } @@ -1260,6 +1261,10 @@ void CdbDebugEnginePrivate::updateStackTrace() qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage)); return; } + // Disassembling slows things down a bit. Assembler is still available via menu. +#if 0 + m_engine->reloadDisassembler(); // requires stack trace +#endif const QList stackFrames = m_currentStackTrace->frames(); // find the first usable frame and select it int current = -1; @@ -1275,7 +1280,7 @@ void CdbDebugEnginePrivate::updateStackTrace() if (current >= 0) { m_debuggerManagerAccess->stackHandler()->setCurrentIndex(current); m_engine->activateFrame(current); - } + } } diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp index 6e97800e843..70e8bd7d523 100644 --- a/src/plugins/debugger/cdb/cdbmodules.cpp +++ b/src/plugins/debugger/cdb/cdbmodules.cpp @@ -77,5 +77,61 @@ bool getModuleList(IDebugSymbols3 *syms, QList *modules, QString *errorM return true; } +// Search symbols matching a pattern +bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern, + QStringList *matches, QString *errorMessage) +{ + matches->clear(); + ULONG64 handle; + // E_NOINTERFACE means "no match" + HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle); + if (hr == E_NOINTERFACE) { + 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; +} + } } diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h index 3a959b7f575..a7be7a94321 100644 --- a/src/plugins/debugger/cdb/cdbmodules.h +++ b/src/plugins/debugger/cdb/cdbmodules.h @@ -42,6 +42,17 @@ namespace Internal { class Module; bool getModuleList(IDebugSymbols3 *syms, QList *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); } } From 4c2f5d1eafc15a108def26eea40bda0eaf011586 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 15 Apr 2009 12:01:58 +0200 Subject: [PATCH 09/11] Make the "Show symbols" option of the module window work on Windows. Introduce API to debug engines and debugger manager to do this. Reviewed-by: hjk --- src/plugins/debugger/cdb/cdbmodules.cpp | 32 ++++++++++++-- src/plugins/debugger/cdb/cdbmodules.h | 5 +++ src/plugins/debugger/debuggermanager.cpp | 8 +++- src/plugins/debugger/debuggermanager.h | 4 +- src/plugins/debugger/gdbengine.cpp | 34 +++++++++++++++ src/plugins/debugger/gdbengine.h | 1 + src/plugins/debugger/idebuggerengine.h | 4 ++ src/plugins/debugger/moduleshandler.h | 13 ++++++ src/plugins/debugger/moduleswindow.cpp | 53 +++++++++++++----------- src/plugins/debugger/moduleswindow.h | 5 ++- src/plugins/debugger/scriptengine.cpp | 5 +++ src/plugins/debugger/scriptengine.h | 1 + 12 files changed, 134 insertions(+), 31 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp index 70e8bd7d523..8dd52a01353 100644 --- a/src/plugins/debugger/cdb/cdbmodules.cpp +++ b/src/plugins/debugger/cdb/cdbmodules.cpp @@ -31,6 +31,8 @@ #include "moduleshandler.h" #include "cdbdebugengine_p.h" +#include + namespace Debugger { namespace Internal { @@ -82,11 +84,13 @@ bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern, QStringList *matches, QString *errorMessage) { matches->clear(); - ULONG64 handle; - // E_NOINTERFACE means "no match" + 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) { - syms->EndSymbolMatch(handle); + if (handle) + syms->EndSymbolMatch(handle); return true; } if (FAILED(hr)) { @@ -133,5 +137,27 @@ ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, return ResolveSymbolOk; } +// List symbols of a module +bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName, + QList *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; +} + } } diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h index a7be7a94321..d3058bc906f 100644 --- a/src/plugins/debugger/cdb/cdbmodules.h +++ b/src/plugins/debugger/cdb/cdbmodules.h @@ -40,6 +40,7 @@ namespace Debugger { namespace Internal { class Module; +class Symbol; bool getModuleList(IDebugSymbols3 *syms, QList *modules, QString *errorMessage); // Search symbols matching a pattern @@ -54,6 +55,10 @@ enum ResolveSymbolResult { ResolveSymbolOk, ResolveSymbolAmbiguous, ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString *errorMessage); +// List symbols of a module +bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName, + QList *symbols, QString *errorMessage); + } } diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 9597c128c9b..5f8f07aed0e 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -175,7 +175,7 @@ void DebuggerManager::init() m_statusLabel = new QLabel; m_breakWindow = new BreakWindow; m_disassemblerWindow = new DisassemblerWindow; - m_modulesWindow = new ModulesWindow; + m_modulesWindow = new ModulesWindow(this); m_outputWindow = new DebuggerOutputWindow; m_registerWindow = new RegisterWindow; m_stackWindow = new StackWindow; @@ -998,6 +998,12 @@ void DebuggerManager::loadSymbols(const QString &module) m_engine->loadSymbols(module); } +QList DebuggerManager::moduleSymbols(const QString &moduleName) +{ + QTC_ASSERT(m_engine, return QList()); + return m_engine->moduleSymbols(moduleName); +} + void DebuggerManager::stepExec() { QTC_ASSERT(m_engine, return); diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 72c1467c52e..b9709a68fa5 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -65,7 +65,7 @@ class WatchHandler; class SourceFilesWindow; class WatchData; class BreakpointData; - +class Symbol; // Note: the Debugger process itself is referred to as 'Debugger', // whereas the debugged process is referred to as 'Inferior' or 'Debuggee'. @@ -309,6 +309,8 @@ public: int status() const { return m_status; } DebuggerStartMode startMode() const { return m_startMode; } + QList moduleSymbols(const QString &moduleName); + signals: void debuggingFinished(); void inferiorPidChanged(qint64 pid); diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index af3bde01f31..0279c15181f 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -2389,6 +2389,40 @@ void GdbEngine::loadAllSymbols() reloadModules(); } +QList GdbEngine::moduleSymbols(const QString &moduleName) +{ + QList 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() { sendCommand("info shared", ModulesList, QVariant()); diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index aebb5da6373..b5f5868dcf5 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -129,6 +129,7 @@ private: void loadSymbols(const QString &moduleName); void loadAllSymbols(); + virtual QList moduleSymbols(const QString &moduleName); Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); Q_SLOT void setUseDebuggingHelpers(const QVariant &on); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 2bb44f8e47b..0d3863a34e7 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -31,6 +31,7 @@ #define DEBUGGER_IDEBUGGERENGINE_H #include +#include QT_BEGIN_NAMESPACE class QPoint; @@ -40,6 +41,8 @@ QT_END_NAMESPACE namespace Debugger { namespace Internal { +class Symbol; + class IDebuggerEngine : public QObject { public: @@ -79,6 +82,7 @@ public: virtual void reloadModules() = 0; virtual void loadSymbols(const QString &moduleName) = 0; virtual void loadAllSymbols() = 0; + virtual QList moduleSymbols(const QString &moduleName) = 0; virtual void reloadRegisters() = 0; diff --git a/src/plugins/debugger/moduleshandler.h b/src/plugins/debugger/moduleshandler.h index 4c555c83929..a6d77e4a28e 100644 --- a/src/plugins/debugger/moduleshandler.h +++ b/src/plugins/debugger/moduleshandler.h @@ -51,6 +51,19 @@ enum ModulesModelRoles LoadAllSymbolsRole }; +////////////////////////////////////////////////////////////////// +// +// Symbol +// +////////////////////////////////////////////////////////////////// + +class Symbol +{ +public: + QString address; + QString state; + QString name; +}; ////////////////////////////////////////////////////////////////// // diff --git a/src/plugins/debugger/moduleswindow.cpp b/src/plugins/debugger/moduleswindow.cpp index 8d87709eadc..6435e8b65a6 100644 --- a/src/plugins/debugger/moduleswindow.cpp +++ b/src/plugins/debugger/moduleswindow.cpp @@ -29,6 +29,7 @@ #include "moduleswindow.h" #include "moduleshandler.h" // for model roles +#include "debuggermanager.h" #include #include @@ -40,7 +41,7 @@ #include #include #include - +#include /////////////////////////////////////////////////////////////////////////// // @@ -48,10 +49,14 @@ // /////////////////////////////////////////////////////////////////////////// -using Debugger::Internal::ModulesWindow; +namespace Debugger { +namespace Internal { -ModulesWindow::ModulesWindow(QWidget *parent) - : QTreeView(parent), m_alwaysResizeColumnsToContents(false) +ModulesWindow::ModulesWindow(DebuggerManager *debuggerManager, + QWidget *parent) : + QTreeView(parent), + m_alwaysResizeColumnsToContents(false), + m_debuggerManager(debuggerManager) { setWindowTitle(tr("Modules")); setSortingEnabled(true); @@ -88,9 +93,12 @@ void ModulesWindow::resizeEvent(QResizeEvent *event) void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev) { + QString name; QModelIndex index = indexAt(ev->pos()); - index = index.sibling(index.row(), 0); - QString name = model()->data(index).toString(); + if (index.isValid()) + index = index.sibling(index.row(), 0); + if (index.isValid()) + name = model()->data(index).toString(); QMenu menu; QAction *act0 = new QAction(tr("Update module list"), &menu); @@ -116,9 +124,6 @@ void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev) act5->setDisabled(name.isEmpty()); act6->setDisabled(name.isEmpty()); act7->setDisabled(name.isEmpty()); - #ifndef Q_OS_LINUX - act7->setDisabled(true); - #endif menu.addAction(act0); menu.addAction(act4); @@ -178,28 +183,26 @@ void ModulesWindow::showSymbols(const QString &name) { if (name.isEmpty()) return; - QProcess proc; - proc.start("nm", QStringList() << "-D" << name); - proc.waitForFinished(); + QApplication::setOverrideCursor(Qt::WaitCursor); + const QList symbols = m_debuggerManager->moduleSymbols(name); + QApplication::restoreOverrideCursor(); + if (symbols.empty()) + return; QTreeWidget *w = new QTreeWidget; w->setColumnCount(3); w->setRootIsDecorated(false); w->setAlternatingRowColors(true); - //w->header()->hide(); w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol")); w->setWindowTitle(tr("Symbols in \"%1\"").arg(name)); - QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput()); - QRegExp re("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)"); - foreach (QString line, contents.split('\n')) { - if (re.indexIn(line) != -1) { - QTreeWidgetItem *it = new QTreeWidgetItem; - it->setData(0, Qt::DisplayRole, re.cap(1)); - it->setData(1, Qt::DisplayRole, re.cap(2)); - it->setData(2, Qt::DisplayRole, re.cap(3)); - w->addTopLevelItem(it); - } else { - qDebug() << "UNHANDLED LINE" << line; - } + foreach (const Symbol &s, symbols) { + QTreeWidgetItem *it = new QTreeWidgetItem; + it->setData(0, Qt::DisplayRole, s.address); + it->setData(1, Qt::DisplayRole, s.state); + it->setData(2, Qt::DisplayRole, s.name); + w->addTopLevelItem(it); } emit newDockRequested(w); } + +} +} diff --git a/src/plugins/debugger/moduleswindow.h b/src/plugins/debugger/moduleswindow.h index 36377fb58ee..fc2b1af2acf 100644 --- a/src/plugins/debugger/moduleswindow.h +++ b/src/plugins/debugger/moduleswindow.h @@ -35,12 +35,14 @@ namespace Debugger { namespace Internal { +class DebuggerManager; + class ModulesWindow : public QTreeView { Q_OBJECT public: - explicit ModulesWindow(QWidget *parent = 0); + explicit ModulesWindow(DebuggerManager *debuggerManager, QWidget *parent = 0); signals: void reloadModulesRequested(); @@ -62,6 +64,7 @@ private: void setModel(QAbstractItemModel *model); bool m_alwaysResizeColumnsToContents; + DebuggerManager *m_debuggerManager; }; } // namespace Internal diff --git a/src/plugins/debugger/scriptengine.cpp b/src/plugins/debugger/scriptengine.cpp index 3ee8b7f8697..4ab74e2154a 100644 --- a/src/plugins/debugger/scriptengine.cpp +++ b/src/plugins/debugger/scriptengine.cpp @@ -38,6 +38,7 @@ #include "registerhandler.h" #include "stackhandler.h" #include "watchhandler.h" +#include "moduleshandler.h" #include @@ -405,6 +406,10 @@ void ScriptEngine::reloadModules() { } +QList ScriptEngine::moduleSymbols(const QString & /*moduleName*/) +{ + return QList(); +} ////////////////////////////////////////////////////////////////////// diff --git a/src/plugins/debugger/scriptengine.h b/src/plugins/debugger/scriptengine.h index 5e009327da7..ee5612d09d8 100644 --- a/src/plugins/debugger/scriptengine.h +++ b/src/plugins/debugger/scriptengine.h @@ -102,6 +102,7 @@ private: void loadSymbols(const QString &moduleName); void loadAllSymbols(); + virtual QList moduleSymbols(const QString &moduleName); void reloadDisassembler(); void reloadModules(); void reloadRegisters() {} From 2f115bebd75ad79bf3bc755c2cd8c886623dcd61 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 15 Apr 2009 12:04:27 +0200 Subject: [PATCH 10/11] Fix previous commit. --- src/plugins/debugger/cdb/cdbdebugengine.cpp | 19 +++++++++++++++++++ src/plugins/debugger/cdb/cdbdebugengine.h | 1 + 2 files changed, 20 insertions(+) diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index cf42ce3faf2..a71aa2ac721 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -1089,6 +1089,25 @@ void CdbDebugEngine::loadAllSymbols() qDebug() << Q_FUNC_INFO; } +QList CdbDebugEngine::moduleSymbols(const QString &moduleName) +{ + QList 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()) { diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index f37bade1cd3..fe91fef5df8 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -87,6 +87,7 @@ public: virtual void reloadModules(); virtual void loadSymbols(const QString &moduleName); virtual void loadAllSymbols(); + virtual QList moduleSymbols(const QString &moduleName); virtual void reloadRegisters(); virtual void reloadSourceFiles(); From 800a48f027242d93c08c98a79b365a4632acb322 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 15 Apr 2009 14:26:08 +0200 Subject: [PATCH 11/11] debugger: code cosmetics --- src/plugins/debugger/cdb/cdbassembler.cpp | 4 ++-- src/plugins/debugger/cdb/cdbassembler.h | 4 ++-- src/plugins/debugger/cdb/cdbbreakpoint.cpp | 4 ++-- src/plugins/debugger/cdb/cdbbreakpoint.h | 7 ++++--- src/plugins/debugger/cdb/cdbdebugengine_p.h | 3 ++- src/plugins/debugger/cdb/cdbmodules.cpp | 4 ++-- src/plugins/debugger/cdb/cdbmodules.h | 4 ++-- src/plugins/debugger/cdb/cdbstacktracecontext.cpp | 4 ++-- src/plugins/debugger/cdb/cdbstacktracecontext.h | 4 ++-- src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp | 8 ++++---- src/plugins/debugger/cdb/cdbsymbolgroupcontext.h | 7 ++++--- 11 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbassembler.cpp b/src/plugins/debugger/cdb/cdbassembler.cpp index 00c34415ea2..4cb59c7d69f 100644 --- a/src/plugins/debugger/cdb/cdbassembler.cpp +++ b/src/plugins/debugger/cdb/cdbassembler.cpp @@ -230,5 +230,5 @@ bool dissassemble(IDebugClient5 *client, return true; } -} -} +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbassembler.h b/src/plugins/debugger/cdb/cdbassembler.h index d065707db14..e43492ebaf2 100644 --- a/src/plugins/debugger/cdb/cdbassembler.h +++ b/src/plugins/debugger/cdb/cdbassembler.h @@ -57,8 +57,8 @@ bool dissassemble(IDebugClient5 *client, unsigned long afterLines, QList *lines, QString *errorMessage); -} -} +} // namespace Internal +} // namespace Debugger #endif // CDBASSEMBLER_H diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp index 345ed2f9680..6ef96f5597a 100644 --- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp +++ b/src/plugins/debugger/cdb/cdbbreakpoint.cpp @@ -385,5 +385,5 @@ bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl, return true; } -} -} +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.h b/src/plugins/debugger/cdb/cdbbreakpoint.h index 3040c0895f0..3d925b2577e 100644 --- a/src/plugins/debugger/cdb/cdbbreakpoint.h +++ b/src/plugins/debugger/cdb/cdbbreakpoint.h @@ -49,7 +49,8 @@ class BreakpointData; /* CDB Break point data structure with utilities to * apply to engine and to retrieve them from the engine and comparison. */ -struct CDBBreakPoint { +struct CDBBreakPoint +{ CDBBreakPoint(); CDBBreakPoint(const BreakpointData &bpd); @@ -94,7 +95,7 @@ inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2) inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2) { return b1.compare(b2) < 0; } -} -} +} // namespace Internal +} // namespace Debugger #endif // CDBBREAKPOINTS_H diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index 665ea28b09e..ce9c2e381bf 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -48,7 +48,8 @@ class CdbStackTraceContext; // Thin wrapper around the 'DBEng' debugger engine shared library // which is loaded at runtime. -class DebuggerEngineLibrary { +class DebuggerEngineLibrary +{ public: DebuggerEngineLibrary(); bool init(QString *errorMessage); diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp index 8dd52a01353..237ead93312 100644 --- a/src/plugins/debugger/cdb/cdbmodules.cpp +++ b/src/plugins/debugger/cdb/cdbmodules.cpp @@ -159,5 +159,5 @@ bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName, return true; } -} -} +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h index d3058bc906f..9a375cdb031 100644 --- a/src/plugins/debugger/cdb/cdbmodules.h +++ b/src/plugins/debugger/cdb/cdbmodules.h @@ -59,7 +59,7 @@ ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName, QList *symbols, QString *errorMessage); -} -} +} // namespace Internal +} // namespace Debugger #endif // CDBMODULES_H diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 7d207fbba66..07bf81c5bd4 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -166,5 +166,5 @@ IDebugSymbolGroup2 *CdbStackTraceContext::createSymbolGroup(int index, QString * return sg; } -} -} +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h index 4f3be5c5fc1..efbd1c1e816 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -84,7 +84,7 @@ private: ULONG64 m_instructionOffset; }; -} -} +} // namespace Internal +} // namespace Debugger #endif // CDBSTACKTRACECONTEXT_H diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index c4895df333e..5f234192785 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -58,13 +58,13 @@ static inline void debugSymbolFlags(unsigned long f, QTextStream &str) 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="; if (isTopLevelSymbol(p)) { str << ""; } else { - str << p.ParentSymbol; + str << p.ParentSymbol; } str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/'; debugSymbolFlags(p.Flags, str); @@ -639,5 +639,5 @@ bool CdbSymbolGroupContext::completeModel(CdbSymbolGroupContext *sg, return true; } -} -} +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index cf4fa2a9839..0773133c18a 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -41,7 +41,7 @@ #include namespace Debugger { - namespace Internal { +namespace Internal { class WatchData; class WatchHandler; @@ -145,6 +145,7 @@ bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterato return true; } -} -} +} // namespace Internal +} // namespace Debugger + #endif // CDBSYMBOLGROUPCONTEXT_H