1
0
Fork 0

Introducing showthreadid command

Additional options in CallStackView
This commit is contained in:
foralost 2023-11-08 18:04:50 +01:00
parent b0392eda1c
commit c9d80e5c99
13 changed files with 165 additions and 17 deletions

View File

@ -1779,6 +1779,12 @@ BRIDGE_IMPEXP void GuiMenuSetEntryHotkey(int hEntry, const char* hack)
_gui_sendmessage(GUI_MENU_SET_ENTRY_HOTKEY, (void*)hEntry, (void*)hack);
}
BRIDGE_IMPEXP void GuiShowThreads()
{
_gui_sendmessage(GUI_SHOW_THREADS, 0, 0);
}
BRIDGE_IMPEXP void GuiShowCpu()
{
_gui_sendmessage(GUI_SHOW_CPU, 0, 0);

View File

@ -1152,6 +1152,7 @@ typedef enum
GUI_GRAPH,
GUI_MEMMAP,
GUI_SYMMOD,
GUI_THREADS,
} GUISELECTIONTYPE;
#define GUI_MAX_LINE_SIZE 65536
@ -1281,6 +1282,7 @@ typedef enum
GUI_SAVE_LOG, // param1=const char* file name,param2=unused
GUI_REDIRECT_LOG, // param1=const char* file name,param2=unused
GUI_STOP_REDIRECT_LOG, // param1=unused, param2=unused
GUI_SHOW_THREADS, // param1=unused, param2=unused
} GUIMSG;
//GUI Typedefs
@ -1423,6 +1425,7 @@ BRIDGE_IMPEXP void GuiMenuSetName(int hMenu, const char* name);
BRIDGE_IMPEXP void GuiMenuSetEntryName(int hEntry, const char* name);
BRIDGE_IMPEXP void GuiMenuSetEntryHotkey(int hEntry, const char* hack);
BRIDGE_IMPEXP void GuiShowCpu();
BRIDGE_IMPEXP void GuiShowThreads();
BRIDGE_IMPEXP void GuiAddQWidgetTab(void* qWidget);
BRIDGE_IMPEXP void GuiShowQWidgetTab(void* qWidget);
BRIDGE_IMPEXP void GuiCloseQWidgetTab(void* qWidget);

View File

@ -8,6 +8,60 @@
#include "value.h"
#include "variable.h"
bool cbShowThreadId(int argc, char* argv[])
{
duint threadID = 0;
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)
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Could not search for thread ID 0 or argument was not a number in decimal base.\n"));
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;
}
bool cbDebugDisasm(int argc, char* argv[])
{
duint addr = 0;

View File

@ -2,6 +2,7 @@
#include "command.h"
bool cbShowThreadId(int argc, char* argv[]);
bool cbDebugDisasm(int argc, char* argv[]);
bool cbDebugDump(int argc, char* argv[]);
bool cbDebugStackDump(int argc, char* argv[]);

View File

@ -415,6 +415,7 @@ static void registercommands()
dbgcmdnew("scriptcmd", cbScriptCmd, false); // execute a script command TODO: undocumented
//gui
dbgcmdnew("showthreadid", cbShowThreadId, false); // show given thread in threads
dbgcmdnew("disasm,dis,d", cbDebugDisasm, true); //doDisasm
dbgcmdnew("dump", cbDebugDump, true); //dump at address
dbgcmdnew("sdump", cbDebugStackDump, true); //dump at stack address

View File

@ -579,6 +579,9 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
case GUI_MEMMAP:
emit selectionMemmapSet(selection);
break;
case GUI_THREADS:
emit selectionThreadsSet(selection);
break;
default:
return (void*)false;
}
@ -644,6 +647,10 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
emit loadSourceFile(QString((const char*)param1), (duint)param2);
break;
case GUI_SHOW_THREADS:
emit showThreads();
break;
case GUI_SHOW_CPU:
emit showCpu();
break;

View File

@ -125,6 +125,7 @@ signals:
void selectionMemmapGet(SELECTIONDATA* selection);
void selectionMemmapSet(const SELECTIONDATA* selection);
void selectionSymmodGet(SELECTIONDATA* selection);
void selectionThreadsSet(const SELECTIONDATA* selection);
void getStrWindow(const QString title, QString* text);
void autoCompleteAddCmd(const QString cmd);
void autoCompleteDelCmd(const QString cmd);
@ -139,6 +140,7 @@ signals:
void symbolRefreshCurrent();
void loadSourceFile(const QString path, duint addr);
void showCpu();
void showThreads();
void addQWidgetTab(QWidget* qWidget);
void showQWidgetTab(QWidget* qWidget);
void closeQWidgetTab(QWidget* qWidget);

View File

