1
0
Fork 0

Merge pull request #3278 from foralost/3051_Switch__to_thread_handles

#3051: Follow a thread from handles window
This commit is contained in:
Duncan Ogilvie 2023-12-21 21:33:38 +01:00 committed by GitHub
commit b683fc6a59
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 166 additions and 110 deletions

View File

@ -10,55 +10,21 @@
bool cbShowThreadId(int argc, char* argv[])
{
duint threadID = 0;
if(argc > 1)
{
duint threadId = 0;
if(!valfromstring(argv[1], &threadId, false))
return false;
if(argc > 2)
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Too many arguments specified. Only 1 argument can be passed, or none.\n"));
return false;
}
else if(argc == 2)
{
threadID = strtoll(argv[1], NULL, 10);
if(threadID == 0)
SELECTIONDATA newSelection = { threadId, threadId };
if(!GuiSelectionSet(GUI_THREADS, &newSelection))
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Could not search for thread ID 0 or argument was not a number in decimal base.\n"));
dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid thread %s\n"), formatpidtid((DWORD)threadId).c_str());
return false;
}
}
else if(argc == 1)
{
GuiShowThreads();
return true;
}
THREADLIST threads_head{};
DbgGetThreadList(&threads_head);
GuiUpdateThreadView(); // To be sure that we have the freshest stuff
bool threadFound = false;
uint32_t row;
for(row = 0; row < threads_head.count; row++)
{
THREADALLINFO currThread = threads_head.list[row];
if(currThread.BasicInfo.ThreadId == threadID)
{
threadFound = true;
break;
}
}
BridgeFree(threads_head.list);
if(!threadFound)
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Could not find provided thread ID: %llu\n"), threadID);
return false;
}
SELECTIONDATA foundThreadGUIRow{row, row};
GuiShowThreads();
GuiSelectionSet(GUI_THREADS, &foundThreadGUIRow);
return true;
}

View File

@ -42,6 +42,7 @@ public:
void deleteAllColumns() override;
virtual QString getCellContent(duint row, duint column) = 0;
virtual duint getCellUserdata(duint row, duint column) = 0;
virtual bool isValidIndex(duint row, duint column) = 0;
virtual void sortRows(duint column, bool ascending) = 0;

View File

@ -182,7 +182,7 @@ void ReferenceView::addColumnAtRef(int width, QString title)
StdSearchListView::addColumnAt(width, title, true);
}
void ReferenceView::setRowCount(dsint count)
void ReferenceView::setRowCount(duint count)
{
if(!stdList()->getRowCount() && count) //from zero to N rows
searchSelectionChanged(0);

View File

@ -21,7 +21,7 @@ public:
public slots:
void addColumnAtRef(int width, QString title);
void setRowCount(dsint count) override;
void setRowCount(duint count) override;
void setSingleSelection(int index, bool scroll);
void addCommand(QString title, QString command);

View File

@ -57,16 +57,22 @@ void StdSearchListView::loadColumnFromConfig(const QString & viewName)
stdSearchList()->loadColumnFromConfig(viewName);
}
void StdSearchListView::setRowCount(dsint count)
void StdSearchListView::setRowCount(duint count)
{
//clearFilter();
stdList()->setRowCount(count);
}
void StdSearchListView::setCellContent(int r, int c, QString s)
void StdSearchListView::setCellContent(duint row, duint column, QString s)
{
//clearFilter();
stdList()->setCellContent(r, c, s);
stdList()->setCellContent(row, column, s);
}
void StdSearchListView::setCellUserdata(duint row, duint column, duint userdata)
{
//clearFilter();
stdList()->setCellUserdata(row, column, userdata);
}
void StdSearchListView::reloadData()

View File

