Merge pull request #2573 from torusrxxx/patch000000b9
Go to function return in trace view
This commit is contained in:
commit
5a59ce27c7
|
@ -265,6 +265,8 @@ void TraceRecordManager::TraceExecuteRecord(const Zydis & newInstruction)
|
|||
// Don't try to resolve memory values for invalid/lea/nop instructions
|
||||
if(newInstruction.Success() && !newInstruction.IsNop() && newInstruction.GetId() != ZYDIS_MNEMONIC_LEA)
|
||||
{
|
||||
// This can happen when trace execute instruction is used, we need to fix that or something would go wrong with the GUI.
|
||||
newContext.registers.regcontext.cip = newInstruction.Address();
|
||||
DISASM_ARGTYPE argType;
|
||||
duint value;
|
||||
unsigned char memoryContent[memoryContentSize];
|
||||
|
|
|
@ -67,10 +67,10 @@ void ExceptionDirectoryAnalysis::Analyse()
|
|||
EnumerateFunctionRuntimeEntries64([&](PRUNTIME_FUNCTION Function)
|
||||
{
|
||||
auto funcAddr = mModuleBase + Function->BeginAddress;
|
||||
auto funcEnd = mModuleBase + Function->EndAddress;
|
||||
auto funcEnd = mModuleBase + Function->EndAddress - 1;
|
||||
|
||||
// If within limits...
|
||||
if(inRange(funcAddr) && inRange(funcEnd))
|
||||
if(inRange(funcAddr) && inRange(funcEnd) && funcAddr <= funcEnd)
|
||||
mFunctions.push_back({ funcAddr, funcEnd });
|
||||
|
||||
return true;
|
||||
|
|
|
@ -507,13 +507,36 @@ bool BpSetSingleshoot(duint Address, BP_TYPE Type, bool singleshoot)
|
|||
ASSERT_DEBUGGING("Command function call");
|
||||
EXCLUSIVE_ACQUIRE(LockBreakpoints);
|
||||
|
||||
// Set breakpoint fast resume
|
||||
// Set breakpoint singleshoot
|
||||
BREAKPOINT* bpInfo = BpInfoFromAddr(Type, Address);
|
||||
|
||||
if(!bpInfo)
|
||||
return false;
|
||||
|
||||
bpInfo->singleshoot = singleshoot;
|
||||
// Update singleshoot information in TitanEngine
|
||||
switch(Type)
|
||||
{
|
||||
case BPNORMAL:
|
||||
bpInfo->titantype = (bpInfo->titantype & ~UE_SINGLESHOOT) | (singleshoot ? UE_SINGLESHOOT : 0);
|
||||
if(IsBPXEnabled(Address) && bpInfo->enabled)
|
||||
{
|
||||
if(!DeleteBPX(Address))
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Delete breakpoint failed (DeleteBPX): %p\n"), Address);
|
||||
if(!SetBPX(Address, bpInfo->titantype, (void*)cbUserBreakpoint))
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Error setting breakpoint at %p! (SetBPX)\n"), Address);
|
||||
}
|
||||
break;
|
||||
case BPMEMORY:
|
||||
if(bpInfo->enabled)
|
||||
{
|
||||
if(!RemoveMemoryBPX(Address, bpInfo->memsize))
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Delete memory breakpoint failed (RemoveMemoryBPX): %p\n"), Address);
|
||||
if(!SetMemoryBPXEx(Address, bpInfo->memsize, bpInfo->titantype, !singleshoot, (void*)cbMemoryBreakpoint))
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Could not enable memory breakpoint %p (SetMemoryBPXEx)\n"), Address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ static bool cbDisableAllBreakpoints(const BREAKPOINT* bp)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Software breakpoints
|
||||
bool cbDebugSetBPX(int argc, char* argv[]) //bp addr [,name [,type]]
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
|
@ -325,6 +326,7 @@ bool cbDebugDisableBPX(int argc, char* argv[])
|
|||
return true;
|
||||
}
|
||||
|
||||
// Hardware breakpoints
|
||||
static bool cbDeleteAllHardwareBreakpoints(const BREAKPOINT* bp)
|
||||
{
|
||||
if(bp->type != BPHARDWARE)
|
||||
|
@ -627,6 +629,7 @@ bool cbDebugDisableHardwareBreakpoint(int argc, char* argv[])
|
|||
return true;
|
||||
}
|
||||
|
||||
// Memory breakpoints
|
||||
static bool cbDeleteAllMemoryBreakpoints(const BREAKPOINT* bp)
|
||||
{
|
||||
if(bp->type != BPMEMORY)
|
||||
|
@ -897,6 +900,7 @@ bool cbDebugDisableMemoryBreakpoint(int argc, char* argv[])
|
|||
return true;
|
||||
}
|
||||
|
||||
// DLL breakpoints
|
||||
static bool cbDeleteAllDllBreakpoints(const BREAKPOINT* bp)
|
||||
{
|
||||
if(bp->type != BPDLL || !bp->enabled)
|
||||
|
@ -1111,6 +1115,7 @@ bool cbDebugBpDllDisable(int argc, char* argv[])
|
|||
return true;
|
||||
}
|
||||
|
||||
// Exception breakpoints
|
||||
static bool cbDeleteAllExceptionBreakpoints(const BREAKPOINT* bp)
|
||||
{
|
||||
if(bp->type != BPEXCEPTION)
|
||||
|
|
|
@ -760,7 +760,14 @@ static void handleBreakCondition(const BREAKPOINT & bp, const void* ExceptionAdd
|
|||
if(doBreak)
|
||||
{
|
||||
if(bp.singleshoot)
|
||||
{
|
||||
BpDelete(bp.addr, bp.type);
|
||||
if(bp.type == BPHARDWARE) // Remove this singleshoot hardware breakpoint
|
||||
{
|
||||
if(TITANDRXVALID(bp.titantype) && !DeleteHardwareBreakPoint(TITANGETDRX(bp.titantype)))
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Delete hardware breakpoint failed: %p (DeleteHardwareBreakPoint)\n"), bp.addr);
|
||||
}
|
||||
}
|
||||
if(!bp.silent)
|
||||
{
|
||||
switch(bp.type)
|
||||
|
@ -1208,26 +1215,24 @@ static void cbRtrFinalStep(bool checkRepeat = false)
|
|||
void cbRtrStep()
|
||||
{
|
||||
hActiveThread = ThreadGetHandle(((DEBUG_EVENT*)GetDebugData())->dwThreadId);
|
||||
unsigned char ch = 0x90;
|
||||
unsigned char data[MAX_DISASM_BUFFER];
|
||||
memset(data, 0x90, sizeof(data));
|
||||
duint cip = GetContextDataEx(hActiveThread, UE_CIP);
|
||||
duint csp = GetContextDataEx(hActiveThread, UE_CSP);
|
||||
MemRead(cip, &ch, 1);
|
||||
MemRead(cip, data, sizeof(data));
|
||||
if(bTraceRecordEnabledDuringTrace)
|
||||
_dbg_dbgtraceexecute(cip);
|
||||
if(mRtrPreviousCSP <= csp) //"Run until return" should break only if RSP is bigger than or equal to current value
|
||||
{
|
||||
if(ch == 0xC3 || ch == 0xC2) //retn instruction
|
||||
if(data[0] == 0xC3 || data[0] == 0xC2) //retn instruction
|
||||
cbRtrFinalStep(true);
|
||||
else if(ch == 0x26 || ch == 0x36 || ch == 0x2e || ch == 0x3e || (ch >= 0x64 && ch <= 0x67) || ch == 0xf2 || ch == 0xf3 //instruction prefixes
|
||||
else if(data[0] == 0x26 || data[0] == 0x36 || data[0] == 0x2e || data[0] == 0x3e || (data[0] >= 0x64 && data[0] <= 0x67) || data[0] == 0xf2 || data[0] == 0xf3 //instruction prefixes
|
||||
#ifdef _WIN64
|
||||
|| (ch >= 0x40 && ch <= 0x4f)
|
||||
|| (data[0] >= 0x40 && data[0] <= 0x4f)
|
||||
#endif //_WIN64
|
||||
)
|
||||
{
|
||||
Zydis cp;
|
||||
unsigned char data[MAX_DISASM_BUFFER];
|
||||
memset(data, 0, sizeof(data));
|
||||
MemRead(cip, data, MAX_DISASM_BUFFER);
|
||||
if(cp.Disassemble(cip, data) && cp.IsRet())
|
||||
cbRtrFinalStep(true);
|
||||
else
|
||||
|
|
|
@ -46,6 +46,7 @@ CPURegistersView::CPURegistersView(CPUWidget* parent) : RegistersView(parent), m
|
|||
wCM_FollowInDump = new QAction(DIcon("dump.png"), tr("Follow in Dump"), this);
|
||||
wCM_FollowInStack = new QAction(DIcon("stack.png"), tr("Follow in Stack"), this);
|
||||
wCM_FollowInMemoryMap = new QAction(DIcon("memmap_find_address_page"), tr("Follow in Memory Map"), this);
|
||||
wCM_RemoveHardware = new QAction(DIcon("breakpoint_remove.png"), tr("&Remove hardware breakpoint"), this);
|
||||
wCM_Incrementx87Stack = setupAction(DIcon("arrow-small-down.png"), tr("Increment x87 Stack"), this);
|
||||
wCM_Decrementx87Stack = setupAction(DIcon("arrow-small-up.png"), tr("Decrement x87 Stack"), this);
|
||||
wCM_ChangeFPUView = new QAction(DIcon("change-view.png"), tr("Change view"), this);
|
||||
|
@ -163,6 +164,7 @@ CPURegistersView::CPURegistersView(CPUWidget* parent) : RegistersView(parent), m
|
|||
connect(wCM_FollowInDump, SIGNAL(triggered()), this, SLOT(onFollowInDump()));
|
||||
connect(wCM_FollowInStack, SIGNAL(triggered()), this, SLOT(onFollowInStack()));
|
||||
connect(wCM_FollowInMemoryMap, SIGNAL(triggered()), this, SLOT(onFollowInMemoryMap()));
|
||||
connect(wCM_RemoveHardware, SIGNAL(triggered()), this, SLOT(onRemoveHardware()));
|
||||
connect(wCM_IncrementPtrSize, SIGNAL(triggered()), this, SLOT(onIncrementPtrSize()));
|
||||
connect(wCM_DecrementPtrSize, SIGNAL(triggered()), this, SLOT(onDecrementPtrSize()));
|
||||
connect(wCM_Push, SIGNAL(triggered()), this, SLOT(onPushAction()));
|
||||
|
@ -770,6 +772,15 @@ void CPURegistersView::onFollowInMemoryMap()
|
|||
}
|
||||
}
|
||||
|
||||
void CPURegistersView::onRemoveHardware()
|
||||
{
|
||||
if(mSelected == DR0 || mSelected == DR1 || mSelected == DR2 || mSelected == DR3)
|
||||
{
|
||||
QString addr = QString("%1").arg((* ((duint*) registerValue(&wRegDumpStruct, mSelected))), mRegisterPlaces[mSelected].valuesize, 16, QChar('0')).toUpper();
|
||||
DbgCmdExec(QString().sprintf("bphc \"%s\"", addr.toUtf8().constData()));
|
||||
}
|
||||
}
|
||||
|
||||
void CPURegistersView::displayCustomContextMenuSlot(QPoint pos)
|
||||
{
|
||||
if(!isActive)
|
||||
|
@ -854,6 +865,12 @@ void CPURegistersView::displayCustomContextMenuSlot(QPoint pos)
|
|||
}
|
||||
}
|
||||
|
||||
if(mSelected == DR0 || mSelected == DR1 || mSelected == DR2 || mSelected == DR3)
|
||||
{
|
||||
if(* ((duint*) registerValue(&wRegDumpStruct, mSelected)) != 0)
|
||||
wMenu.addAction(wCM_RemoveHardware);
|
||||
}
|
||||
|
||||
wMenu.addAction(wCM_CopyToClipboard);
|
||||
if(mFPUx87_80BITSDISPLAY.contains(mSelected))
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@ protected slots:
|
|||
void onFollowInDumpN();
|
||||
void onFollowInStack();
|
||||
void onFollowInMemoryMap();
|
||||
void onRemoveHardware();
|
||||
void onIncrementPtrSize();
|
||||
void onDecrementPtrSize();
|
||||
void onPushAction();
|
||||
|
@ -78,6 +79,7 @@ private:
|
|||
QAction* wCM_FollowInDump;
|
||||
QAction* wCM_FollowInStack;
|
||||
QAction* wCM_FollowInMemoryMap;
|
||||
QAction* wCM_RemoveHardware;
|
||||
QAction* wCM_Incrementx87Stack;
|
||||
QAction* wCM_Decrementx87Stack;
|
||||
QAction* wCM_ChangeFPUView;
|
||||
|
|
|
@ -876,6 +876,7 @@ void TraceBrowser::setupRightClickContextMenu()
|
|||
});
|
||||
MenuBuilder* gotoMenu = new MenuBuilder(this, isValid);
|
||||
gotoMenu->addAction(makeShortcutAction(DIcon("goto.png"), tr("Expression"), SLOT(gotoSlot()), "ActionGotoExpression"), isValid);
|
||||
gotoMenu->addAction(makeAction(DIcon("arrow-step-rtr.png"), tr("Function return"), SLOT(rtrSlot())), isValid);
|
||||
gotoMenu->addAction(makeShortcutAction(DIcon("previous.png"), tr("Previous"), SLOT(gotoPreviousSlot()), "ActionGotoPrevious"), [this](QMenu*)
|
||||
{
|
||||
return mHistory.historyHasPrev();
|
||||
|
@ -1330,7 +1331,7 @@ void TraceBrowser::parseFinishedSlot()
|
|||
{
|
||||
if(mTraceFile->isError())
|
||||
{
|
||||
SimpleErrorBox(this, tr("Error"), "Error when opening run trace file");
|
||||
SimpleErrorBox(this, tr("Error"), tr("Error when opening run trace file"));
|
||||
delete mTraceFile;
|
||||
mTraceFile = nullptr;
|
||||
setRowCount(0);
|
||||
|
@ -1370,6 +1371,16 @@ void TraceBrowser::mnemonicHelpSlot()
|
|||
emit displayLogWidget();
|
||||
}
|
||||
|
||||
void TraceBrowser::disasm(unsigned long long index, bool history)
|
||||
{
|
||||
setSingleSelection(index);
|
||||
makeVisible(index);
|
||||
if(history)
|
||||
mHistory.addVaToHistory(index);
|
||||
updateViewport();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
}
|
||||
|
||||
void TraceBrowser::gotoSlot()
|
||||
{
|
||||
if(mTraceFile == nullptr || mTraceFile->Progress() < 100)
|
||||
|
@ -1379,37 +1390,26 @@ void TraceBrowser::gotoSlot()
|
|||
{
|
||||
auto val = DbgValFromString(gotoDlg.expressionText.toUtf8().constData());
|
||||
if(val >= 0 && val < mTraceFile->Length())
|
||||
disasm(val);
|
||||
}
|
||||
}
|
||||
|
||||
void TraceBrowser::rtrSlot()
|
||||
{
|
||||
setSingleSelection(val);
|
||||
makeVisible(val);
|
||||
mHistory.addVaToHistory(val);
|
||||
updateViewport();
|
||||
}
|
||||
}
|
||||
// Let's hope this search will be fast...
|
||||
disasm(TraceFileSearchFuncReturn(mTraceFile, getInitialSelection()));
|
||||
}
|
||||
|
||||
void TraceBrowser::gotoNextSlot()
|
||||
{
|
||||
if(mHistory.historyHasNext())
|
||||
{
|
||||
auto index = mHistory.historyNext();
|
||||
setSingleSelection(index);
|
||||
makeVisible(index);
|
||||
updateViewport();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
}
|
||||
disasm(mHistory.historyNext(), false);
|
||||
}
|
||||
|
||||
void TraceBrowser::gotoPreviousSlot()
|
||||
{
|
||||
if(mHistory.historyHasPrev())
|
||||
{
|
||||
auto index = mHistory.historyPrev();
|
||||
setSingleSelection(index);
|
||||
makeVisible(index);
|
||||
updateViewport();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
}
|
||||
disasm(mHistory.historyPrev(), false);
|
||||
}
|
||||
|
||||
void TraceBrowser::copyCipSlot()
|
||||
|
|
|
@ -160,6 +160,7 @@ public slots:
|
|||
void onSelectionChanged(unsigned long long selection);
|
||||
|
||||
void gotoSlot();
|
||||
void rtrSlot();
|
||||
void gotoPreviousSlot();
|
||||
void gotoNextSlot();
|
||||
void enableHighlightingModeSlot();
|
||||
|
@ -182,6 +183,9 @@ public slots:
|
|||
void updateSlot();
|
||||
|
||||
void toggleAutoDisassemblyFollowSelectionSlot();
|
||||
|
||||
protected:
|
||||
void disasm(unsigned long long index, bool history = true);
|
||||
};
|
||||
|
||||
#endif //TRACEBROWSER_H
|
||||
|
|
|
@ -12,7 +12,7 @@ static bool inRange(duint value, duint start, duint end)
|
|||
int TraceFileSearchConstantRange(TraceFileReader* file, duint start, duint end)
|
||||
{
|
||||
int count = 0;
|
||||
Zydis cp;
|
||||
Zydis zy;
|
||||
QString title;
|
||||
if(start == end)
|
||||
title = QCoreApplication::translate("TraceFileSearch", "Constant: %1").arg(ToPtrString(start));
|
||||
|
@ -77,8 +77,8 @@ int TraceFileSearchConstantRange(TraceFileReader* file, duint start, duint end)
|
|||
unsigned char opcode[16];
|
||||
int opcodeSize = 0;
|
||||
file->OpCode(index, opcode, &opcodeSize);
|
||||
cp.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize);
|
||||
GuiReferenceSetCellContent(count, 2, cp.InstructionText(true).c_str());
|
||||
zy.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize);
|
||||
GuiReferenceSetCellContent(count, 2, zy.InstructionText(true).c_str());
|
||||
//GuiReferenceSetCurrentTaskProgress; GuiReferenceSetProgress
|
||||
count++;
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ int TraceFileSearchConstantRange(TraceFileReader* file, duint start, duint end)
|
|||
int TraceFileSearchMemReference(TraceFileReader* file, duint address)
|
||||
{
|
||||
int count = 0;
|
||||
Zydis cp;
|
||||
Zydis zy;
|
||||
GuiReferenceInitialize(QCoreApplication::translate("TraceFileSearch", "Reference").toUtf8().constData());
|
||||
GuiReferenceAddColumn(sizeof(duint) * 2, QCoreApplication::translate("TraceFileSearch", "Address").toUtf8().constData());
|
||||
GuiReferenceAddColumn(sizeof(duint) * 2, QCoreApplication::translate("TraceFileSearch", "Index").toUtf8().constData());
|
||||
|
@ -122,8 +122,8 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address)
|
|||
unsigned char opcode[16];
|
||||
int opcodeSize = 0;
|
||||
file->OpCode(index, opcode, &opcodeSize);
|
||||
cp.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize);
|
||||
GuiReferenceSetCellContent(count, 2, cp.InstructionText(true).c_str());
|
||||
zy.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize);
|
||||
GuiReferenceSetCellContent(count, 2, zy.InstructionText(true).c_str());
|
||||
//GuiReferenceSetCurrentTaskProgress; GuiReferenceSetProgress
|
||||
count++;
|
||||
}
|
||||
|
@ -131,3 +131,31 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address)
|
|||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
unsigned long long TraceFileSearchFuncReturn(TraceFileReader* file, unsigned long long start)
|
||||
{
|
||||
auto mCsp = file->Registers(start).regcontext.csp;
|
||||
auto TID = file->ThreadId(start);
|
||||
Zydis zy;
|
||||
for(unsigned long long index = start; index < file->Length(); index++)
|
||||
{
|
||||
if(mCsp <= file->Registers(index).regcontext.csp && file->ThreadId(index) == TID) //"Run until return" should break only if RSP is bigger than or equal to current value
|
||||
{
|
||||
unsigned char data[16];
|
||||
int opcodeSize = 0;
|
||||
file->OpCode(index, data, &opcodeSize);
|
||||
if(data[0] == 0xC3 || data[0] == 0xC2) //retn instruction
|
||||
return index;
|
||||
else if(data[0] == 0x26 || data[0] == 0x36 || data[0] == 0x2e || data[0] == 0x3e || (data[0] >= 0x64 && data[0] <= 0x67) || data[0] == 0xf2 || data[0] == 0xf3 //instruction prefixes
|
||||
#ifdef _WIN64
|
||||
|| (data[0] >= 0x40 && data[0] <= 0x4f)
|
||||
#endif //_WIN64
|
||||
)
|
||||
{
|
||||
if(zy.Disassemble(file->Registers(index).regcontext.cip, data, opcodeSize) && zy.IsRet())
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return start; //Nothing found, so just stay here
|
||||
}
|
||||
|
|
|
@ -5,4 +5,5 @@ class TraceFileReader;
|
|||
|
||||
int TraceFileSearchConstantRange(TraceFileReader* file, duint start, duint end);
|
||||
int TraceFileSearchMemReference(TraceFileReader* file, duint address);
|
||||
unsigned long long TraceFileSearchFuncReturn(TraceFileReader* file, unsigned long long start);
|
||||
#endif //TRACEFILESEARCH_H
|
||||
|
|
Loading…
Reference in New Issue