Show suspected call stack frame, and fix a bug (#1282)
* show suspected call stack frame * log hyperlink never works on 32-bit platform * update * Party in call stack view
This commit is contained in:
parent
1bf7b1298b
commit
ec14fb5813
|
@ -899,6 +899,7 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
|
|||
bSkipInt3Stepping = settingboolget("Engine", "SkipInt3Stepping");
|
||||
bIgnoreInconsistentBreakpoints = settingboolget("Engine", "IgnoreInconsistentBreakpoints");
|
||||
bNoForegroundWindow = settingboolget("Gui", "NoForegroundWindow");
|
||||
stackupdatesettings();
|
||||
|
||||
duint setting;
|
||||
if(BridgeSettingGetUint("Engine", "BreakpointType", &setting))
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
using SehMap = std::unordered_map<duint, STACK_COMMENT>;
|
||||
static SehMap SehCache;
|
||||
bool ShowSuspectedCallStack;
|
||||
|
||||
void stackupdateseh()
|
||||
{
|
||||
|
@ -183,6 +184,49 @@ void stackupdatecallstack(duint csp)
|
|||
stackgetcallstack(csp, callstack, false);
|
||||
}
|
||||
|
||||
static void stackgetsuspectedcallstack(duint csp, std::vector<CALLSTACKENTRY> & callstackVector)
|
||||
{
|
||||
duint size;
|
||||
duint base = MemFindBaseAddr(csp, &size);
|
||||
duint end = base + size;
|
||||
size = end - csp;
|
||||
Memory<duint*> stackdata(size);
|
||||
MemRead(csp, stackdata(), size);
|
||||
for(duint i = csp; i < end; i += sizeof(duint))
|
||||
{
|
||||
duint data = stackdata()[(i - csp) / sizeof(duint)];
|
||||
duint size = 0;
|
||||
duint base = MemFindBaseAddr(data, &size);
|
||||
duint readStart = data - 16 * 4;
|
||||
if(readStart < base)
|
||||
readStart = base;
|
||||
unsigned char disasmData[256];
|
||||
if(base != 0 && size != 0 && MemRead(readStart, disasmData, sizeof(disasmData)))
|
||||
{
|
||||
duint prev = disasmback(disasmData, 0, sizeof(disasmData), data - readStart, 1);
|
||||
duint previousInstr = readStart + prev;
|
||||
|
||||
BASIC_INSTRUCTION_INFO basicinfo;
|
||||
bool valid = disasmfast(disasmData + prev, previousInstr, &basicinfo);
|
||||
if(valid && basicinfo.call)
|
||||
{
|
||||
CALLSTACKENTRY stackframe;
|
||||
stackframe.addr = i;
|
||||
stackframe.to = data;
|
||||
char returnToAddr[MAX_COMMENT_SIZE] = "";
|
||||
getSymAddrName(data, returnToAddr);
|
||||
|
||||
data = basicinfo.addr;
|
||||
char returnFromAddr[MAX_COMMENT_SIZE] = "";
|
||||
getSymAddrName(data, returnFromAddr);
|
||||
sprintf_s(stackframe.comment, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "return to %s from %s")), returnToAddr, returnFromAddr);
|
||||
stackframe.from = data;
|
||||
callstackVector.push_back(stackframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stackgetcallstack(duint csp, std::vector<CALLSTACKENTRY> & callstackVector, bool cache)
|
||||
{
|
||||
if(cache)
|
||||
|
@ -213,63 +257,70 @@ void stackgetcallstack(duint csp, std::vector<CALLSTACKENTRY> & callstackVector,
|
|||
if(ResumeThread(hActiveThread) == -1)
|
||||
return;
|
||||
|
||||
// Set up all frame data
|
||||
STACKFRAME64 frame;
|
||||
ZeroMemory(&frame, sizeof(STACKFRAME64));
|
||||
if(ShowSuspectedCallStack)
|
||||
{
|
||||
stackgetsuspectedcallstack(csp, callstackVector);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set up all frame data
|
||||
STACKFRAME64 frame;
|
||||
ZeroMemory(&frame, sizeof(STACKFRAME64));
|
||||
|
||||
#ifdef _M_IX86
|
||||
DWORD machineType = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = csp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD machineType = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = csp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_X64
|
||||
DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rsp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = csp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rsp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = csp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
const int MaxWalks = 50;
|
||||
// Container for each callstack entry (50 pre-allocated entries)
|
||||
callstackVector.clear();
|
||||
callstackVector.reserve(MaxWalks);
|
||||
const int MaxWalks = 50;
|
||||
// Container for each callstack entry (50 pre-allocated entries)
|
||||
callstackVector.clear();
|
||||
callstackVector.reserve(MaxWalks);
|
||||
|
||||
for(auto i = 0; i < MaxWalks; i++)
|
||||
{
|
||||
if(!StackWalk64(
|
||||
machineType,
|
||||
fdProcessInfo->hProcess,
|
||||
hActiveThread,
|
||||
&frame,
|
||||
&context,
|
||||
StackReadProcessMemoryProc64,
|
||||
SymFunctionTableAccess64,
|
||||
StackGetModuleBaseProc64,
|
||||
StackTranslateAddressProc64))
|
||||
for(auto i = 0; i < MaxWalks; i++)
|
||||
{
|
||||
// Maybe it failed, maybe we have finished walking the stack
|
||||
break;
|
||||
}
|
||||
if(!StackWalk64(
|
||||
machineType,
|
||||
fdProcessInfo->hProcess,
|
||||
hActiveThread,
|
||||
&frame,
|
||||
&context,
|
||||
StackReadProcessMemoryProc64,
|
||||
SymFunctionTableAccess64,
|
||||
StackGetModuleBaseProc64,
|
||||
StackTranslateAddressProc64))
|
||||
{
|
||||
// Maybe it failed, maybe we have finished walking the stack
|
||||
break;
|
||||
}
|
||||
|
||||
if(frame.AddrPC.Offset != 0)
|
||||
{
|
||||
// Valid frame
|
||||
CALLSTACKENTRY entry;
|
||||
memset(&entry, 0, sizeof(CALLSTACKENTRY));
|
||||
if(frame.AddrPC.Offset != 0)
|
||||
{
|
||||
// Valid frame
|
||||
CALLSTACKENTRY entry;
|
||||
memset(&entry, 0, sizeof(CALLSTACKENTRY));
|
||||
|
||||
StackEntryFromFrame(&entry, (duint)frame.AddrFrame.Offset + sizeof(duint), (duint)frame.AddrPC.Offset, (duint)frame.AddrReturn.Offset);
|
||||
callstackVector.push_back(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Base reached
|
||||
break;
|
||||
StackEntryFromFrame(&entry, (duint)frame.AddrFrame.Offset + sizeof(duint), (duint)frame.AddrPC.Offset, (duint)frame.AddrReturn.Offset);
|
||||
callstackVector.push_back(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Base reached
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,4 +345,11 @@ void stackgetcallstack(duint csp, CALLSTACK* callstack)
|
|||
// Copy data directly from the vector
|
||||
memcpy(callstack->entries, callstackVector.data(), callstack->total * sizeof(CALLSTACKENTRY));
|
||||
}
|
||||
}
|
||||
|
||||
void stackupdatesettings()
|
||||
{
|
||||
ShowSuspectedCallStack = settingboolget("Engine", "ShowSuspectedCallStack");
|
||||
std::vector<CALLSTACKENTRY> dummy;
|
||||
stackgetcallstack(GetContextDataEx(hActiveThread, UE_CSP), dummy, false);
|
||||
}
|
|
@ -22,5 +22,6 @@ bool stackcommentget(duint addr, STACK_COMMENT* comment);
|
|||
void stackupdatecallstack(duint csp);
|
||||
void stackgetcallstack(duint csp, CALLSTACK* callstack);
|
||||
void stackgetcallstack(duint csp, std::vector<CALLSTACKENTRY> & callstack, bool cache);
|
||||
void stackupdatesettings();
|
||||
|
||||
#endif //_STACKINFO_H
|
|
@ -50,6 +50,7 @@ CPUStack::CPUStack(CPUMultiDump* multiDump, QWidget* parent) : HexDump(parent)
|
|||
connect(Bridge::getBridge(), SIGNAL(selectionStackSet(const SELECTIONDATA*)), this, SLOT(selectionSet(const SELECTIONDATA*)));
|
||||
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(dbgStateChangedSlot(DBGSTATE)));
|
||||
connect(Bridge::getBridge(), SIGNAL(focusStack()), this, SLOT(setFocus()));
|
||||
connect(Bridge::getBridge(), SIGNAL(updateDump()), this, SLOT(updateSlot()));
|
||||
|
||||
connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot()));
|
||||
|
||||
|
@ -569,6 +570,36 @@ void CPUStack::stackDumpAt(duint addr, duint csp)
|
|||
printDumpAt(addr);
|
||||
}
|
||||
|
||||
void CPUStack::updateSlot()
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
// Get the callstack
|
||||
DBGCALLSTACK callstack;
|
||||
memset(&callstack, 0, sizeof(DBGCALLSTACK));
|
||||
DbgFunctions()->GetCallStack(&callstack);
|
||||
mCallstack.resize(callstack.total);
|
||||
if(mCallstack.size())
|
||||
{
|
||||
// callstack data highest >> lowest
|
||||
std::qsort(callstack.entries, callstack.total, sizeof(DBGCALLSTACKENTRY), [](const void* a, const void* b)
|
||||
{
|
||||
auto p = (const DBGCALLSTACKENTRY*)a;
|
||||
auto q = (const DBGCALLSTACKENTRY*)b;
|
||||
if(p->addr < q->addr)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
});
|
||||
for(size_t i = 0; i < mCallstack.size(); i++)
|
||||
{
|
||||
mCallstack[i].addr = callstack.entries[i].addr;
|
||||
mCallstack[i].party = DbgFunctions()->ModGetParty(callstack.entries[i].to);
|
||||
}
|
||||
BridgeFree(callstack.entries);
|
||||
}
|
||||
}
|
||||
|
||||
void CPUStack::gotoCspSlot()
|
||||
{
|
||||
DbgCmdExec("sdump csp");
|
||||
|
|
|
@ -74,6 +74,7 @@ public slots:
|
|||
void dbgStateChangedSlot(DBGSTATE state);
|
||||
void followInMemoryMapSlot();
|
||||
void followInDumpSlot();
|
||||
void updateSlot();
|
||||
|
||||
private:
|
||||
duint mCsp;
|
||||
|
|
|
@ -9,7 +9,8 @@ CallStackView::CallStackView(StdTable* parent) : StdTable(parent)
|
|||
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("To"), true); //return to
|
||||
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("From"), true); //return from
|
||||
addColumnAt(8 + charwidth * sizeof(dsint) * 2, tr("Size"), true); //size
|
||||
addColumnAt(10, tr("Comment"), true);
|
||||
addColumnAt(50 * charwidth, tr("Comment"), true);
|
||||
addColumnAt(8 * charwidth, tr("Party"), true); //party
|
||||
loadColumnFromConfig("CallStack");
|
||||
|
||||
connect(Bridge::getBridge(), SIGNAL(updateCallStack()), this, SLOT(updateCallStack()));
|
||||
|
@ -35,6 +36,19 @@ void CallStackView::setupContextMenu()
|
|||
{
|
||||
return !getCellContent(getInitialSelection(), 2).isEmpty();
|
||||
});
|
||||
mMenuBuilder->addSeparator();
|
||||
QAction* wShowSuspectedCallStack = makeAction(tr("Show Suspected Call Stack Frame"), SLOT(showSuspectedCallStack()));
|
||||
mMenuBuilder->addAction(wShowSuspectedCallStack, [wShowSuspectedCallStack](QMenu*)
|
||||
{
|
||||
duint i;
|
||||
if(!BridgeSettingGetUint("Engine", "ShowSuspectedCallStack", &i))
|
||||
i = 0;
|
||||
if(i != 0)
|
||||
wShowSuspectedCallStack->setText(tr("Show Active Call Stack Frame"));
|
||||
else
|
||||
wShowSuspectedCallStack->setText(tr("Show Suspected Call Stack Frame"));
|
||||
return true;
|
||||
});
|
||||
MenuBuilder* mCopyMenu = new MenuBuilder(this);
|
||||
setupCopyMenu(mCopyMenu);
|
||||
// Column count cannot be zero
|
||||
|
@ -67,6 +81,19 @@ void CallStackView::updateCallStack()
|
|||
else
|
||||
setCellContent(i, 3, "");
|
||||
setCellContent(i, 4, callstack.entries[i].comment);
|
||||
int party = DbgFunctions()->ModGetParty(callstack.entries[i].to);
|
||||
switch(party)
|
||||
{
|
||||
case 0:
|
||||
setCellContent(i, 5, tr("User"));
|
||||
break;
|
||||
case 1:
|
||||
setCellContent(i, 5, tr("System"));
|
||||
break;
|
||||
default:
|
||||
setCellContent(i, 5, QString("%1").arg(party));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(callstack.total)
|
||||
BridgeFree(callstack.entries);
|
||||
|
@ -97,3 +124,15 @@ void CallStackView::followFrom()
|
|||
QString addrText = getCellContent(getInitialSelection(), 2);
|
||||
DbgCmdExecDirect(QString("disasm " + addrText).toUtf8().constData());
|
||||
}
|
||||
|
||||
void CallStackView::showSuspectedCallStack()
|
||||
{
|
||||
duint i;
|
||||
if(!BridgeSettingGetUint("Engine", "ShowSuspectedCallStack", &i))
|
||||
i = 0;
|
||||
i = (i == 0) ? 1 : 0;
|
||||
BridgeSettingSetUint("Engine", "ShowSuspectedCallStack", i);
|
||||
DbgSettingsUpdated();
|
||||
updateCallStack();
|
||||
emit Bridge::getBridge()->updateDump();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ protected slots:
|
|||
void followAddress();
|
||||
void followTo();
|
||||
void followFrom();
|
||||
void showSuspectedCallStack();
|
||||
|
||||
private:
|
||||
MenuBuilder* mMenuBuilder;
|
||||
|
|
|
@ -207,7 +207,7 @@ void LogView::onAnchorClicked(const QUrl & link)
|
|||
if(DbgIsDebugging())
|
||||
{
|
||||
bool ok = false;
|
||||
duint address = link.fragment(QUrl::DecodeReserved).toULong(&ok);
|
||||
duint address = link.fragment(QUrl::DecodeReserved).toULong(&ok, 16);
|
||||
if(ok)
|
||||
{
|
||||
if(DbgFunctions()->MemIsCodePage(address, true))
|
||||
|
|
|
@ -202,6 +202,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
|
||||
QMap<QString, bool> engineBool;
|
||||
engineBool.insert("ListAllPages", false);
|
||||
engineBool.insert("ShowSuspectedCallStack", false);
|
||||
defaultBools.insert("Engine", engineBool);
|
||||
|
||||
QMap<QString, bool> miscellaneousBool;
|
||||
|
@ -244,7 +245,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "DLLBreakpoint", 8);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "ExceptionBreakpoint", 8);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "MemoryMap", 8);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "CallStack", 5);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "CallStack", 6);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "SEH", 4);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Script", 3);
|
||||
AbstractTableView::setupColumnConfigDefaultValue(guiUint, "Thread", 14);
|
||||
|
|
Loading…
Reference in New Issue