@ -18,12 +18,13 @@ public:
void enableMultiSelection(bool enabled);
void setAddressColumn(int col, bool cipBase = false);
void loadColumnFromConfig(const QString & viewName);
virtual void setRowCount(duint count);
void setCellContent(duint row, duint column, QString s);
void setCellUserdata(duint row, duint column, duint userdata);
void setSearchStartCol(duint column);
public slots:
virtual void setRowCount(dsint count);
void setCellContent(int r, int c, QString s);
void reloadData();
void setSearchStartCol(duint col);
private:
StdTableSearchList* mSearchListData;

View File

@ -25,7 +25,7 @@ public:
void setCellContent(duint r, duint c, QString s, duint userdata);
QString getCellContent(duint r, duint c) override;
void setCellUserdata(duint r, duint c, duint userdata);
duint getCellUserdata(duint r, duint c);
duint getCellUserdata(duint r, duint c) override;
bool isValidIndex(duint r, duint c) override;
void sortRows(duint column, bool ascending) override;

View File

@ -688,6 +688,9 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_SYMMOD:
emit selectionSymmodGet(selection);
break;
case GUI_THREADS:
emit selectionThreadsGet(selection);
break;
default:
return (void*)false;
}

View File

@ -130,6 +130,7 @@ signals:
void selectionMemmapGet(SELECTIONDATA* selection);
void selectionMemmapSet(const SELECTIONDATA* selection);
void selectionSymmodGet(SELECTIONDATA* selection);
void selectionThreadsGet(SELECTIONDATA* selection);
void selectionThreadsSet(const SELECTIONDATA* selection);
void getStrWindow(const QString title, QString* text);
void autoCompleteAddCmd(const QString cmd);

View File

