From 1b5391953b64cb9da26e8f865917e62edf934bb5 Mon Sep 17 00:00:00 2001 From: clc5q <clc5q@git.zephyr-software.com> Date: Thu, 13 Dec 2007 22:31:53 +0000 Subject: [PATCH] Add SMPFunction::FindAllocPoint method to find end of stack frame allocation when it is done by pushes, e.g. in strpbrk(). --- SMPDataFlowAnalysis.cpp | 110 ++++++++++++++++++++++++++++++++++++---- SMPDataFlowAnalysis.h | 1 + 2 files changed, 101 insertions(+), 10 deletions(-) diff --git a/SMPDataFlowAnalysis.cpp b/SMPDataFlowAnalysis.cpp index 91aab70e..b9be5af9 100644 --- a/SMPDataFlowAnalysis.cpp +++ b/SMPDataFlowAnalysis.cpp @@ -867,10 +867,7 @@ void SMPFunction::SetStackFrameInfo(void) { // local vars. This code could be made more robust in the future // by matching LocalVarsSize to the immediate value in the allocation // instruction. However, IDA Pro is sometimes a little off on this - // number, claiming 4 bytes for functions with no locals at all, - // assigning the 4 bytes used for a callee-saved register to the - // local vars space and then claiming 0 bytes for callee-saved - // registers. **!!** + // number. **!!** if (0 < this->LocalVarsSize) { for (list<SMPInstr>::iterator CurrInstr = this->Instrs.begin(); CurrInstr != this->Instrs.end(); @@ -913,13 +910,23 @@ void SMPFunction::SetStackFrameInfo(void) { if (!FoundAllocInstr) { // Could not find the frame allocating instruction. Bad. // Emit diagnostic and use the first instruction in the - // function. - msg("ERROR: Could not find stack frame allocation in %s\n", - FuncName); - msg("LocalVarsSize: %d SavedRegsSize: %d ArgsSize: %d\n", - LocalVarsSize, CalleeSavedRegsSize, IncomingArgsSize); - this->LocalVarsAllocInstr = this->FuncInfo->startEA; + // function as a pseudo-allocation instruction to emit + // some stack frame info (return address, etc.) + this->LocalVarsAllocInstr = this->FindAllocPoint(this->FuncInfo->frsize); +#if SMP_DEBUG_FRAMEFIXUP + if (BADADDR == this->LocalVarsAllocInstr) { + msg("ERROR: Could not find stack frame allocation in %s\n", + FuncName); + msg("LocalVarsSize: %d SavedRegsSize: %d ArgsSize: %d\n", + LocalVarsSize, CalleeSavedRegsSize, IncomingArgsSize); + } + else { + msg("FindAllocPoint found %x for function %s\n", + this->LocalVarsAllocInstr, this->GetFuncName()); + } +#endif } +#if SMP_DEBUG_FIX_FRAMEINFO if (!FoundDeallocInstr) { // Could not find the frame deallocating instruction. Bad. // Emit diagnostic and use the last instruction in the @@ -927,6 +934,7 @@ void SMPFunction::SetStackFrameInfo(void) { msg("ERROR: Could not find stack frame deallocation in %s\n", FuncName); } +#endif } // else LocalVarsSize was zero, meaning that we need to search // for the end of the function prologue code and emit stack frame @@ -1166,6 +1174,88 @@ bool SMPFunction::MDFixFrameInfo(void) { return Changed; } // end of SMPFunction::MDFixFrameInfo() +// Some functions have difficult to find stack allocations. For example, in some +// version of glibc, strpbrk() zeroes out register ECX and then pushes it more than +// 100 times in order to allocate zero-ed out local vars space for a character translation +// table. We will use the stack pointer analysis of IDA to find out if there is a point +// in the first basic block at which the stack pointer reaches the allocation total +// that IDA is expecting for the local vars region. +// If so, we return the address of the instruction at which ESP reaches its value, else +// we return BADADDR. +ea_t SMPFunction::FindAllocPoint(asize_t OriginalLocSize) { + bool DebugFlag = (0 == strncmp("strpbrk", this->GetFuncName(), 7)); + sval_t TargetSize = - ((sval_t) OriginalLocSize); // negate; stack grows down + +#if SMP_DEBUG_FRAMEFIXUP + if (DebugFlag) + msg("strpbrk OriginalLocSize: %d\n", OriginalLocSize); +#endif + + if (this->FuncInfo->analyzed_sp()) { + // Limit our analysis to the first basic block in the function. + ea_t AddrLimit = this->Blocks.front().GetLastInstr()->GetAddr(); + for (list<SMPInstr>::iterator CurrInstr = this->Blocks.front().GetFirstInstr(); + CurrInstr != this->Blocks.front().GetLastInstr(); + ++CurrInstr) { + ea_t addr = CurrInstr->GetAddr(); + // get_spd() returns a cumulative delta of ESP + sval_t sp_delta = get_spd(this->FuncInfo, addr); +#if SMP_DEBUG_FRAMEFIXUP + if (DebugFlag) + msg("strpbrk delta: %d at %x\n", sp_delta, addr); +#endif + if (sp_delta == TargetSize) { + // Previous instruction hit the frame size. + if (CurrInstr == this->Blocks.front().GetFirstInstr()) { + return BADADDR; // cannot back up from first instruction + } + else { + return (--CurrInstr)->GetAddr(); + } + } + } + // SP delta is marked at the beginning of an instruction to show the SP + // after the effects of the previous instruction. Maybe the last instruction + // is the first time the SP shows its desired value. + list<SMPInstr>::iterator FinalInstr = this->Blocks.front().GetLastInstr(); + ea_t FinalAddr = FinalInstr->GetAddr(); + sval_t FinalDelta = get_spd(this->FuncInfo, FinalAddr); +#if SMP_DEBUG_FRAMEFIXUP + if (DebugFlag) + msg("strpbrk FinalDelta: %d\n", FinalDelta); +#endif + if (TargetSize == FinalDelta) { + // Back up one instruction + if (FinalAddr == this->Blocks.front().GetFirstInstr()->GetAddr()) { + return BADADDR; // cannot back up from first instruction + } + else { + return (--FinalInstr)->GetAddr(); + } + } + else if (!FinalInstr->IsBasicBlockTerminator()) { + // Special case. The basic block does not terminate with a branch or + // return, but falls through to the start of a loop, most likely. + // Thus, the last instruction CAN increase the sp_delta, unlike + // a jump or branch, and the sp_delta would not hit the target until + // the first instruction in the second block. We can examine the + // effect on the stack pointer of this last instruction to see if it + // causes the SP delta to hit the OriginalLocSize. + sval_t LastInstrDelta = get_sp_delta(this->FuncInfo, FinalAddr); + if (TargetSize == (FinalDelta + LastInstrDelta)) { + // Return very last instruction (don't back up 1 here) + return FinalAddr; + } + } + } // end if (this->FuncInfo->analyzed_sp()) +#if SMP_DEBUG_FRAMEFIXUP + else { + msg("analyzed_sp() is false for %s\n", this->GetFuncName()); + } +#endif + return BADADDR; +} // end of SMPFunction::FindAllocPoint() + // IDA Pro is sometimes confused by a function that uses the frame pointer // register for other purposes. For the x86, a function that uses EBP // as a frame pointer would begin with: push ebp; mov ebp,esp to save diff --git a/SMPDataFlowAnalysis.h b/SMPDataFlowAnalysis.h index f78e7b66..a6267bd9 100644 --- a/SMPDataFlowAnalysis.h +++ b/SMPDataFlowAnalysis.h @@ -174,6 +174,7 @@ private: ea_t LocalVarsAllocInstr; // address of instr that allocates stack frame ea_t LocalVarsDeallocInstr; // address of epilogue instr that deallocs frame void SetStackFrameInfo(void); + ea_t FindAllocPoint(asize_t); // Deal with difficult to find stack frame allocations bool MDFixFrameInfo(void); // Redefine stack regions for our needs bool MDFixUseFP(void); // Fix IDA errors affecting UseFP void EmitStackFrameAnnotations(FILE *AnnotFile, list<SMPInstr>::iterator Instr); -- GitLab