@ -7,7 +7,7 @@ CallStackView::CallStackView(StdTable* parent) : StdIconTable(parent)
{
int charwidth = getCharWidth();
addColumnAt(8 * charwidth, tr("Thread ID"), false);
addColumnAt(32 * charwidth, tr("Thread ID"), false);
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("Address"), false); //address in the stack
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("To"), false); //return to
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("From"), false); //return from
@ -56,6 +56,7 @@ void CallStackView::setupContextMenu()
// TODO: Is Label/Comment/Bookmark useful?
mCommonActions->build(mMenuBuilder, CommonActions::ActionBreakpoint);
mMenuBuilder->addSeparator();
QAction* showSuspectedCallStack = makeAction(tr("Show Suspected Call Stack Frame"), SLOT(showSuspectedCallStack()));
mMenuBuilder->addAction(showSuspectedCallStack, [showSuspectedCallStack](QMenu*)
{
@ -68,6 +69,20 @@ void CallStackView::setupContextMenu()
showSuspectedCallStack->setText(tr("Show Suspected Call Stack Frame"));
return true;
});
mMenuBuilder->addSeparator();
QAction* followInThreads = makeAction(tr("Follow in Threads"), SLOT(followInThreads()));
mMenuBuilder->addAction(followInThreads, [this](QMenu*)
{
return isThreadHeaderSelected();
});
QAction* renameThread = makeAction(tr("Rename Thread"), SLOT(renameThread()));
mMenuBuilder->addAction(renameThread, [this](QMenu*)
{
return isThreadHeaderSelected();
});
MenuBuilder* mCopyMenu = new MenuBuilder(this);
setupCopyMenu(mCopyMenu);
// Column count cannot be zero
@ -146,7 +161,14 @@ void CallStackView::updateCallStack()
memset(&callstack, 0, sizeof(DBGCALLSTACK));
DbgFunctions()->GetCallStackByThread(threadList.list[currentIndexToDraw].BasicInfo.Handle, &callstack);
setRowCount(currentRow + callstack.total + 1);
setCellContent(currentRow, ColThread, ToDecString(threadList.list[currentIndexToDraw].BasicInfo.ThreadId));
QString threadName = threadList.list[currentIndexToDraw].BasicInfo.threadName;
QString colThreadString = ToDecString(threadList.list[currentIndexToDraw].BasicInfo.ThreadId);
if(threadName.size() > 0)
colThreadString += " - " + threadName; // The " - " is crucial here, because later split is happening
setCellContent(currentRow, ColThread, colThreadString);
currentRow++;
@ -223,6 +245,27 @@ void CallStackView::followFrom()
DbgCmdExecDirect(QString("disasm " + addrText));
}
void CallStackView::renameThread()
{
const QStringList threadIDName = getCellContent(getInitialSelection(), 0).split("-", QString::SplitBehavior::SkipEmptyParts);
const duint threadID = threadIDName[0].toInt();
const QString windowTitle = QStringLiteral("%1 - %2").arg(tr("Changing Threads Name")).arg(threadID);
QString newThreadsName("");
SimpleInputBox(this, windowTitle, "", newThreadsName, "Place new threads name here...");
QString escapedName = newThreadsName.replace("\"", "\\\"");
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadID)).arg(escapedName));
}
void CallStackView::followInThreads()
{
QStringList threadIDName = getCellContent(getInitialSelection(), ColThread).split(" - ");
if(threadIDName[0].size() == 0)
return;
DbgCmdExecDirect(QString("showthreadid " + threadIDName[0]));
}
void CallStackView::showSuspectedCallStack()
{
duint i;
@ -235,6 +278,11 @@ void CallStackView::showSuspectedCallStack()
emit Bridge::getBridge()->updateDump();
}
bool CallStackView::isThreadHeaderSelected()
{
return !getCellContent(getInitialSelection(), ColThread).isEmpty();
}
bool CallStackView::isSelectionValid()
{
return getCellContent(getInitialSelection(), ColThread).isEmpty();

View File

@ -21,6 +21,8 @@ protected slots:
void followTo();
void followFrom();
void showSuspectedCallStack();
void followInThreads();
void renameThread();
private:
enum
@ -37,4 +39,5 @@ private:
MenuBuilder* mMenuBuilder;
CommonActions* mCommonActions;
bool isSelectionValid();
bool CallStackView::isThreadHeaderSelected();
};

View File

