Introducing showthreadid command
Additional options in CallStackView
This commit is contained in:
parent
b0392eda1c
commit
c9d80e5c99
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue