1
0
Fork 0

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:
Torusrxxx 2016-11-22 18:03:57 +00:00 committed by Duncan Ogilvie
parent 1bf7b1298b
commit ec14fb5813
9 changed files with 184 additions and 51 deletions

View File

@ -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))

View File

@ -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);
}

View File

@ -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

View File

@ -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");

View File

@ -74,6 +74,7 @@ public slots:
void dbgStateChangedSlot(DBGSTATE state);
void followInMemoryMapSlot();
void followInDumpSlot();
void updateSlot();
private:
duint mCsp;

View File

@ -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();
}

View File

@ -16,6 +16,7 @@ protected slots:
void followAddress();
void followTo();
void followFrom();
void showSuspectedCallStack();
private:
MenuBuilder* mMenuBuilder;

View File

@ -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))

View File

@ -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);