@ -91,6 +91,7 @@ MainWindow::MainWindow(QWidget* parent)
connect(Bridge::getBridge(), SIGNAL(getStrWindow(QString, QString*)), this, SLOT(getStrWindow(QString, QString*)));
connect(Bridge::getBridge(), SIGNAL(showCpu()), this, SLOT(displayCpuWidget()));
connect(Bridge::getBridge(), SIGNAL(showReferences()), this, SLOT(displayReferencesWidget()));
connect(Bridge::getBridge(), SIGNAL(showThreads()), this, SLOT(displayThreadsWidget()));
connect(Bridge::getBridge(), SIGNAL(addQWidgetTab(QWidget*)), this, SLOT(addQWidgetTab(QWidget*)));
connect(Bridge::getBridge(), SIGNAL(showQWidgetTab(QWidget*)), this, SLOT(showQWidgetTab(QWidget*)));
connect(Bridge::getBridge(), SIGNAL(closeQWidgetTab(QWidget*)), this, SLOT(closeQWidgetTab(QWidget*)));
@ -368,6 +369,7 @@ MainWindow::MainWindow(QWidget* parent)
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySourceManagerWidget()), this, SLOT(displaySourceViewWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(displaySymbolsWidget()), this, SLOT(displaySymbolWidget()));
connect(mThreadView, SIGNAL(displayThreadsView()), this, SLOT(displayThreadsWidget()));
connect(mCpuWidget->getDisasmWidget(), SIGNAL(showPatches()), this, SLOT(patchWindow()));
connect(mCpuWidget->getGraphWidget(), SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget()));
@ -1363,6 +1365,11 @@ void MainWindow::displayCpuWidget()
showQWidgetTab(mCpuWidget);
}
void MainWindow::displayThreadsWidget()
{
showQWidgetTab(mThreadView);
}
void MainWindow::displaySymbolWidget()
{
showQWidgetTab(mSymbolView);
@ -1378,11 +1385,6 @@ void MainWindow::displayReferencesWidget()
showQWidgetTab(mReferenceManager);
}
void MainWindow::displayThreadsWidget()
{
showQWidgetTab(mThreadView);
}
void MainWindow::displayGraphWidget()
{
showQWidgetTab(mCpuWidget);

View File

@ -80,12 +80,12 @@ public slots:
void displayBreakpointWidget();
void updateWindowTitleSlot(QString filename);
void runSlot();
void displayThreadsWidget();
void displayCpuWidget();
void displayCpuWidgetShowCpu();
void displaySymbolWidget();
void displaySourceViewWidget();
void displayReferencesWidget();
void displayThreadsWidget();
void displayVariables();
void displayGraphWidget();
void displayTraceWidget();

View File

@ -174,7 +174,7 @@ ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
loadColumnFromConfig("Thread");
//setCopyMenuOnly(true);
connect(Bridge::getBridge(), SIGNAL(selectionThreadsSet(const SELECTIONDATA*)), this, SLOT(selectionThreadsSet(const SELECTIONDATA*)));
connect(Bridge::getBridge(), SIGNAL(updateThreads()), this, SLOT(updateThreadList()));
connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot()));
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
@ -184,6 +184,23 @@ ThreadView::ThreadView(StdTable* parent) : StdTable(parent)
new DisassemblyPopup(this, Bridge::getArchitecture());
}
void ThreadView::selectionThreadsSet(const SELECTIONDATA* selection)
{
if(selection->start >= getRowCount() ||
selection->end >= getRowCount() ||
selection->start > selection->end)
{
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 0);
return;
}
mSelection.firstSelectedIndex = selection->start;
mSelection.fromIndex = selection->start;
mSelection.toIndex = selection->end;
Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 1);
emit selectionChanged(mSelection.firstSelectedIndex);
}
void ThreadView::updateThreadList()
{
THREADLIST threadList;
@ -394,12 +411,13 @@ void ThreadView::doubleClickedSlot()
void ThreadView::SetNameSlot()
{
duint threadId = getCellUserdata(getInitialSelection(), 1);
LineEditDialog mLineEdit(this);
mLineEdit.setWindowTitle(tr("Name") + threadId);
mLineEdit.setText(getCellContent(getInitialSelection(), 13));
if(mLineEdit.exec() != QDialog::Accepted)
return;
QString escapedName = mLineEdit.editText.replace("\"", "\\\"");
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadId)).arg(escapedName));
const duint threadID = getCellUserdata(getInitialSelection(), 1);
const QString currentThreadsName = getCellContent(getInitialSelection(), 13);
const QString windowTitle = QStringLiteral("%1 - %2").arg(tr("Changing Threads Name")).arg(threadID);
QString newThreadsName("");
SimpleInputBox(this, windowTitle, "", newThreadsName, "Place new threads name here...");
QString escapedName = newThreadsName.replace("\"", "\\\"");
DbgCmdExec(QString("setthreadname %1, \"%2\"").arg(ToHexString(threadID)).arg(escapedName));
}

View File

@ -10,8 +10,11 @@ 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 updateThreadList();
void doubleClickedSlot();
void ExecCommand();