@ -71,13 +71,13 @@ void CallStackView::setupContextMenu()
});
mMenuBuilder->addSeparator();
QAction* followInThreads = makeAction(tr("Follow in Threads"), SLOT(followInThreadsSlot()));
QAction* followInThreads = makeAction(DIcon("arrow-threads"), tr("Follow in Threads"), SLOT(followInThreadsSlot()));
mMenuBuilder->addAction(followInThreads, [this](QMenu*)
{
return isThreadHeaderSelected();
});
QAction* renameThread = makeAction(tr("Rename Thread"), SLOT(renameThreadSlot()));
QAction* renameThread = makeAction(DIcon("thread-setname"), tr("Rename Thread"), SLOT(renameThreadSlot()));
mMenuBuilder->addAction(renameThread, [this](QMenu*)
{
return isThreadHeaderSelected();
@ -162,7 +162,6 @@ void CallStackView::updateCallStackSlot()
DbgFunctions()->GetCallStackByThread(threadList.list[currentIndexToDraw].BasicInfo.Handle, &callstack);
setRowCount(currentRow + callstack.total + 1);
auto threadId = threadList.list[currentIndexToDraw].BasicInfo.ThreadId;
setCellContent(currentRow, ColThread, ToDecString(threadId));
QString threadName = threadList.list[currentIndexToDraw].BasicInfo.threadName;
QString colThreadString = ToDecString(threadList.list[currentIndexToDraw].BasicInfo.ThreadId);
@ -265,6 +264,7 @@ void CallStackView::renameThreadSlot()
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadId)).arg(DbgCmdEscape(threadName)));
}
void CallStackView::followInThreadsSlot()
{
QStringList threadIDName = getCellContent(getInitialSelection(), ColThread).split(" - ");

View File

@ -47,7 +47,7 @@ HandlesView::HandlesView(QWidget* parent) : QWidget(parent)
mWindowsTable->addColumnAt(8 + 16 * charWidth, tr("StyleEx"), true, "", StdTable::SortBy::AsHex);
mWindowsTable->addColumnAt(8 + 8 * charWidth, tr("Parent"), true);
mWindowsTable->addColumnAt(8 + 20 * charWidth, tr("Size"), true);
mWindowsTable->addColumnAt(8 + 6 * charWidth, tr("Enable"), true);
mWindowsTable->addColumnAt(8 + 8 * charWidth, tr("Enable"), true);
mWindowsTable->loadColumnFromConfig("Window");
mWindowsTable->setIconColumn(2);
@ -118,6 +118,8 @@ HandlesView::HandlesView(QWidget* parent) : QWidget(parent)
mActionFollowProc = new QAction(DIcon(ArchValue("processor32", "processor64")), tr("Follow Proc in Disassembler"), this);
connect(mActionFollowProc, SIGNAL(triggered()), this, SLOT(followInDisasmSlot()));
mActionFollowProc->setShortcut(Qt::Key_Return);
mActionFollowThread = new QAction(DIcon("arrow-threads"), tr("Follow in Threads"), this);
connect(mActionFollowThread, SIGNAL(triggered()), this, SLOT(followInThreads()));
mWindowsTable->addAction(mActionFollowProc);
mActionToggleProcBP = new QAction(DIcon("breakpoint_toggle"), tr("Toggle Breakpoint in Proc"), this);
connect(mActionToggleProcBP, SIGNAL(triggered()), this, SLOT(toggleBPSlot()));
@ -221,6 +223,7 @@ void HandlesView::windowsTableContextMenuSlot(QMenu* menu)
}
menu->addAction(mActionFollowProc);
menu->addAction(mActionFollowThread);
menu->addAction(mActionToggleProcBP);
menu->addAction(mActionMessageProcBP);
}
@ -325,6 +328,12 @@ void HandlesView::followInDisasmSlot()
DbgCmdExec(QString("disasm %1").arg(mWindowsTable->mCurList->getCellContent(mWindowsTable->mCurList->getInitialSelection(), 0)));
}
void HandlesView::followInThreads()
{
auto threadId = mWindowsTable->mCurList->getCellUserdata(mWindowsTable->mCurList->getInitialSelection(), 4);
DbgCmdExec(QString("showthreadid %1").arg(ToHexString(threadId)));
}
void HandlesView::toggleBPSlot()
{
auto & mCurList = *mWindowsTable->mCurList;
@ -435,13 +444,13 @@ void HandlesView::enumWindows()
mWindowsTable->setCellContent(i, 1, ToHexString(windows[i].handle));
mWindowsTable->setCellContent(i, 2, QString(windows[i].windowTitle));
mWindowsTable->setCellContent(i, 3, QString(windows[i].windowClass));
char threadname[MAX_THREAD_NAME_SIZE];
if(DbgFunctions()->ThreadGetName(windows[i].threadId, threadname) && *threadname != '\0')
mWindowsTable->setCellContent(i, 4, QString::fromUtf8(threadname));
else if(Config()->getBool("Gui", "PidTidInHex"))
mWindowsTable->setCellContent(i, 4, ToHexString(windows[i].threadId));
auto tidStr = QString().sprintf(Config()->getBool("Gui", "PidTidInHex") ? "%X" : "%u", windows[i].threadId);
char threadName[MAX_THREAD_NAME_SIZE];
if(DbgFunctions()->ThreadGetName(windows[i].threadId, threadName) && *threadName != '\0')
mWindowsTable->setCellContent(i, 4, QString::fromUtf8(threadName) + QString(" (%1)").arg(tidStr));
else
mWindowsTable->setCellContent(i, 4, QString::number(windows[i].threadId));
mWindowsTable->setCellContent(i, 4, tidStr);
mWindowsTable->setCellUserdata(i, 4, windows[i].threadId);
//Style
mWindowsTable->setCellContent(i, 5, ToHexString(windows[i].style));
//StyleEx

View File

@ -35,6 +35,7 @@ public slots:
void enableWindowSlot();
void disableWindowSlot();
void followInDisasmSlot();
void followInThreads();
void toggleBPSlot();
void messagesBPSlot();
@ -56,6 +57,7 @@ private:
QAction* mActionEnableWindow;
QAction* mActionDisableWindow;
QAction* mActionFollowProc;
QAction* mActionFollowThread;
QAction* mActionToggleProcBP;
QAction* mActionMessageProcBP;

View File

@ -41,12 +41,12 @@ SourceView::~SourceView()
clear();
}
QString SourceView::getCellContent(duint r, duint c)
QString SourceView::getCellContent(duint row, duint column)
{
if(!isValidIndex(r, c))
if(!isValidIndex(row, column))
return QString();
LineData & line = mLines.at(r - mPrepareTableOffset);
switch(c)
LineData & line = mLines.at(row - mPrepareTableOffset);
switch(column)
{
case ColAddr:
return line.addr ? ToPtrString(line.addr) : QString();
@ -59,13 +59,29 @@ QString SourceView::getCellContent(duint r, duint c)
return "INVALID";
}
bool SourceView::isValidIndex(duint r, duint c)
duint SourceView::getCellUserdata(duint row, duint column)
{
if(!isValidIndex(row, column))
return 0;
LineData & line = mLines.at(row - mPrepareTableOffset);
switch(column)
{
case ColAddr:
return line.addr;
case ColLine:
return line.index + 1;
default:
return 0;
}
}
bool SourceView::isValidIndex(duint row, duint column)
{
if(!mFileLines)
return false;
if(c < ColAddr || c > ColCode)
if(column < ColAddr || column > ColCode)
return false;
return r >= 0 && size_t(r) < mFileLines->size();
return row >= 0 && size_t(row) < mFileLines->size();
}
void SourceView::sortRows(duint column, bool ascending)

View File

@ -13,8 +13,9 @@ public:
SourceView(QString path, duint addr, QWidget* parent = nullptr);
~SourceView();
QString getCellContent(duint r, duint c) override;
bool isValidIndex(duint r, duint c) override;
QString getCellContent(duint row, duint column) override;
duint getCellUserdata(duint row, duint column) override;
bool isValidIndex(duint row, duint column) override;
void sortRows(duint column, bool ascending) override;
void prepareData() override;

View File

@ -17,7 +17,7 @@ void ThreadView::contextMenuSlot(const QPoint & pos)
void ThreadView::gotoThreadEntrySlot()
{
QString addrText = getCellContent(getInitialSelection(), 2);
QString addrText = getCellContent(getInitialSelection(), ColEntry);
DbgCmdExecDirect(QString("disasm " + addrText));
}
@ -167,6 +167,7 @@ ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
//setCopyMenuOnly(true);
connect(Bridge::getBridge(), SIGNAL(selectionThreadsSet(const SELECTIONDATA*)), this, SLOT(selectionThreadsSet(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(selectionThreadsGet(SELECTIONDATA*)), this, SLOT(selectionThreadsGet(SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(updateThreads()), this, SLOT(updateThreadListSlot()));
connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
@ -178,19 +179,27 @@ ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
void ThreadView::selectionThreadsSet(const SELECTIONDATA* selection)
{
if(selection->start >= getRowCount() ||
selection->end >= getRowCount() ||
selection->start > selection->end)
auto selectedThreadId = selection->start;
auto rowCount = getRowCount();
for(duint row = 0; row < rowCount; row++)
{
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 0);
return;
auto threadId = getCellUserdata(row, ColThreadId);
if(threadId == selectedThreadId)
{
setSingleSelection(row);
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 1);
return;
}
}
mSelection.firstSelectedIndex = selection->start;
mSelection.fromIndex = selection->start;
mSelection.toIndex = selection->end;
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 1);
emit selectionChanged(mSelection.firstSelectedIndex);
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 0);
}
void ThreadView::selectionThreadsGet(SELECTIONDATA* selection)
{
auto threadId = getCellUserdata(getInitialSelection(), ColThreadId);
selection->start = selection->end = threadId;
Bridge::getBridge()->setResult(BridgeResult::SelectionGet, 1);
}
void ThreadView::updateThreadListSlot()
@ -203,15 +212,15 @@ void ThreadView::updateThreadListSlot()
for(int i = 0; i < threadList.count; i++)
{
if(!threadList.list[i].BasicInfo.ThreadNumber)
setCellContent(i, 0, tr("Main"));
setCellContent(i, ColNumber, tr("Main"));
else
setCellContent(i, 0, ToDecString(threadList.list[i].BasicInfo.ThreadNumber));
setCellContent(i, 1, QString().sprintf(tidFormat, threadList.list[i].BasicInfo.ThreadId));
setCellUserdata(i, 1, threadList.list[i].BasicInfo.ThreadId);
setCellContent(i, 2, ToPtrString(threadList.list[i].BasicInfo.ThreadStartAddress));
setCellContent(i, 3, ToPtrString(threadList.list[i].BasicInfo.ThreadLocalBase));
setCellContent(i, 4, ToPtrString(threadList.list[i].ThreadCip));
setCellContent(i, 5, ToDecString(threadList.list[i].SuspendCount));
setCellContent(i, ColNumber, ToDecString(threadList.list[i].BasicInfo.ThreadNumber));
setCellContent(i, ColThreadId, QString().sprintf(tidFormat, threadList.list[i].BasicInfo.ThreadId));
setCellUserdata(i, ColThreadId, threadList.list[i].BasicInfo.ThreadId);
setCellContent(i, ColEntry, ToPtrString(threadList.list[i].BasicInfo.ThreadStartAddress));
setCellContent(i, ColTeb, ToPtrString(threadList.list[i].BasicInfo.ThreadLocalBase));
setCellContent(i, ColCip, ToPtrString(threadList.list[i].ThreadCip));
setCellContent(i, ColSuspendCount, ToDecString(threadList.list[i].SuspendCount));
QString priorityString;
switch(threadList.list[i].Priority)
{
@ -240,7 +249,7 @@ void ThreadView::updateThreadListSlot()
priorityString = tr("Unknown");
break;
}
setCellContent(i, 6, priorityString);
setCellContent(i, ColPriority, priorityString);
QString waitReasonString;
switch(threadList.list[i].WaitReason)
{
@ -359,13 +368,13 @@ void ThreadView::updateThreadListSlot()
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, FILETIMEToTime(threadList.list[i].UserTime));
setCellContent(i, 10, FILETIMEToTime(threadList.list[i].KernelTime));
setCellContent(i, 11, FILETIMEToDate(threadList.list[i].CreationTime));
setCellContent(i, 12, ToLongLongHexString(threadList.list[i].Cycles));
setCellContent(i, 13, threadList.list[i].BasicInfo.threadName);
setCellContent(i, ColWaitReason, waitReasonString);
setCellContent(i, ColLastError, QString("%1").arg(threadList.list[i].LastError, sizeof(unsigned int) * 2, 16, QChar('0')).toUpper());
setCellContent(i, ColUserTime, FILETIMEToTime(threadList.list[i].UserTime));
setCellContent(i, ColKernelTime, FILETIMEToTime(threadList.list[i].KernelTime));
setCellContent(i, ColCreationTime, FILETIMEToDate(threadList.list[i].CreationTime));
setCellContent(i, ColCpuCycles, ToLongLongHexString(threadList.list[i].Cycles));
setCellContent(i, ColThreadName, threadList.list[i].BasicInfo.threadName);
}
mCurrentThreadId = -1;
if(threadList.count)
@ -381,7 +390,7 @@ void ThreadView::updateThreadListSlot()
QString ThreadView::paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h)
{
QString ret = StdTable::paintContent(painter, row, col, x, y, w, h);
duint threadId = getCellUserdata(row, 1);
duint threadId = getCellUserdata(row, ColThreadId);
if(threadId == mCurrentThreadId && !col)
{
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("ThreadCurrentBackgroundColor")));
@ -394,17 +403,17 @@ QString ThreadView::paintContent(QPainter* painter, duint row, duint col, int x,
void ThreadView::doubleClickedSlot()
{
duint threadId = getCellUserdata(getInitialSelection(), 1);
duint threadId = getCellUserdata(getInitialSelection(), ColThreadId);
DbgCmdExecDirect("switchthread " + ToHexString(threadId));
QString addrText = getCellContent(getInitialSelection(), 4);
QString addrText = getCellContent(getInitialSelection(), ColCip);
DbgCmdExec("disasm " + addrText);
}
void ThreadView::setNameSlot()
{
duint threadId = getCellUserdata(getInitialSelection(), 1);
QString threadName = getCellContent(getInitialSelection(), 13);
duint threadId = getCellUserdata(getInitialSelection(), ColThreadId);
QString threadName = getCellContent(getInitialSelection(), ColThreadName);
if(!SimpleInputBox(this, tr("Thread name - %1").arg(threadId), threadName, threadName, QString()))
return;

View File

@ -10,11 +10,13 @@ public:
explicit ThreadView(StdTable* parent = nullptr);
QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override;
void setupContextMenu();
signals:
void displayThreadsView();
public slots:
void selectionThreadsSet(const SELECTIONDATA* selection);
void selectionThreadsGet(SELECTIONDATA* selection);
void updateThreadListSlot();
void doubleClickedSlot();
void execCommandSlot();
@ -26,4 +28,22 @@ private:
QAction* makeCommandAction(QAction* action, const QString & command);
duint mCurrentThreadId;
MenuBuilder* mMenuBuilder;
enum
{
ColNumber = 0,
ColThreadId,
ColEntry,
ColTeb,
ColCip,
ColSuspendCount,
ColPriority,
ColWaitReason,
ColLastError,
ColUserTime,
ColKernelTime,
ColCreationTime,
ColCpuCycles,
ColThreadName,
};
};

View File

@ -56,20 +56,40 @@ ZehSymbolTable::ZehSymbolTable(QWidget* parent)
Initialize();
}
QString ZehSymbolTable::getCellContent(duint r, duint c)
QString ZehSymbolTable::getCellContent(duint row, duint column)
{
QMutexLocker lock(&mMutex);
if(!isValidIndex(r, c))
if(!isValidIndex(row, column))
return QString();
SymbolInfoWrapper info;
DbgGetSymbolInfo(&mData.at(r), info.put());
return symbolInfoString(info.get(), c);
DbgGetSymbolInfo(&mData.at(row), info.put());
return symbolInfoString(info.get(), column);
}
bool ZehSymbolTable::isValidIndex(duint r, duint c)
duint ZehSymbolTable::getCellUserdata(duint row, duint column)
{
QMutexLocker lock(&mMutex);
return r >= 0 && r < (int)mData.size() && c >= 0 && c <= ColUndecorated;
if(!isValidIndex(row, column))
return 0;
SymbolInfoWrapper info;
DbgGetSymbolInfo(&mData.at(row), info.put());
switch(column)
{
case ColAddr:
return info->addr;
case ColOrdinal:
return info->ordinal;
case ColType:
return info->type;
default:
return 0;
}
}
bool ZehSymbolTable::isValidIndex(duint row, duint column)
{
QMutexLocker lock(&mMutex);
return row >= 0 && row < (int)mData.size() && column >= 0 && column <= ColUndecorated;
}
void ZehSymbolTable::sortRows(duint column, bool ascending)

View File

@ -9,8 +9,9 @@ class ZehSymbolTable : public AbstractStdTable
public:
ZehSymbolTable(QWidget* parent = nullptr);
QString getCellContent(duint r, duint c) override;
bool isValidIndex(duint r, duint c) override;
QString getCellContent(duint row, duint column) override;
duint getCellUserdata(duint row, duint column) override;
bool isValidIndex(duint row, duint column) override;
void sortRows(duint column, bool ascending) override;
friend class SymbolView;