Commit 6d4d19df authored by Friedemann Kleint's avatar Friedemann Kleint

Handle various CDB output windows.

Add modules, threads and register view. Refactor register format code.
parent e6843ff5
......@@ -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")
......
/**************************************************************************
**
** 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 <QtCore/QVector>
namespace Debugger {
namespace Internal {
bool getRegisters(IDebugControl4 *ctl,
IDebugRegisters2 *ireg,
QList<Register> *registers,
QString *errorMessage, int base)
{
registers->clear();
ULONG count;
HRESULT hr = ireg->GetNumberRegisters(&count);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetNumberRegisters", hr);
return false;
}
if (!count)
return true;
// Retrieve names
WCHAR wszBuf[MAX_PATH];
for (ULONG r = 0; r < count; r++) {
hr = ireg->GetDescriptionWide(r, wszBuf, MAX_PATH - 1, 0, 0);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetDescriptionWide", hr);
return false;
}
Register reg;
reg.name = QString::fromUtf16(wszBuf);
registers->push_back(reg);
}
// get values
QVector<DEBUG_VALUE> values(count);
DEBUG_VALUE *valuesPtr = &(*values.begin());
memset(valuesPtr, 0, count * sizeof(DEBUG_VALUE));
hr = ireg->GetValues(count, 0, 0, valuesPtr);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetValues", hr);
return false;
}
if (base < 2)
base = 10;
for (ULONG r = 0; r < count; r++)
(*registers)[r].value = CdbSymbolGroupContext::debugValueToString(values.at(r), ctl, 0, base);
return true;
}
}
}
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#ifndef CDBASSEMBLER_H
#define CDBASSEMBLER_H
#include <QtCore/QList>
#include <QtCore/QString>
#include <windows.h>
#include <inc/dbgeng.h>
namespace Debugger {
namespace Internal {
// Utilities related to assembler code.
class Register;
bool getRegisters(IDebugControl4 *ctl,
IDebugRegisters2 *ireg,
QList<Register> *registers,
QString *errorMessage,
int base = 10 /* 16 for hex, etc */);
}
}
#endif // CDBASSEMBLER_H
......@@ -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 <utils/qtcassert.h>
......@@ -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<Register> registers;
QString errorMessage;
if (!getRegisters(m_d->m_pDebugControl, m_d->m_pDebugRegisters, &registers, &errorMessage, intBase))
qWarning("reloadRegisters() failed: %s\n", qPrintable(errorMessage));
m_d->m_debuggerManagerAccess->registerHandler()->setRegisters(registers);
}
void CdbDebugEngine::timerEvent(QTimerEvent* te)
......@@ -1142,21 +1186,34 @@ void CdbDebugEnginePrivate::updateThreadList()
ThreadsHandler* th = m_debuggerManagerAccess->threadsHandler();
QList<ThreadData> threads;
bool success = false;
QString errorMessage;
do {
ULONG numberOfThreads;
HRESULT hr= m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads);
if (FAILED(hr)) {
errorMessage= msgComFailed("GetNumberThreads", hr);
break;
}
const ULONG maxThreadIds = 256;
ULONG threadIds[maxThreadIds];
ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
hr = m_pDebugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
if (FAILED(hr)) {
errorMessage= msgComFailed("GetThreadIdsByIndex", hr);
break;
}
for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
ThreadData thread;
thread.id = threadId;
threads.append(thread);
}
HRESULT hr;
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<Module> 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)
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -33,13 +33,16 @@
#include <windows.h>
#include <inc/dbgeng.h>
#include <QtCore/QObject>
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;
};
......
/**************************************************************************
**
** 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<Module> *modules, QString *errorMessage)
{
modules->clear();
ULONG loadedCount, unloadedCount;
HRESULT hr = syms->GetNumberModules(&loadedCount, &unloadedCount);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetNumberModules", hr);
return false;
}
// retrieve array of parameters
const ULONG count = loadedCount + unloadedCount;
QVector<DEBUG_MODULE_PARAMETERS> parameters(count);
DEBUG_MODULE_PARAMETERS *parmPtr = &(*parameters.begin());
memset(parmPtr, 0, sizeof(DEBUG_MODULE_PARAMETERS) * count);
hr = syms->GetModuleParameters(count, 0, 0u, parmPtr);
// E_INVALIDARG indicates 'Partial results' according to docu
if (FAILED(hr) && hr != E_INVALIDARG) {
*errorMessage= msgComFailed("GetModuleParameters", hr);
return false;
}
// fill array
const QString hexPrefix = QLatin1String("0x");
WCHAR wszBuf[MAX_PATH];
for (ULONG m = 0; m < count; m++) {
const DEBUG_MODULE_PARAMETERS &p = parameters.at(m);
if (p.Base != DEBUG_INVALID_OFFSET) { // Partial results?
Module module;
module.symbolsRead = (p.Flags & DEBUG_MODULE_USER_MODE)
&& (p.SymbolType != DEBUG_SYMTYPE_NONE);
module.startAddress = hexPrefix + QString::number(p.Base, 16);
module.endAddress = hexPrefix + QString::number((p.Base + p.Size), 16);
hr = syms ->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, m, 0, wszBuf, MAX_PATH - 1, 0);
if (FAILED(hr) && hr != E_INVALIDARG) {
*errorMessage= msgComFailed("GetModuleNameStringWide", hr);
return false;
}
module.moduleName = QString::fromUtf16(wszBuf);
modules->push_back(module);
}
}
return true;
}
}
}
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/
#ifndef CDBMODULES_H
#define CDBMODULES_H
#include <QtCore/QList>
#include <QtCore/QString>
#include <windows.h>
#include <inc/dbgeng.h>
namespace Debugger {
namespace Internal {