forked from qt-creator/qt-creator
Debugger: Make threads tooltip more verbose
CDB: Add more information and state to Thread. Refactor thread information in CdbCore classes to prepare for more information.
This commit is contained in:
@@ -194,6 +194,7 @@ void CdbDebugEnginePrivate::clearForRun()
|
|||||||
cleanStackTrace();
|
cleanStackTrace();
|
||||||
m_stoppedReason = StoppedOther;
|
m_stoppedReason = StoppedOther;
|
||||||
m_stoppedMessage.clear();
|
m_stoppedMessage.clear();
|
||||||
|
m_engine->threadsHandler()->notifyRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CdbDebugEnginePrivate::cleanStackTrace()
|
void CdbDebugEnginePrivate::cleanStackTrace()
|
||||||
@@ -1331,7 +1332,13 @@ void CdbDebugEnginePrivate::handleDebugEvent()
|
|||||||
if (m_engine->state() != InferiorStopping)
|
if (m_engine->state() != InferiorStopping)
|
||||||
m_engine->setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
|
m_engine->setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
|
||||||
m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
|
m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
|
||||||
m_eventThreadId = updateThreadList();
|
// Indicate artifical thread that is created when interrupting as such,
|
||||||
|
// else use stop message with cleaned newlines and blanks.
|
||||||
|
const QString currentThreadState =
|
||||||
|
m_interrupted ? CdbDebugEngine::tr("<interrupt thread>") :
|
||||||
|
(m_stoppedReason == StoppedBreakpoint ? CdbDebugEngine::tr("Breakpoint") :
|
||||||
|
m_stoppedMessage.simplified() );
|
||||||
|
m_eventThreadId = updateThreadList(currentThreadState);
|
||||||
m_interruptArticifialThreadId = m_interrupted ? m_eventThreadId : -1;
|
m_interruptArticifialThreadId = m_interrupted ? m_eventThreadId : -1;
|
||||||
// Get thread to stop and its index. If avoidable, do not use
|
// Get thread to stop and its index. If avoidable, do not use
|
||||||
// the artifical thread that is created when interrupting,
|
// the artifical thread that is created when interrupting,
|
||||||
@@ -1406,7 +1413,7 @@ bool CdbDebugEnginePrivate::setCDBThreadId(unsigned long threadId, QString *erro
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG CdbDebugEnginePrivate::updateThreadList()
|
ULONG CdbDebugEnginePrivate::updateThreadList(const QString ¤tThreadState)
|
||||||
{
|
{
|
||||||
if (debugCDB)
|
if (debugCDB)
|
||||||
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
|
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
|
||||||
@@ -1415,8 +1422,23 @@ ULONG CdbDebugEnginePrivate::updateThreadList()
|
|||||||
ULONG currentThreadId;
|
ULONG currentThreadId;
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
// When interrupting, an artifical thread with a breakpoint is created.
|
// When interrupting, an artifical thread with a breakpoint is created.
|
||||||
if (!CdbStackTraceContext::getThreads(interfaces(), &threads, ¤tThreadId, &errorMessage))
|
const bool stopped = m_engine->state() == InferiorStopped;
|
||||||
|
if (!CdbStackTraceContext::getThreads(interfaces(),
|
||||||
|
stopped,
|
||||||
|
&threads, ¤tThreadId,
|
||||||
|
&errorMessage))
|
||||||
m_engine->warning(errorMessage);
|
m_engine->warning(errorMessage);
|
||||||
|
// Indicate states 'stopped' or current thread state.
|
||||||
|
// Do not indicate 'running' since we can't know if it is suspended.
|
||||||
|
if (stopped) {
|
||||||
|
const QString state = CdbDebugEngine::tr("stopped");
|
||||||
|
const bool hasCurrentState = !currentThreadState.isEmpty();
|
||||||
|
const int count = threads.size();
|
||||||
|
for (int i= 0; i < count; i++) {
|
||||||
|
threads[i].state = hasCurrentState && threads.at(i).id == currentThreadId ?
|
||||||
|
currentThreadState : state;
|
||||||
|
}
|
||||||
|
}
|
||||||
m_engine->threadsHandler()->setThreads(threads);
|
m_engine->threadsHandler()->setThreads(threads);
|
||||||
return currentThreadId;
|
return currentThreadId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public:
|
|||||||
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
|
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
|
||||||
|
|
||||||
bool isDebuggeeRunning() const { return isWatchTimerRunning(); }
|
bool isDebuggeeRunning() const { return isWatchTimerRunning(); }
|
||||||
ULONG updateThreadList();
|
ULONG updateThreadList(const QString ¤tThreadState = QString());
|
||||||
bool setCDBThreadId(unsigned long threadId, QString *errorMessage);
|
bool setCDBThreadId(unsigned long threadId, QString *errorMessage);
|
||||||
void updateStackTrace();
|
void updateStackTrace();
|
||||||
void updateModules();
|
void updateModules();
|
||||||
|
|||||||
@@ -115,32 +115,45 @@ QList<StackFrame> CdbStackTraceContext::stackFrames() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CdbStackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
|
bool CdbStackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
|
||||||
|
bool stopped,
|
||||||
Threads *threads,
|
Threads *threads,
|
||||||
ULONG *currentThreadId,
|
ULONG *currentThreadId,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
QVector<CdbCore::Thread> coreThreads;
|
||||||
|
if (!CdbCore::StackTraceContext::getThreadList(cif, &coreThreads, currentThreadId, errorMessage))
|
||||||
|
return false;
|
||||||
|
// Get frames only if stopped.
|
||||||
|
QVector<CdbCore::StackFrame> frames;
|
||||||
|
if (stopped)
|
||||||
|
if (!CdbCore::StackTraceContext::getStoppedThreadFrames(cif, *currentThreadId,
|
||||||
|
coreThreads, &frames, errorMessage))
|
||||||
|
return false;
|
||||||
// Convert from Core data structures
|
// Convert from Core data structures
|
||||||
threads->clear();
|
threads->clear();
|
||||||
ThreadIdFrameMap threadMap;
|
const int count = coreThreads.size();
|
||||||
if (!CdbCore::StackTraceContext::getThreads(cif, &threadMap,
|
if (!count)
|
||||||
currentThreadId, errorMessage))
|
return true;
|
||||||
return false;
|
threads->reserve(count);
|
||||||
const QChar slash = QLatin1Char('/');
|
const QChar slash(QLatin1Char('/'));
|
||||||
const ThreadIdFrameMap::const_iterator cend = threadMap.constEnd();
|
for (int i = 0; i < count; i++) {
|
||||||
for (ThreadIdFrameMap::const_iterator it = threadMap.constBegin(); it != cend; ++it) {
|
const CdbCore::Thread &coreThread = coreThreads.at(i);
|
||||||
ThreadData data(it.key());
|
ThreadData data(coreThread.id);
|
||||||
const CdbCore::StackFrame &coreFrame = it.value();
|
data.targetId = QLatin1String("0x") + QString::number(coreThread.systemId);
|
||||||
|
if (stopped) {
|
||||||
|
const CdbCore::StackFrame &coreFrame = frames.at(i);
|
||||||
data.address = coreFrame.address;
|
data.address = coreFrame.address;
|
||||||
data.function = coreFrame.function;
|
data.function = coreFrame.function;
|
||||||
data.lineNumber = coreFrame.line;
|
data.lineNumber = coreFrame.line;
|
||||||
// Basename only for brevity
|
// Basename only for brevity
|
||||||
const int slashPos = coreFrame.fileName.lastIndexOf(slash);
|
const int slashPos = coreFrame.fileName.lastIndexOf(slash);
|
||||||
data.fileName = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1);
|
data.fileName = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1);
|
||||||
|
}
|
||||||
threads->push_back(data);
|
threads->push_back(data);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ public:
|
|||||||
|
|
||||||
// get threads in stopped state
|
// get threads in stopped state
|
||||||
static bool getThreads(const CdbCore::ComInterfaces &cif,
|
static bool getThreads(const CdbCore::ComInterfaces &cif,
|
||||||
|
bool stopped,
|
||||||
Threads *threads,
|
Threads *threads,
|
||||||
ULONG *currentThreadId,
|
ULONG *currentThreadId,
|
||||||
QString *errorMessage);
|
QString *errorMessage);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtCore/QTextStream>
|
#include <QtCore/QTextStream>
|
||||||
|
#include <QtCore/QScopedArrayPointer>
|
||||||
|
|
||||||
enum { debug = 0 };
|
enum { debug = 0 };
|
||||||
|
|
||||||
@@ -74,6 +75,27 @@ void StackFrame::format(QTextStream &str) const
|
|||||||
str.setIntegerBase(10);
|
str.setIntegerBase(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Thread::Thread(unsigned long i, unsigned long si) :
|
||||||
|
id(i), systemId(si), dataOffset(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Thread::toString() const
|
||||||
|
{
|
||||||
|
QString rc;
|
||||||
|
QTextStream str(&rc);
|
||||||
|
str << "Thread id " << id << " System id " << systemId << " Data at 0x";
|
||||||
|
str.setIntegerBase(16);
|
||||||
|
str << dataOffset;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug d, const Thread &t)
|
||||||
|
{
|
||||||
|
d.nospace() << t.toString();
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for special functions
|
// Check for special functions
|
||||||
StackTraceContext::SpecialFunction StackTraceContext::specialFunction(const QString &module,
|
StackTraceContext::SpecialFunction StackTraceContext::specialFunction(const QString &module,
|
||||||
const QString &function)
|
const QString &function)
|
||||||
@@ -347,20 +369,21 @@ static inline QString msgGetThreadsFailed(const QString &why)
|
|||||||
return QString::fromLatin1("Unable to determine the thread information: %1").arg(why);
|
return QString::fromLatin1("Unable to determine the thread information: %1").arg(why);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StackTraceContext::getThreadIds(const CdbCore::ComInterfaces &cif,
|
bool StackTraceContext::getThreadList(const CdbCore::ComInterfaces &cif,
|
||||||
QVector<ULONG> *threadIds,
|
QVector<Thread> *threads,
|
||||||
ULONG *currentThreadId,
|
ULONG *currentThreadId,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
threadIds->clear();
|
threads->clear();
|
||||||
ULONG threadCount;
|
ULONG threadCount;
|
||||||
*currentThreadId = 0;
|
*currentThreadId = 0;
|
||||||
|
// Get count
|
||||||
HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount);
|
HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetNumberThreads", hr));
|
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetNumberThreads", hr));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Get ids and index of current
|
// Get index of current
|
||||||
if (!threadCount)
|
if (!threadCount)
|
||||||
return true;
|
return true;
|
||||||
hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId);
|
hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId);
|
||||||
@@ -368,40 +391,50 @@ bool StackTraceContext::getThreadIds(const CdbCore::ComInterfaces &cif,
|
|||||||
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetCurrentThreadId", hr));
|
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetCurrentThreadId", hr));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
threadIds->resize(threadCount);
|
// Get Identifiers
|
||||||
hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds->begin()), 0);
|
threads->reserve(threadCount);
|
||||||
|
QScopedArrayPointer<ULONG> ids(new ULONG[threadCount]);
|
||||||
|
QScopedArrayPointer<ULONG> systemIds(new ULONG[threadCount]);
|
||||||
|
hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, ids.data(), systemIds.data());
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetThreadIdsByIndex", hr));
|
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetThreadIdsByIndex", hr));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Create entries
|
||||||
|
for (ULONG i= 0; i < threadCount ; i++) {
|
||||||
|
threads->push_back(Thread(ids[i], systemIds[i]));
|
||||||
|
if (ids[i] == *currentThreadId) { // More info for current
|
||||||
|
ULONG64 offset;
|
||||||
|
if (SUCCEEDED(cif.debugSystemObjects->GetCurrentThreadDataOffset(&offset)))
|
||||||
|
threads->back().dataOffset = offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
|
bool StackTraceContext::getStoppedThreadFrames(const CdbCore::ComInterfaces &cif,
|
||||||
ThreadIdFrameMap *threads,
|
ULONG currentThreadId,
|
||||||
ULONG *currentThreadId,
|
const QVector<Thread> &threads,
|
||||||
|
QVector<StackFrame> *frames,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
threads->clear();
|
frames->clear();
|
||||||
QVector<ULONG> threadIds;
|
if (threads.isEmpty())
|
||||||
if (!getThreadIds(cif, &threadIds, currentThreadId, errorMessage))
|
|
||||||
return false;
|
|
||||||
if (threadIds.isEmpty())
|
|
||||||
return true;
|
return true;
|
||||||
|
frames->reserve(threads.size());
|
||||||
|
|
||||||
const int threadCount = threadIds.size();
|
const int threadCount = threads.size();
|
||||||
for (int i = 0; i < threadCount; i++) {
|
for (int i = 0; i < threadCount; i++) {
|
||||||
const ULONG id = threadIds.at(i);
|
|
||||||
StackFrame frame;
|
StackFrame frame;
|
||||||
if (!getStoppedThreadState(cif, id, &frame, errorMessage)) {
|
if (!getStoppedThreadState(cif, threads.at(i).id, &frame, errorMessage)) {
|
||||||
qWarning("%s\n", qPrintable(*errorMessage));
|
qWarning("%s\n", qPrintable(*errorMessage));
|
||||||
errorMessage->clear();
|
errorMessage->clear();
|
||||||
}
|
}
|
||||||
threads->insert(id, frame);
|
frames->append(frame);
|
||||||
}
|
}
|
||||||
// Restore thread id
|
// Restore thread id
|
||||||
if (threadIds.back() != *currentThreadId) {
|
if (threads.back().id != currentThreadId) {
|
||||||
const HRESULT hr = cif.debugSystemObjects->SetCurrentThreadId(*currentThreadId);
|
const HRESULT hr = cif.debugSystemObjects->SetCurrentThreadId(currentThreadId);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("SetCurrentThreadId", hr));
|
*errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("SetCurrentThreadId", hr));
|
||||||
return false;
|
return false;
|
||||||
@@ -410,19 +443,6 @@ bool StackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString StackTraceContext::formatThreads(const ThreadIdFrameMap &threads)
|
|
||||||
{
|
|
||||||
QString rc;
|
|
||||||
QTextStream str(&rc);
|
|
||||||
const ThreadIdFrameMap::const_iterator cend = threads.constEnd();
|
|
||||||
for (ThreadIdFrameMap::const_iterator it = threads.constBegin(); it != cend; ++it) {
|
|
||||||
str << '#' << it.key() << ' ';
|
|
||||||
it.value().format(str);
|
|
||||||
str << '\n';
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug d, const StackTraceContext &t)
|
QDebug operator<<(QDebug d, const StackTraceContext &t)
|
||||||
{
|
{
|
||||||
d.nospace() << t.toString();
|
d.nospace() << t.toString();
|
||||||
|
|||||||
@@ -63,7 +63,19 @@ struct StackFrame {
|
|||||||
ULONG64 address;
|
ULONG64 address;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Thread {
|
||||||
|
explicit Thread(unsigned long id = 0, unsigned long sysId = 0);
|
||||||
|
QString toString() const;
|
||||||
|
|
||||||
|
unsigned long id;
|
||||||
|
unsigned long systemId;
|
||||||
|
quint64 dataOffset; // Only for current.
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator<(const Thread &t1, const Thread &t2) { return t1.id < t2.id; }
|
||||||
|
|
||||||
QDebug operator<<(QDebug d, const StackFrame &);
|
QDebug operator<<(QDebug d, const StackFrame &);
|
||||||
|
QDebug operator<<(QDebug d, const Thread &);
|
||||||
|
|
||||||
/* Context representing a break point stack consisting of several frames.
|
/* Context representing a break point stack consisting of several frames.
|
||||||
* Maintains an on-demand constructed list of SymbolGroupContext
|
* Maintains an on-demand constructed list of SymbolGroupContext
|
||||||
@@ -87,9 +99,6 @@ public:
|
|||||||
};
|
};
|
||||||
static SpecialFunction specialFunction(const QString &module, const QString &function);
|
static SpecialFunction specialFunction(const QString &module, const QString &function);
|
||||||
|
|
||||||
// A map of thread id, stack frame
|
|
||||||
typedef QMap<unsigned long, StackFrame> ThreadIdFrameMap;
|
|
||||||
|
|
||||||
enum { maxFrames = 100 };
|
enum { maxFrames = 100 };
|
||||||
|
|
||||||
~StackTraceContext();
|
~StackTraceContext();
|
||||||
@@ -112,8 +121,8 @@ public:
|
|||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
|
||||||
// Thread helpers: Retrieve a list of thread ids. Also works when running.
|
// Thread helpers: Retrieve a list of thread ids. Also works when running.
|
||||||
static inline bool getThreadIds(const CdbCore::ComInterfaces &cif,
|
static bool getThreadList(const CdbCore::ComInterfaces &cif,
|
||||||
QVector<ULONG> *threadIds,
|
QVector<Thread> *threads,
|
||||||
ULONG *currentThreadId,
|
ULONG *currentThreadId,
|
||||||
QString *errorMessage);
|
QString *errorMessage);
|
||||||
|
|
||||||
@@ -124,14 +133,14 @@ public:
|
|||||||
StackFrame *topFrame,
|
StackFrame *topFrame,
|
||||||
QString *errorMessage);
|
QString *errorMessage);
|
||||||
|
|
||||||
// Retrieve detailed information about all threads, works in stopped state.
|
// Get the stack traces for threads in stopped state (only, fails when running).
|
||||||
static bool getThreads(const CdbCore::ComInterfaces &cif,
|
// Potentially changes and restores current thread.
|
||||||
ThreadIdFrameMap *threads,
|
static bool getStoppedThreadFrames(const CdbCore::ComInterfaces &cif,
|
||||||
ULONG *currentThreadId,
|
ULONG currentThreadId,
|
||||||
|
const QVector<Thread> &threads,
|
||||||
|
QVector<StackFrame> *frames,
|
||||||
QString *errorMessage);
|
QString *errorMessage);
|
||||||
|
|
||||||
static QString formatThreads(const ThreadIdFrameMap &threads);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual SymbolGroupContext *createSymbolGroup(const ComInterfaces &cif,
|
virtual SymbolGroupContext *createSymbolGroup(const ComInterfaces &cif,
|
||||||
int index,
|
int index,
|
||||||
|
|||||||
@@ -2966,7 +2966,7 @@ void GdbEngine::handleThreadInfo(const GdbResponse &response)
|
|||||||
const GdbMi frame = item.findChild("frame");
|
const GdbMi frame = item.findChild("frame");
|
||||||
ThreadData thread;
|
ThreadData thread;
|
||||||
thread.id = item.findChild("id").data().toInt();
|
thread.id = item.findChild("id").data().toInt();
|
||||||
thread.targetId = item.findChild("target-id").data().toInt();
|
thread.targetId = QString::fromAscii(item.findChild("target-id").data());
|
||||||
thread.core = QString::fromLatin1(item.findChild("core").data());
|
thread.core = QString::fromLatin1(item.findChild("core").data());
|
||||||
thread.state = QString::fromLatin1(item.findChild("state").data());
|
thread.state = QString::fromLatin1(item.findChild("state").data());
|
||||||
thread.address = frame.findChild("addr").data().toULongLong(&ok, 0);
|
thread.address = frame.findChild("addr").data().toULongLong(&ok, 0);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "debuggerconstants.h"
|
#include "debuggerconstants.h"
|
||||||
#include "debuggerengine.h"
|
#include "debuggerengine.h"
|
||||||
|
|
||||||
|
#include <QtCore/QTextStream>
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -58,6 +59,56 @@ void ThreadData::notifyRunning()
|
|||||||
lineNumber = -1;
|
lineNumber = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int id;
|
||||||
|
QString targetId;
|
||||||
|
QString core;
|
||||||
|
|
||||||
|
// State information when stopped
|
||||||
|
void notifyRunning(); // Clear state information
|
||||||
|
|
||||||
|
int frameLevel;
|
||||||
|
quint64 address;
|
||||||
|
QString function;
|
||||||
|
QString fileName;
|
||||||
|
QString state;
|
||||||
|
int lineNumber;
|
||||||
|
|
||||||
|
static inline QString threadToolTip(const ThreadData &thread)
|
||||||
|
{
|
||||||
|
const char tableRowStartC[] = "<tr><td>";
|
||||||
|
const char tableRowSeparatorC[] = "</td><td>";
|
||||||
|
const char tableRowEndC[] = "</td>";
|
||||||
|
QString rc;
|
||||||
|
QTextStream str(&rc);
|
||||||
|
str << "<html><head/><body><table>"
|
||||||
|
<< tableRowStartC << ThreadsHandler::tr("Thread id:")
|
||||||
|
<< tableRowSeparatorC << thread.id << tableRowEndC;
|
||||||
|
if (!thread.targetId.isEmpty())
|
||||||
|
str << tableRowStartC << ThreadsHandler::tr("Target id:")
|
||||||
|
<< tableRowSeparatorC << thread.targetId << tableRowEndC;
|
||||||
|
if (!thread.state.isEmpty())
|
||||||
|
str << tableRowStartC << ThreadsHandler::tr("State:")
|
||||||
|
<< tableRowSeparatorC << thread.state << tableRowEndC;
|
||||||
|
if (!thread.core.isEmpty())
|
||||||
|
str << tableRowStartC << ThreadsHandler::tr("Core:")
|
||||||
|
<< tableRowSeparatorC << thread.core << tableRowEndC;
|
||||||
|
|
||||||
|
if (thread.address) {
|
||||||
|
str << tableRowStartC << ThreadsHandler::tr("Stopped at:")
|
||||||
|
<< tableRowSeparatorC;
|
||||||
|
if (!thread.function.isEmpty())
|
||||||
|
str << thread.function << "<br>";
|
||||||
|
if (!thread.fileName.isEmpty())
|
||||||
|
str << thread.fileName << ':' << thread.lineNumber << "<br>";
|
||||||
|
str.setIntegerBase(16);
|
||||||
|
str << "0x" << thread.address;
|
||||||
|
str.setIntegerBase(10);
|
||||||
|
}
|
||||||
|
str << "</table></body></html>";
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// ThreadsHandler
|
// ThreadsHandler
|
||||||
@@ -92,7 +143,8 @@ QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
const ThreadData &thread = m_threads.at(row);
|
const ThreadData &thread = m_threads.at(row);
|
||||||
|
|
||||||
if (role == Qt::DisplayRole) {
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case ThreadData::IdColumn:
|
case ThreadData::IdColumn:
|
||||||
return thread.id;
|
return thread.id;
|
||||||
@@ -112,21 +164,15 @@ QVariant ThreadsHandler::data(const QModelIndex &index, int role) const
|
|||||||
case ThreadData::StateColumn:
|
case ThreadData::StateColumn:
|
||||||
return thread.state;
|
return thread.state;
|
||||||
}
|
}
|
||||||
} else if (role == Qt::ToolTipRole) {
|
case Qt::ToolTipRole:
|
||||||
if (thread.address == 0)
|
return threadToolTip(thread);
|
||||||
return tr("Thread: %1").arg(thread.id);
|
case Qt::DecorationRole: // Return icon that indicates whether this is the active stack frame
|
||||||
// Stopped
|
if (index.column() == 0)
|
||||||
if (thread.fileName.isEmpty())
|
|
||||||
return tr("Thread: %1 at %2 (0x%3)").arg(thread.id)
|
|
||||||
.arg(thread.function).arg(thread.address, 0, 16);
|
|
||||||
return tr("Thread: %1 at %2, %3:%4 (0x%5)").
|
|
||||||
arg(thread.id).arg(thread.function, thread.fileName)
|
|
||||||
.arg(thread.lineNumber).arg(thread.address, 0, 16);
|
|
||||||
} else if (role == Qt::DecorationRole && index.column() == 0) {
|
|
||||||
// Return icon that indicates whether this is the active stack frame
|
|
||||||
return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon;
|
return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user