Commit 145c1fb9 authored by dt's avatar dt
Browse files

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

parents 0a2df326 8ba891bb
......@@ -260,6 +260,7 @@ void CMakeProject::parseCMakeLists()
QString CMakeProject::buildParser(const QString &buildConfiguration) const
{
Q_UNUSED(buildConfiguration);
// TODO this is actually slightly wrong, but do i care?
// this should call toolchain(buildConfiguration)
if (!m_toolChain)
......
......@@ -238,16 +238,27 @@ void NavigationWidget::saveSettings(QSettings *settings)
void NavigationWidget::restoreSettings(QSettings *settings)
{
if (settings->contains("Navigation/Views")) {
QStringList views = settings->value("Navigation/Views").toStringList();
for (int i=0; i<views.count()-1; ++i) {
insertSubItem(0);
}
for (int i=0; i<views.count(); ++i) {
const QString &view = views.at(i);
NavigationSubWidget *nsw = m_subWidgets.at(i);
nsw->setFactory(view);
int version = settings->value("Navigation/Version", 1).toInt();
QStringList views = settings->value("Navigation/Views").toStringList();
bool restoreSplitterState = true;
if (version == 1) {
if (views.isEmpty())
views += "Projects";
if (!views.contains("Open Documents")) {
views += "Open Documents";
restoreSplitterState = false;
}
settings->setValue("Navigation/Version", 2);
}
for (int i=0; i<views.count()-1; ++i) {
insertSubItem(0);
}
for (int i=0; i<views.count(); ++i) {
const QString &view = views.at(i);
NavigationSubWidget *nsw = m_subWidgets.at(i);
nsw->setFactory(view);
}
if (settings->contains("Navigation/Visible")) {
......@@ -256,8 +267,15 @@ void NavigationWidget::restoreSettings(QSettings *settings)
setShown(true);
}
if (settings->contains("Navigation/VerticalPosition"))
if (restoreSplitterState && settings->contains("Navigation/VerticalPosition")) {
restoreState(settings->value("Navigation/VerticalPosition").toByteArray());
} else {
QList<int> sizes;
sizes += 256;
for (int i = views.size()-1; i; --i)
sizes.prepend(512);
setSizes(sizes);
}
if (settings->contains("Navigation/Width")) {
m_width = settings->value("Navigation/Width").toInt();
......
......@@ -1209,10 +1209,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
if (Function *function = symbol->type()->asFunctionType()) {
// If the member is a function, automatically place the opening parenthesis,
// except when it might take template parameters.
const bool hasReturnType = function->returnType().isValid() ||
function->returnType().isSigned() ||
function->returnType().isUnsigned();
if (! hasReturnType && (function->identity() && !function->identity()->isDestructorNameId())) {
if (! function->hasReturnType() && (function->identity() && !function->identity()->isDestructorNameId())) {
// Don't insert any magic, since the user might have just wanted to select the class
} else if (function->templateParameterCount() != 0) {
......@@ -1224,8 +1221,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
extraChars += QLatin1Char('(');
// If the function takes no arguments, automatically place the closing parenthesis
if (function->argumentCount() == 0 || (function->argumentCount() == 1 &&
function->argumentAt(0)->type()->isVoidType())) {
if (item.m_duplicateCount == 0 && ! function->hasArguments()) {
extraChars += QLatin1Char(')');
// If the function doesn't return anything, automatically place the semicolon,
......
......@@ -22,12 +22,16 @@ HEADERS += \
$$PWD/cdbdebugengine.h \
$$PWD/cdbdebugengine_p.h \
$$PWD/cdbdebugeventcallback.h \
$$PWD/cdbdebugoutput.h
$$PWD/cdbdebugoutput.h \
$$PWD/cdbsymbolgroupcontext.h \
$$PWD/cdbstacktracecontext.h
SOURCES += \
$$PWD/cdbdebugengine.cpp \
$$PWD/cdbdebugeventcallback.cpp \
$$PWD/cdbdebugoutput.cpp
$$PWD/cdbdebugoutput.cpp \
$$PWD/cdbsymbolgroupcontext.cpp \
$$PWD/cdbstacktracecontext.cpp
} else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
}
......
......@@ -29,6 +29,8 @@
#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
#include "cdbsymbolgroupcontext.h"
#include "cdbstacktracecontext.h"
#include "debuggermanager.h"
#include "breakhandler.h"
......@@ -55,7 +57,12 @@
static const char *dbgEngineDllC = "dbgeng";
static const char *debugCreateFuncC = "DebugCreate";
static QString msgDebugEngineComResult(HRESULT hr)
static const char *localSymbolRootC = "local";
namespace Debugger {
namespace Internal {
QString msgDebugEngineComResult(HRESULT hr)
{
switch (hr) {
case S_OK:
......@@ -87,13 +94,12 @@ static QString msgStackIndexOutOfRange(int idx, int size)
return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
}
static QString msgComFailed(const char *func, HRESULT hr)
QString msgComFailed(const char *func, HRESULT hr)
{
return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
}
namespace Debugger {
namespace Internal {
static const char *msgNoStackTraceC = "Internal error: no stack trace present.";
DebuggerEngineLibrary::DebuggerEngineLibrary() :
m_debugCreate(0)
......@@ -138,6 +144,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn
m_engine(engine),
m_debuggerManager(parent),
m_debuggerManagerAccess(parent->engineInterface()),
m_currentStackTrace(0),
m_mode(AttachCore)
{
}
......@@ -205,6 +212,7 @@ IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent)
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
{
cleanStackTrace();
if (m_pDebugClient)
m_pDebugClient->Release();
if (m_pDebugControl)
......@@ -217,6 +225,17 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
m_pDebugRegisters->Release();
}
void CdbDebugEnginePrivate::cleanStackTrace()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
if (m_currentStackTrace) {
delete m_currentStackTrace;
m_currentStackTrace = 0;
}
}
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) :
IDebuggerEngine(parent),
m_d(new CdbDebugEnginePrivate(parent, this))
......@@ -366,6 +385,7 @@ void CdbDebugEngine::processTerminated(unsigned long exitCode)
if (debugCDB)
qDebug() << Q_FUNC_INFO << exitCode;
m_d->cleanStackTrace();
m_d->setDebuggeeHandles(0, 0);
m_d->m_debuggerManagerAccess->notifyInferiorExited();
m_d->m_debuggerManager->exitDebugger();
......@@ -377,6 +397,7 @@ void CdbDebugEngine::exitDebugger()
qDebug() << Q_FUNC_INFO;
if (m_d->m_hDebuggeeProcess) {
m_d->cleanStackTrace();
// Terminate or detach if we are running
HRESULT hr;
switch (m_d->m_mode) {
......@@ -407,47 +428,22 @@ void CdbDebugEngine::exitDebugger()
killWatchTimer();
}
// Retrieve a symbol
static WatchData symbolToWatchData(ULONG index, const QString &namePrefix,
IDebugSymbolGroup2 *pDbgSymGroup)
class ModelBuildIterator {
public:
explicit ModelBuildIterator(WatchHandler *wh) : m_wh(wh) {}
ModelBuildIterator & operator*() { return *this; }
ModelBuildIterator &operator=(const WatchData &wd);
ModelBuildIterator &operator++() { return *this; }
private:
WatchHandler *m_wh;
};
ModelBuildIterator &ModelBuildIterator::operator=(const WatchData &wd)
{
// retrieve symbol names and value strings
ULONG nameLength;
static WCHAR nameBuffer[MAX_PATH + 1];
// Name
pDbgSymGroup->GetSymbolNameWide(index, nameBuffer, MAX_PATH, &nameLength);
nameBuffer[nameLength] = 0;
const QString name = QString::fromUtf16(nameBuffer);
// Type name
pDbgSymGroup->GetSymbolTypeNameWide(index, nameBuffer, MAX_PATH, &nameLength);
nameBuffer[nameLength] = 0;
const QString type = QString::fromUtf16(nameBuffer);
// Value
QString value;
const HRESULT hr = pDbgSymGroup->GetSymbolValueTextWide(index, nameBuffer, MAX_PATH, &nameLength);
if (SUCCEEDED(hr)) {
nameBuffer[nameLength] = 0;
value = QString::fromUtf16(nameBuffer);
} else {
value = QLatin1String("<unknown>");
}
WatchData wd;
wd.iname =namePrefix + name;
wd.name = name;
wd.value = value;
wd.type = type;
if (isPointerType(type)) {
wd.setTypeUnneeded();
wd.setValueUnneeded();
} else {
wd.setAllUnneeded();
}
if (debugCDB) {
qDebug() << Q_FUNC_INFO << index << "state=0x" << QString::number(wd.state, 16)
<< wd.name << " type=" << wd.type << " (" << type << ')'
<< " value " << wd.value << " (" << value << ')';
}
return wd;
m_wh->insertData(wd);
return *this;
}
bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
......@@ -456,82 +452,36 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << frameIndex;
CdbStackTrace cdbStackTrace;
if (!getCdbStrackTrace(&cdbStackTrace, errorMessage))
return false;
if ((unsigned)frameIndex >= cdbStackTrace.frameCount) {
*errorMessage = msgStackIndexOutOfRange(frameIndex, cdbStackTrace.frameCount);
return false;
}
IDebugSymbolGroup2 *pDbgSymGroup = 0;
DEBUG_SYMBOL_PARAMETERS *symParams = 0;
bool success = false;
wh->cleanup();
do {
HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &pDbgSymGroup);
if (FAILED(hr)) {
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
break;
}
hr = m_pDebugSymbols->SetScope(0, cdbStackTrace.frames + frameIndex, NULL, 0);
if (FAILED(hr)) {
*errorMessage = msgComFailed("SetScope", hr);
break;
}
// refresh with current frame
hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, pDbgSymGroup, &pDbgSymGroup);
if (FAILED(hr)) {
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
break;
}
ULONG symbolCount;
hr = pDbgSymGroup->GetNumberSymbols(&symbolCount);
if (FAILED(hr)) {
*errorMessage = msgComFailed("GetNumberSymbols", hr);
if (!m_currentStackTrace) {
*errorMessage = QLatin1String(msgNoStackTraceC);
break;
}
symParams = new DEBUG_SYMBOL_PARAMETERS[symbolCount];
hr = pDbgSymGroup->GetSymbolParameters(0, symbolCount, symParams);
if (FAILED(hr)) {
*errorMessage = msgComFailed("GetSymbolParameters", hr);
CdbSymbolGroupContext *sgc = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage);
if (!sgc) {
break;
}
wh->cleanup();
// retrieve symbol names and value strings.
// Add a dummy place holder in case children are needed
const QString localPrefix = QLatin1String("local.");
for (ULONG s = 0 ; s < symbolCount ; s++ ) {
WatchData wd = symbolToWatchData(s, localPrefix, pDbgSymGroup);
if (wd.isSomethingNeeded()) {
wh->insertData(wd.pointerChildPlaceHolder());
wd.setAllUnneeded();
wd.setChildCount(1);
}
wh->insertData(wd);
}
wh->rebuildModel();
ModelBuildIterator it(wh);
sgc->getSymbols(sgc->prefix(), it);
success = true;
} while (false);
wh->rebuildModel();
delete [] symParams;
if (pDbgSymGroup)
pDbgSymGroup->Release();
return success;
}
void CdbDebugEngine::updateWatchModel()
{
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
const QList<WatchData> incomplete = watchHandler->takeCurrentIncompletes();
if (debugCDB)
qDebug() << Q_FUNC_INFO << incomplete.size();
foreach (const WatchData& wd, incomplete)
qDebug() << Q_FUNC_INFO << wd.toString();
}
void CdbDebugEngine::stepExec()
......@@ -540,8 +490,9 @@ void CdbDebugEngine::stepExec()
qDebug() << Q_FUNC_INFO;
//m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
HRESULT hr;
hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
m_d->cleanStackTrace();
const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
Q_UNUSED(hr)
m_d->m_bIgnoreNextDebugEvent = true;
startWatchTimer();
}
......@@ -594,6 +545,7 @@ void CdbDebugEngine::nextExec()
if (debugCDB)
qDebug() << Q_FUNC_INFO;
m_d->cleanStackTrace();
const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
if (SUCCEEDED(hr)) {
startWatchTimer();
......@@ -612,6 +564,7 @@ void CdbDebugEngine::nextIExec()
if (debugCDB)
qDebug() << Q_FUNC_INFO;
m_d->cleanStackTrace();
const HRESULT hr = m_d->m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
if (SUCCEEDED(hr)) {
startWatchTimer();
......@@ -625,6 +578,7 @@ void CdbDebugEngine::continueInferior()
if (debugCDB)
qDebug() << Q_FUNC_INFO;
m_d->cleanStackTrace();
killWatchTimer();
m_d->m_debuggerManager->resetLocation();
......@@ -714,7 +668,7 @@ void CdbDebugEngine::activateFrame(int frameIndex)
}
const StackFrame &frame = stackHandler->currentFrame();
if (frame.file.isEmpty() || !QFileInfo(frame.file).isReadable()) {
if (!frame.isUsable()) {
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
arg(QLatin1String(Q_FUNC_INFO), frame.file);
break;
......@@ -933,78 +887,29 @@ void CdbDebugEnginePrivate::updateThreadList()
th->setThreads(threads);
}
// Get CDB stack trace
bool CdbDebugEnginePrivate::getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage)
{
HRESULT hr = m_pDebugSystemObjects->SetCurrentThreadId(m_currentThreadId);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3").
arg(QString::fromLatin1(Q_FUNC_INFO)).
arg(m_currentThreadId).
arg(msgDebugEngineComResult(hr));
return false;
}
hr = m_pDebugControl->GetStackTrace(0, 0, 0, st->frames, CdbStackTrace::maxFrames, &(st->frameCount));
if (FAILED(hr)) {
*errorMessage = *errorMessage = msgComFailed("GetStackTrace", hr);
return false;
}
return true;
}
bool CdbDebugEnginePrivate::getStackTrace(QList<StackFrame> *stackFrames,
int *current, QString *errorMessage)
{
stackFrames->clear();
*current = -1;
// Get the CDB trace and convert into debugger plugin structures
CdbStackTrace cdbStackTrace;
if (!getCdbStrackTrace(&cdbStackTrace, errorMessage))
return false;
WCHAR wszBuf[MAX_PATH];
for (ULONG i=0; i < cdbStackTrace.frameCount; ++i) {
StackFrame frame;
frame.line = 0;
frame.level = i;
frame.address = QString::fromLatin1("0x%1").arg(cdbStackTrace.frames[i].InstructionOffset, 0, 16);
m_pDebugSymbols->GetNameByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
frame.function = QString::fromUtf16(wszBuf);
ULONG ulLine;
ULONG ulFileNameSize;
ULONG64 ul64Displacement;
const HRESULT hr = m_pDebugSymbols->GetLineByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement);
if (SUCCEEDED(hr)) {
frame.line = ulLine;
frame.file = QString::fromUtf16(wszBuf, ulFileNameSize);
}
stackFrames->append(frame);
}
// find the first usable frame and select it
const int count = stackFrames->count();
for (int i=0; i < count; ++i) {
const StackFrame &frame = stackFrames->at(i);
const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
if (usable) {
*current = i;
break;
}
}
return true;
}
void CdbDebugEnginePrivate::updateStackTrace()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
QList<StackFrame> stackFrames;
int current;
// Create a new context
cleanStackTrace();
QString errorMessage;
if (getStackTrace(&stackFrames, &current, &errorMessage))
qWarning("%s", qPrintable(errorMessage));
m_currentStackTrace =
CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects,
m_pDebugSymbols, m_currentThreadId, &errorMessage);
if (!m_currentStackTrace) {
qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
return;
}
const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
// find the first usable frame and select it
int current = -1;
const int count = stackFrames.count();
for (int i=0; i < count; ++i)
if (stackFrames.at(i).isUsable()) {
current = i;
break;
}
m_debuggerManagerAccess->stackHandler()->setFrames(stackFrames);
if (current >= 0) {
......
......@@ -42,6 +42,8 @@ namespace Internal {
class DebuggerManager;
class IDebuggerManagerAccessForEngines;
class WatchHandler;
class CdbSymbolGroupContext;
class CdbStackTraceContext;
// Thin wrapper around the 'DBEng' debugger engine shared library
// which is loaded at runtime.
......@@ -61,16 +63,6 @@ private:
DebugCreateFunction m_debugCreate;
};
// Helper struct for stack traces
struct CdbStackTrace {
CdbStackTrace() : frameCount(0) {}
enum { maxFrames = 100 };
ULONG frameCount;
DEBUG_STACK_FRAME frames[maxFrames];
};
struct CdbDebugEnginePrivate
{
explicit CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine);
......@@ -84,10 +76,9 @@ struct CdbDebugEnginePrivate
void updateThreadList();
void updateStackTrace();
bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage);
bool getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage);
bool getStackTrace(QList<StackFrame> *stackFrames, int *current, QString *errorMessage);
void handleDebugOutput(const char* szOutputString);
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
void cleanStackTrace();
HANDLE m_hDebuggeeProcess;
HANDLE m_hDebuggeeThread;
......@@ -106,10 +97,16 @@ struct CdbDebugEnginePrivate
CdbDebugEngine* m_engine;
DebuggerManager *m_debuggerManager;
IDebuggerManagerAccessForEngines *m_debuggerManagerAccess;
CdbStackTraceContext *m_currentStackTrace;
DebuggerStartMode m_mode;
Core::Utils::ConsoleProcess m_consoleStubProc;
};
// Message
QString msgDebugEngineComResult(HRESULT hr);
QString msgComFailed(const char *func, HRESULT hr);
enum { debugCDB = 0 };
} // namespace Internal
......
/**************************************************************************
**
** 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 "cdbstacktracecontext.h"
#include "cdbsymbolgroupcontext.h"
#include "cdbdebugengine_p.h"
namespace Debugger {
namespace Internal {
CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects,
IDebugSymbols3* pDebugSymbols) :
m_pDebugSystemObjects(pDebugSystemObjects),
m_pDebugSymbols(pDebugSymbols)
{
}
CdbStackTraceContext *CdbStackTraceContext::create(IDebugControl4* pDebugControl,
IDebugSystemObjects4* pDebugSystemObjects,
IDebugSymbols3* pDebugSymbols,
unsigned long threadId,
QString *errorMessage)
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << threadId;
HRESULT hr = pDebugSystemObjects->SetCurrentThreadId(threadId);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3").
arg(QString::fromLatin1(Q_FUNC_INFO)).
arg(threadId).
arg(msgDebugEngineComResult(hr));
return 0;