forked from qt-creator/qt-creator
Start stack frame context/symbol group classes for CDB
This commit is contained in:
@@ -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);
|
||||
if (!m_currentStackTrace) {
|
||||
*errorMessage = QLatin1String(msgNoStackTraceC);
|
||||
break;
|
||||
}
|
||||
|
||||
hr = m_pDebugSymbols->SetScope(0, cdbStackTrace.frames + frameIndex, NULL, 0);
|
||||
if (FAILED(hr)) {
|
||||
*errorMessage = msgComFailed("SetScope", hr);
|
||||
CdbSymbolGroupContext *sgc = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage);
|
||||
if (!sgc) {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
symParams = new DEBUG_SYMBOL_PARAMETERS[symbolCount];
|
||||
hr = pDbgSymGroup->GetSymbolParameters(0, symbolCount, symParams);
|
||||
if (FAILED(hr)) {
|
||||
*errorMessage = msgComFailed("GetSymbolParameters", hr);
|
||||
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, ¤t, &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
|
||||
|
||||
161
src/plugins/debugger/cdb/cdbstacktracecontext.cpp
Normal file
161
src/plugins/debugger/cdb/cdbstacktracecontext.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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;
|
||||
}
|
||||
// fill the DEBUG_STACK_FRAME array
|
||||
ULONG frameCount;
|
||||
CdbStackTraceContext *ctx = new CdbStackTraceContext(pDebugSystemObjects, pDebugSymbols);
|
||||
hr = pDebugControl->GetStackTrace(0, 0, 0, ctx->m_cdbFrames, CdbStackTraceContext::maxFrames, &frameCount);
|
||||
if (FAILED(hr)) {
|
||||
delete ctx;
|
||||
*errorMessage = msgComFailed("GetStackTrace", hr);
|
||||
return 0;
|
||||
}
|
||||
if (!ctx->init(frameCount, errorMessage)) {
|
||||
delete ctx;
|
||||
return 0;
|
||||
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
CdbStackTraceContext::~CdbStackTraceContext()
|
||||
{
|
||||
qDeleteAll(m_symbolContexts);
|
||||
}
|
||||
|
||||
bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessage*/)
|
||||
{
|
||||
if (debugCDB)
|
||||
qDebug() << Q_FUNC_INFO << frameCount;
|
||||
|
||||
m_symbolContexts.resize(frameCount);
|
||||
qFill(m_symbolContexts, static_cast<CdbSymbolGroupContext*>(0));
|
||||
|
||||
// Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames
|
||||
WCHAR wszBuf[MAX_PATH];
|
||||
for (ULONG i=0; i < frameCount; ++i) {
|
||||
StackFrame frame(i);
|
||||
const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset;
|
||||
frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16);
|
||||
|
||||
m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0);
|
||||
frame.function = QString::fromUtf16(wszBuf);
|
||||
|
||||
ULONG ulLine;
|
||||
ULONG ulFileNameSize;
|
||||
ULONG64 ul64Displacement;
|
||||
const HRESULT hr = m_pDebugSymbols->GetLineByOffsetWide(instructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement);
|
||||
if (SUCCEEDED(hr)) {
|
||||
frame.line = ulLine;
|
||||
frame.file = QString::fromUtf16(wszBuf, ulFileNameSize);
|
||||
}
|
||||
m_frames.push_back(frame);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupContextAt(int index, QString *errorMessage)
|
||||
{
|
||||
// Create a symbol group on demand
|
||||
if (debugCDB)
|
||||
qDebug() << Q_FUNC_INFO << index << m_symbolContexts.at(index);
|
||||
|
||||
if (index < 0 || index >= m_symbolContexts.size()) {
|
||||
*errorMessage = QString::fromLatin1("%1: Index %2 out of range %3.").
|
||||
arg(QLatin1String(Q_FUNC_INFO)).arg(index).arg(m_symbolContexts.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_symbolContexts.at(index))
|
||||
return m_symbolContexts.at(index);
|
||||
IDebugSymbolGroup2 *sg = createSymbolGroup(index, errorMessage);
|
||||
if (!sg)
|
||||
return 0;
|
||||
CdbSymbolGroupContext *sc = new CdbSymbolGroupContext(QLatin1String("local"), sg);
|
||||
m_symbolContexts[index] = sc;
|
||||
return sc;
|
||||
}
|
||||
|
||||
IDebugSymbolGroup2 *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage)
|
||||
{
|
||||
IDebugSymbolGroup2 *sg = 0;
|
||||
HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &sg);
|
||||
if (FAILED(hr)) {
|
||||
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hr = m_pDebugSymbols->SetScope(0, m_cdbFrames + index, NULL, 0);
|
||||
if (FAILED(hr)) {
|
||||
*errorMessage = msgComFailed("SetScope", hr);
|
||||
sg->Release();
|
||||
return 0;
|
||||
}
|
||||
// refresh with current frame
|
||||
hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, sg, &sg);
|
||||
if (FAILED(hr)) {
|
||||
*errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
|
||||
sg->Release();
|
||||
return 0;
|
||||
}
|
||||
return sg;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
86
src/plugins/debugger/cdb/cdbstacktracecontext.h
Normal file
86
src/plugins/debugger/cdb/cdbstacktracecontext.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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 CDBSTACKTRACECONTEXT_H
|
||||
#define CDBSTACKTRACECONTEXT_H
|
||||
|
||||
#include "stackhandler.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <inc/dbgeng.h>
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class CdbSymbolGroupContext;
|
||||
|
||||
/* Context representing a break point stack consisting of several frames.
|
||||
* Maintains an on-demand constructed list of CdbSymbolGroupContext
|
||||
* containining the local variables of the stack. */
|
||||
|
||||
class CdbStackTraceContext
|
||||
{
|
||||
Q_DISABLE_COPY(CdbStackTraceContext)
|
||||
|
||||
explicit CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects,
|
||||
IDebugSymbols3* pDebugSymbols);
|
||||
public:
|
||||
enum { maxFrames = 100 };
|
||||
|
||||
~CdbStackTraceContext();
|
||||
static CdbStackTraceContext *create(IDebugControl4* pDebugControl,
|
||||
IDebugSystemObjects4* pDebugSystemObjects,
|
||||
IDebugSymbols3* pDebugSymbols,
|
||||
unsigned long threadid,
|
||||
QString *errorMessage);
|
||||
|
||||
QList<StackFrame> frames() const { return m_frames; }
|
||||
inline int frameCount() const { return m_frames.size(); }
|
||||
|
||||
CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage);
|
||||
|
||||
private:
|
||||
bool init(unsigned long frameCount, QString *errorMessage);
|
||||
IDebugSymbolGroup2 *createSymbolGroup(int index, QString *errorMessage);
|
||||
|
||||
IDebugSystemObjects4* m_pDebugSystemObjects;
|
||||
IDebugSymbols3* m_pDebugSymbols;
|
||||
|
||||
DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
|
||||
QVector <CdbSymbolGroupContext*> m_symbolContexts;
|
||||
QList<StackFrame> m_frames;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CDBSTACKTRACECONTEXT_H
|
||||
177
src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
Normal file
177
src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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 "cdbsymbolgroupcontext.h"
|
||||
#include "cdbdebugengine_p.h"
|
||||
#include "watchhandler.h"
|
||||
|
||||
// A helper function to extract a string value from a member function of
|
||||
// IDebugSymbolGroup2 taking the symbol index and a character buffer.
|
||||
// Pass in the the member function as '&IDebugSymbolGroup2::GetSymbolNameWide'
|
||||
|
||||
typedef HRESULT (__stdcall IDebugSymbolGroup2::*WideStringRetrievalFunction)(ULONG, PWSTR, ULONG, PULONG);
|
||||
|
||||
static inline QString getSymbolString(IDebugSymbolGroup2 *sg,
|
||||
WideStringRetrievalFunction wsf,
|
||||
unsigned long index)
|
||||
{
|
||||
static WCHAR nameBuffer[MAX_PATH + 1];
|
||||
// Name
|
||||
ULONG nameLength;
|
||||
const HRESULT hr = (sg->*wsf)(index, nameBuffer, MAX_PATH, &nameLength);
|
||||
if (SUCCEEDED(hr)) {
|
||||
nameBuffer[nameLength] = 0;
|
||||
return QString::fromUtf16(nameBuffer);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
CdbSymbolGroupContext::CdbSymbolGroupContext(const QString &prefix,
|
||||
IDebugSymbolGroup2 *symbolGroup) :
|
||||
m_prefix(prefix),
|
||||
m_nameDelimiter(QLatin1Char('.')),
|
||||
m_symbolGroup(symbolGroup)
|
||||
{
|
||||
}
|
||||
|
||||
CdbSymbolGroupContext::~CdbSymbolGroupContext()
|
||||
{
|
||||
m_symbolGroup->Release();
|
||||
}
|
||||
|
||||
CdbSymbolGroupContext::Range
|
||||
CdbSymbolGroupContext::getSymbolRange(const QString &prefix)
|
||||
{
|
||||
if (debugCDB)
|
||||
qDebug() << Q_FUNC_INFO << prefix;
|
||||
const ChildRangeMap::const_iterator it = m_childRanges.constFind(prefix);
|
||||
if (it != m_childRanges.constEnd())
|
||||
return it.value();
|
||||
const Range r = prefix == m_prefix ? allocateRootSymbols() : allocateChildSymbols(prefix);
|
||||
m_childRanges.insert(prefix, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
CdbSymbolGroupContext::Range
|
||||
CdbSymbolGroupContext::allocateChildSymbols(const QString &prefix)
|
||||
{
|
||||
unsigned long startPos = 0;
|
||||
unsigned long count = 0;
|
||||
|
||||
bool success = false;
|
||||
QString errorMessage;
|
||||
do {
|
||||
const int parentIndex = m_symbolINames.indexOf(prefix);
|
||||
if (parentIndex == -1) {
|
||||
errorMessage = QString::fromLatin1("Prefix not found '%1'").arg(prefix);
|
||||
break;
|
||||
}
|
||||
|
||||
success = true;
|
||||
} while (false);
|
||||
if (!success) {
|
||||
qWarning("%s\n", qPrintable(errorMessage));
|
||||
}
|
||||
return Range(startPos, count);
|
||||
}
|
||||
|
||||
CdbSymbolGroupContext::Range
|
||||
CdbSymbolGroupContext::allocateRootSymbols()
|
||||
{
|
||||
unsigned long startPos = 0;
|
||||
unsigned long count = 0;
|
||||
bool success = false;
|
||||
|
||||
QString errorMessage;
|
||||
do {
|
||||
HRESULT hr = m_symbolGroup->GetNumberSymbols(&count);
|
||||
if (FAILED(hr)) {
|
||||
errorMessage = msgComFailed("GetNumberSymbols", hr);
|
||||
break;
|
||||
}
|
||||
|
||||
m_symbolParameters.reserve(3u * count);
|
||||
m_symbolParameters.resize(count);
|
||||
|
||||
hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters());
|
||||
if (FAILED(hr)) {
|
||||
errorMessage = msgComFailed("GetSymbolParameters", hr);
|
||||
break;
|
||||
}
|
||||
const QString symbolPrefix = m_prefix + m_nameDelimiter;
|
||||
for (unsigned long i = 0; i < count; i++)
|
||||
m_symbolINames.push_back(symbolPrefix + getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i));
|
||||
|
||||
success = true;
|
||||
} while (false);
|
||||
if (!success) {
|
||||
clear();
|
||||
count = 0;
|
||||
qWarning("%s\n", qPrintable(errorMessage));
|
||||
}
|
||||
return Range(startPos, count);
|
||||
}
|
||||
|
||||
void CdbSymbolGroupContext::clear()
|
||||
{
|
||||
m_symbolParameters.clear();
|
||||
m_childRanges.clear();
|
||||
m_symbolINames.clear();
|
||||
}
|
||||
|
||||
WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const
|
||||
{
|
||||
if (debugCDB)
|
||||
qDebug() << Q_FUNC_INFO << index;
|
||||
|
||||
WatchData wd;
|
||||
wd.iname = m_symbolINames.at(index);
|
||||
const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter);
|
||||
wd.name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1);
|
||||
wd.type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index);
|
||||
wd.value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
|
||||
const DEBUG_SYMBOL_PARAMETERS ¶ms = m_symbolParameters.at(index);
|
||||
if (params.SubElements) {
|
||||
wd.setTypeUnneeded();
|
||||
wd.setValueUnneeded();
|
||||
wd.setChildCount(1);
|
||||
} else {
|
||||
wd.setAllUnneeded();
|
||||
}
|
||||
if (debugCDB) {
|
||||
qDebug() << Q_FUNC_INFO << wd.toString();
|
||||
}
|
||||
return wd;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
110
src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
Normal file
110
src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** 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 CDBSYMBOLGROUPCONTEXT_H
|
||||
#define CDBSYMBOLGROUPCONTEXT_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <inc/dbgeng.h>
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QPair>
|
||||
#include <QtCore/QMap>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class WatchData;
|
||||
|
||||
/* A thin wrapper around the IDebugSymbolGroup2 interface which represents
|
||||
* a flat list of symbols using an index (for example, belonging to a stack frame).
|
||||
* It uses the hierarchical naming convention of WatchHandler as:
|
||||
* "local" (invisible root)
|
||||
* "local.string" (local class variable)
|
||||
* "local.string.data" (class member).
|
||||
* IDebugSymbolGroup2 can "expand" expandable symbols, appending to the flat list.
|
||||
*/
|
||||
|
||||
class CdbSymbolGroupContext
|
||||
{
|
||||
Q_DISABLE_COPY(CdbSymbolGroupContext);
|
||||
|
||||
// Start position and length of range in m_symbolParameters
|
||||
typedef QPair<unsigned long, unsigned long> Range;
|
||||
|
||||
public:
|
||||
explicit CdbSymbolGroupContext(const QString &prefix,
|
||||
IDebugSymbolGroup2 *symbolGroup);
|
||||
~CdbSymbolGroupContext();
|
||||
|
||||
QString prefix() const { return m_prefix; }
|
||||
|
||||
// Retrieve child symbols of prefix as a sequence of WatchData.
|
||||
template <class OutputIterator>
|
||||
void getSymbols(const QString &prefix, OutputIterator it);
|
||||
|
||||
private:
|
||||
void clear();
|
||||
Range getSymbolRange(const QString &prefix);
|
||||
Range allocateChildSymbols(const QString &prefix);
|
||||
Range allocateRootSymbols();
|
||||
WatchData symbolAt(unsigned long index) const;
|
||||
|
||||
inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
|
||||
inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); }
|
||||
|
||||
const QString m_prefix;
|
||||
const QChar m_nameDelimiter;
|
||||
IDebugSymbolGroup2 *m_symbolGroup;
|
||||
|
||||
QStringList m_symbolINames;
|
||||
QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters;
|
||||
|
||||
typedef QMap<QString, Range> ChildRangeMap;
|
||||
|
||||
ChildRangeMap m_childRanges;
|
||||
};
|
||||
|
||||
template <class OutputIterator>
|
||||
void CdbSymbolGroupContext::getSymbols(const QString &prefix, OutputIterator it)
|
||||
{
|
||||
const Range r = getSymbolRange(prefix);
|
||||
const unsigned long end = r.first + r.second;
|
||||
for (unsigned long i = r.first; i < end; i++) {
|
||||
*it = symbolAt(i);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif // CDBSYMBOLGROUPCONTEXT_H
|
||||
@@ -2447,8 +2447,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record)
|
||||
for (int i = 0; i != stack.childCount(); ++i) {
|
||||
//qDebug() << "HANDLING FRAME: " << stack.childAt(i).toString();
|
||||
const GdbMi frameMi = stack.childAt(i);
|
||||
StackFrame frame;
|
||||
frame.level = i;
|
||||
StackFrame frame(i);
|
||||
QStringList files;
|
||||
files.append(frameMi.findChild("fullname").data());
|
||||
files.append(frameMi.findChild("file").data());
|
||||
@@ -2488,8 +2487,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record)
|
||||
if (0 && topFrame != -1) {
|
||||
// updates of locals already triggered early
|
||||
const StackFrame &frame = qq->stackHandler()->currentFrame();
|
||||
bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
|
||||
if (usable)
|
||||
if (frame.isUsable())
|
||||
q->gotoLocation(frame.file, frame.line, true);
|
||||
else
|
||||
qDebug() << "FULL NAME NOT USABLE 0: " << frame.file;
|
||||
@@ -2500,8 +2498,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record)
|
||||
if (topFrame != -1) {
|
||||
// updates of locals already triggered early
|
||||
const StackFrame &frame = qq->stackHandler()->currentFrame();
|
||||
bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
|
||||
if (usable)
|
||||
if (frame.isUsable())
|
||||
q->gotoLocation(frame.file, frame.line, true);
|
||||
else
|
||||
qDebug() << "FULL NAME NOT USABLE 0: " << frame.file << topFrame;
|
||||
@@ -2551,8 +2548,7 @@ void GdbEngine::activateFrame(int frameIndex)
|
||||
|
||||
const StackFrame &frame = stackHandler->currentFrame();
|
||||
|
||||
bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
|
||||
if (usable)
|
||||
if (frame.isUsable())
|
||||
q->gotoLocation(frame.file, frame.line, true);
|
||||
else
|
||||
qDebug() << "FULL NAME NOT USABLE: " << frame.file;
|
||||
|
||||
@@ -37,6 +37,16 @@
|
||||
|
||||
using namespace Debugger::Internal;
|
||||
|
||||
StackFrame::StackFrame(int l) :
|
||||
level(l),
|
||||
line(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool StackFrame::isUsable() const
|
||||
{
|
||||
return !file.isEmpty() && QFileInfo(file).isReadable();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
@@ -46,6 +46,9 @@ namespace Internal {
|
||||
|
||||
struct StackFrame
|
||||
{
|
||||
StackFrame(int level = 0);
|
||||
bool isUsable() const;
|
||||
|
||||
int level;
|
||||
QString function;
|
||||
QString file; // we try to put an absolute file name in there
|
||||
|
||||
Reference in New Issue
Block a user