385 lines
14 KiB
C++
385 lines
14 KiB
C++
#include "ThreadView.h"
|
|
|
|
void ThreadView::contextMenuSlot(const QPoint & pos)
|
|
{
|
|
if(!DbgIsDebugging())
|
|
return;
|
|
|
|
QMenu* wMenu = new QMenu(this); //create context menu
|
|
wMenu->addAction(mSwitchThread);
|
|
wMenu->addAction(mSuspendThread);
|
|
wMenu->addAction(mResumeThread);
|
|
wMenu->addAction(mKillThread);
|
|
wMenu->addSeparator();
|
|
wMenu->addMenu(mSetPriority);
|
|
wMenu->addSeparator();
|
|
QMenu wCopyMenu("&Copy", this);
|
|
setupCopyMenu(&wCopyMenu);
|
|
if(wCopyMenu.actions().length())
|
|
{
|
|
wMenu->addSeparator();
|
|
wMenu->addMenu(&wCopyMenu);
|
|
}
|
|
|
|
|
|
foreach(QAction * action, mSetPriority->actions())
|
|
{
|
|
action->setCheckable(true);
|
|
action->setChecked(false);
|
|
}
|
|
|
|
QString priority = getCellContent(getInitialSelection(), 6);
|
|
if(priority == "Normal")
|
|
mSetPriorityNormal->setChecked(true);
|
|
else if(priority == "AboveNormal")
|
|
mSetPriorityAboveNormal->setChecked(true);
|
|
else if(priority == "TimeCritical")
|
|
mSetPriorityTimeCritical ->setChecked(true);
|
|
else if(priority == "Idle")
|
|
mSetPriorityIdle->setChecked(true);
|
|
else if(priority == "BelowNormal")
|
|
mSetPriorityBelowNormal->setChecked(true);
|
|
else if(priority == "Highest")
|
|
mSetPriorityHighest->setChecked(true);
|
|
else if(priority == "Lowest")
|
|
mSetPriorityLowest->setChecked(true);
|
|
|
|
wMenu->exec(mapToGlobal(pos)); //execute context menu
|
|
}
|
|
|
|
void ThreadView::SwitchThread()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("switchthread " + threadId).toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SuspendThread()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("suspendthread " + threadId).toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::ResumeThread()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("resumethread " + threadId).toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::KillThread()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("killthread " + threadId).toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SetPriorityIdleSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("setprioritythread " + threadId + ", Idle").toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SetPriorityAboveNormalSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("setprioritythread " + threadId + ", AboveNormal").toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SetPriorityBelowNormalSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("setprioritythread " + threadId + ", BelowNormal").toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SetPriorityHighestSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("setprioritythread " + threadId + ", Highest").toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SetPriorityLowestSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("setprioritythread " + threadId + ", Lowest").toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SetPriorityNormalSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("setprioritythread " + threadId + ", Normal").toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::SetPriorityTimeCriticalSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("setprioritythread " + threadId + ", TimeCritical").toUtf8().constData());
|
|
}
|
|
|
|
void ThreadView::setupContextMenu()
|
|
{
|
|
//Switch thread menu
|
|
mSwitchThread = new QAction("Switch Thread", this);
|
|
connect(mSwitchThread, SIGNAL(triggered()), this, SLOT(SwitchThread()));
|
|
|
|
//Suspend thread menu
|
|
mSuspendThread = new QAction("Suspend Thread", this);
|
|
connect(mSuspendThread, SIGNAL(triggered()), this, SLOT(SuspendThread()));
|
|
|
|
//Resume thread menu
|
|
mResumeThread = new QAction("Resume Thread", this);
|
|
connect(mResumeThread, SIGNAL(triggered()), this, SLOT(ResumeThread()));
|
|
|
|
//Kill thread menu
|
|
mKillThread = new QAction("Kill Thread", this);
|
|
connect(mKillThread, SIGNAL(triggered()), this, SLOT(KillThread()));
|
|
|
|
mSetPriority = new QMenu("Set Priority", this);
|
|
|
|
mSetPriorityIdle = new QAction("Idle", this);
|
|
connect(mSetPriorityIdle, SIGNAL(triggered()), this, SLOT(SetPriorityIdleSlot()));
|
|
mSetPriority->addAction(mSetPriorityIdle);
|
|
|
|
mSetPriorityAboveNormal = new QAction("Above Normal", this);
|
|
connect(mSetPriorityAboveNormal, SIGNAL(triggered()), this, SLOT(SetPriorityAboveNormalSlot()));
|
|
mSetPriority->addAction(mSetPriorityAboveNormal);
|
|
|
|
mSetPriorityBelowNormal = new QAction("Below Normal", this);
|
|
connect(mSetPriorityBelowNormal, SIGNAL(triggered()), this, SLOT(SetPriorityBelowNormalSlot()));
|
|
mSetPriority->addAction(mSetPriorityBelowNormal);
|
|
|
|
mSetPriorityHighest = new QAction("Highest", this);
|
|
connect(mSetPriorityHighest, SIGNAL(triggered()), this, SLOT(SetPriorityHighestSlot()));
|
|
mSetPriority->addAction(mSetPriorityHighest);
|
|
|
|
mSetPriorityLowest = new QAction("Lowest", this);
|
|
connect(mSetPriorityLowest, SIGNAL(triggered()), this, SLOT(SetPriorityLowestSlot()));
|
|
mSetPriority->addAction(mSetPriorityLowest);
|
|
|
|
mSetPriorityNormal = new QAction("Normal", this);
|
|
connect(mSetPriorityNormal, SIGNAL(triggered()), this, SLOT(SetPriorityNormalSlot()));
|
|
mSetPriority->addAction(mSetPriorityNormal);
|
|
|
|
mSetPriorityTimeCritical = new QAction("Time Critical", this);
|
|
connect(mSetPriorityTimeCritical, SIGNAL(triggered()), this, SLOT(SetPriorityTimeCriticalSlot()));
|
|
mSetPriority->addAction(mSetPriorityTimeCritical);
|
|
}
|
|
|
|
ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
|
|
{
|
|
int charwidth = getCharWidth();
|
|
addColumnAt(8 + charwidth * sizeof(unsigned int) * 2, "Number", false);
|
|
addColumnAt(8 + charwidth * sizeof(unsigned int) * 2, "ID", false);
|
|
addColumnAt(8 + charwidth * sizeof(uint_t) * 2, "Entry", false);
|
|
addColumnAt(8 + charwidth * sizeof(uint_t) * 2, "TEB", false);
|
|
#ifdef _WIN64
|
|
addColumnAt(8 + charwidth * sizeof(uint_t) * 2, "RIP", false);
|
|
#else
|
|
addColumnAt(8 + charwidth * sizeof(uint_t) * 2, "EIP", false);
|
|
#endif //_WIN64
|
|
addColumnAt(8 + charwidth * 14, "Suspend Count", false);
|
|
addColumnAt(8 + charwidth * 12, "Priority", false);
|
|
addColumnAt(8 + charwidth * 16, "WaitReason", false);
|
|
addColumnAt(8 + charwidth * 10, "LastError", false);
|
|
addColumnAt(0, "Name", false);
|
|
|
|
//setCopyMenuOnly(true);
|
|
|
|
connect(Bridge::getBridge(), SIGNAL(updateThreads()), this, SLOT(updateThreadList()));
|
|
connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
|
|
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
|
|
|
|
setupContextMenu();
|
|
}
|
|
|
|
void ThreadView::updateThreadList()
|
|
{
|
|
THREADLIST threadList;
|
|
memset(&threadList, 0, sizeof(THREADLIST));
|
|
DbgGetThreadList(&threadList);
|
|
setRowCount(threadList.count);
|
|
for(int i = 0; i < threadList.count; i++)
|
|
{
|
|
if(!threadList.list[i].BasicInfo.ThreadNumber)
|
|
setCellContent(i, 0, "Main");
|
|
else
|
|
setCellContent(i, 0, QString("%1").arg(threadList.list[i].BasicInfo.ThreadNumber, 0, 10));
|
|
setCellContent(i, 1, QString("%1").arg(threadList.list[i].BasicInfo.dwThreadId, 0, 16).toUpper());
|
|
setCellContent(i, 2, QString("%1").arg(threadList.list[i].BasicInfo.ThreadStartAddress, sizeof(int_t) * 2, 16, QChar('0')).toUpper());
|
|
setCellContent(i, 3, QString("%1").arg(threadList.list[i].BasicInfo.ThreadLocalBase, sizeof(int_t) * 2, 16, QChar('0')).toUpper());
|
|
setCellContent(i, 4, QString("%1").arg(threadList.list[i].ThreadCip, sizeof(int_t) * 2, 16, QChar('0')).toUpper());
|
|
setCellContent(i, 5, QString().sprintf("%d", threadList.list[i].SuspendCount));
|
|
QString priorityString;
|
|
switch(threadList.list[i].Priority)
|
|
{
|
|
case _PriorityIdle:
|
|
priorityString = "Idle";
|
|
break;
|
|
case _PriorityAboveNormal:
|
|
priorityString = "AboveNormal";
|
|
break;
|
|
case _PriorityBelowNormal:
|
|
priorityString = "BelowNormal";
|
|
break;
|
|
case _PriorityHighest:
|
|
priorityString = "Highest";
|
|
break;
|
|
case _PriorityLowest:
|
|
priorityString = "Lowest";
|
|
break;
|
|
case _PriorityNormal:
|
|
priorityString = "Normal";
|
|
break;
|
|
case _PriorityTimeCritical:
|
|
priorityString = "TimeCritical";
|
|
break;
|
|
default:
|
|
priorityString = "Unknown";
|
|
break;
|
|
}
|
|
setCellContent(i, 6, priorityString);
|
|
QString waitReasonString;
|
|
switch(threadList.list[i].WaitReason)
|
|
{
|
|
case _Executive:
|
|
waitReasonString = "Executive";
|
|
break;
|
|
case _FreePage:
|
|
waitReasonString = "FreePage";
|
|
break;
|
|
case _PageIn:
|
|
waitReasonString = "PageIn";
|
|
break;
|
|
case _PoolAllocation:
|
|
waitReasonString = "PoolAllocation";
|
|
break;
|
|
case _DelayExecution:
|
|
waitReasonString = "DelayExecution";
|
|
break;
|
|
case _Suspended:
|
|
waitReasonString = "Suspended";
|
|
break;
|
|
case _UserRequest:
|
|
waitReasonString = "UserRequest";
|
|
break;
|
|
case _WrExecutive:
|
|
waitReasonString = "WrExecutive";
|
|
break;
|
|
case _WrFreePage:
|
|
waitReasonString = "WrFreePage";
|
|
break;
|
|
case _WrPageIn:
|
|
waitReasonString = "WrPageIn";
|
|
break;
|
|
case _WrPoolAllocation:
|
|
waitReasonString = "WrPoolAllocation";
|
|
break;
|
|
case _WrDelayExecution:
|
|
waitReasonString = "WrDelayExecution";
|
|
break;
|
|
case _WrSuspended:
|
|
waitReasonString = "WrSuspended";
|
|
break;
|
|
case _WrUserRequest:
|
|
waitReasonString = "WrUserRequest";
|
|
break;
|
|
case _WrEventPair:
|
|
waitReasonString = "WrEventPair";
|
|
break;
|
|
case _WrQueue:
|
|
waitReasonString = "WrQueue";
|
|
break;
|
|
case _WrLpcReceive:
|
|
waitReasonString = "WrLpcReceive";
|
|
break;
|
|
case _WrLpcReply:
|
|
waitReasonString = "WrLpcReply";
|
|
break;
|
|
case _WrVirtualMemory:
|
|
waitReasonString = "WrVirtualMemory";
|
|
break;
|
|
case _WrPageOut:
|
|
waitReasonString = "WrPageOut";
|
|
break;
|
|
case _WrRendezvous:
|
|
waitReasonString = "WrRendezvous";
|
|
break;
|
|
case _Spare2:
|
|
waitReasonString = "Spare2";
|
|
break;
|
|
case _Spare3:
|
|
waitReasonString = "Spare3";
|
|
break;
|
|
case _Spare4:
|
|
waitReasonString = "Spare4";
|
|
break;
|
|
case _Spare5:
|
|
waitReasonString = "Spare5";
|
|
break;
|
|
case _WrCalloutStack:
|
|
waitReasonString = "WrCalloutStack";
|
|
break;
|
|
case _WrKernel:
|
|
waitReasonString = "WrKernel";
|
|
break;
|
|
case _WrResource:
|
|
waitReasonString = "WrResource";
|
|
break;
|
|
case _WrPushLock:
|
|
waitReasonString = "WrPushLock";
|
|
break;
|
|
case _WrMutex:
|
|
waitReasonString = "WrMutex";
|
|
break;
|
|
case _WrQuantumEnd:
|
|
waitReasonString = "WrQuantumEnd";
|
|
break;
|
|
case _WrDispatchInt:
|
|
waitReasonString = "WrDispatchInt";
|
|
break;
|
|
case _WrPreempted:
|
|
waitReasonString = "WrPreempted";
|
|
break;
|
|
case _WrYieldExecution:
|
|
waitReasonString = "WrYieldExecution";
|
|
break;
|
|
case _WrFastMutex:
|
|
waitReasonString = "WrFastMutex";
|
|
break;
|
|
case _WrGuardedMutex:
|
|
waitReasonString = "WrGuardedMutex";
|
|
break;
|
|
case _WrRundown:
|
|
waitReasonString = "WrRundown";
|
|
break;
|
|
default:
|
|
waitReasonString = "Unknown";
|
|
break;
|
|
}
|
|
setCellContent(i, 7, waitReasonString);
|
|
setCellContent(i, 8, QString("%1").arg(threadList.list[i].LastError, sizeof(unsigned int) * 2, 16, QChar('0')).toUpper());
|
|
setCellContent(i, 9, threadList.list[i].BasicInfo.threadName);
|
|
}
|
|
if(threadList.count)
|
|
BridgeFree(threadList.list);
|
|
mCurrentThread = threadList.CurrentThread;
|
|
reloadData();
|
|
}
|
|
|
|
QString ThreadView::paintContent(QPainter* painter, int_t rowBase, int rowOffset, int col, int x, int y, int w, int h)
|
|
{
|
|
QString ret = StdTable::paintContent(painter, rowBase, rowOffset, col, x, y, w, h);
|
|
if(rowBase + rowOffset == mCurrentThread && !col)
|
|
{
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("ThreadCurrentBackgroundColor")));
|
|
painter->setPen(QPen(ConfigColor("ThreadCurrentColor"))); //white text
|
|
painter->drawText(QRect(x + 4, y , w - 4 , h), Qt::AlignVCenter | Qt::AlignLeft, ret);
|
|
ret = "";
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ThreadView::doubleClickedSlot()
|
|
{
|
|
QString threadId = getCellContent(getInitialSelection(), 1);
|
|
DbgCmdExecDirect(QString("switchthread " + threadId).toUtf8().constData());
|
|
emit showCpu();
|
|
}
|