From cd28df6ecd815a55933adbf8ec9c416735b1726d Mon Sep 17 00:00:00 2001 From: clc5q <clc5q@git.zephyr-software.com> Date: Thu, 7 Jan 2016 18:37:42 +0000 Subject: [PATCH] Do not mark return targets as COMPLETE if func is called from orphaned code. Former-commit-id: b8385e6b7c7d8007fd4fd7c9a1826e267a3ec270 --- include/base/SMPDataFlowAnalysis.h | 3 ++ include/base/SMPFunction.h | 3 ++ include/base/SMPProgram.h | 3 ++ src/base/SMPFunction.cpp | 6 ++- src/base/SMPProgram.cpp | 12 +++++ src/drivers/idapro/SMPStaticAnalyzer.cpp | 59 ++++++++++++++++++++++-- 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/include/base/SMPDataFlowAnalysis.h b/include/base/SMPDataFlowAnalysis.h index 05140134..fc31df26 100644 --- a/include/base/SMPDataFlowAnalysis.h +++ b/include/base/SMPDataFlowAnalysis.h @@ -443,6 +443,9 @@ enum SMPitype { HALT = 256 // execution stops }; +#define IsBranchOrCall(FlowType) ((FlowType >= JUMP) && (FlowType <= INDIR_CALL)) +#define IsControlFlow(FlowType) ((FlowType >= JUMP) && (FlowType <= RETURN)) + // A primary goal of data flow analysis in SMP will be to identify // operands as numeric or pointer type. If an instruction definitely // produces a numeric result, an annotation could inform the mmStrata diff --git a/include/base/SMPFunction.h b/include/base/SMPFunction.h index 5b293a5a..f4310796 100644 --- a/include/base/SMPFunction.h +++ b/include/base/SMPFunction.h @@ -294,6 +294,7 @@ public: inline void SetUnsafeForFastReturns(bool Status, UnsafeFastReturnReason Reason) { UnsafeForFastReturns = Status; FastReturnStatus |= (int) Reason; return; }; inline void SetIsSpeculative(bool IsS) { IsSpeculative = IsS; }; inline void SetIsMutuallyRecursive(void) { MutuallyRecursive = true; }; + inline void SetIsCalledFromOrphanedCode(void) { CalledFromOrphanCode = true; }; inline void SetHasHashingCode(bool Hashes) { HasHashingCode = Hashes; }; void AddCallSource(STARS_ea_t addr); // Add a caller to the list of all callers of this function. bool AddDirectCallTarget(STARS_ea_t addr); // Add a direct call target; return true if new target, false if target already added @@ -382,6 +383,7 @@ public: inline bool DoesStackFrameExtendPastStackTop(void) const { return StackFrameExtendsPastStackTop; }; inline bool IsRegPreserved(std::size_t RegNum) const { return (PreservedRegsBitmap[RegNum] != 0); }; inline bool IsPossibleIndirectCallTarget(void) const { return PossibleIndirectCallTarget; }; + inline bool IsCalledFromOrphanedCode(void) const { return CalledFromOrphanCode; }; // Printing methods void Dump(void); // debug dump @@ -462,6 +464,7 @@ private: // bool SharedChunks; // Does function share a tail chunk with other functions? bool UnsharedChunks; // Does function have noncontiguous fragments that are not shared with other funcs? bool MultipleEntryPoints; // Does function have multiple entry points from other functions? + bool CalledFromOrphanCode; // function is called from orphaned code, so program CFG is not complete at this function. bool CallsAlloca; // Does function allocate stack space after initial allocation? NOTE:SMPInstr::IsAllocaCall() excludes immediate value alloca calls bool PushAfterLocalVarAlloc; // Does function push onto the stack after allocating local var space? bool LinkerStub; // Is function just a stub to be filled in by the linker, e.g. a PLT stub? diff --git a/include/base/SMPProgram.h b/include/base/SMPProgram.h index 154a45a5..17ecb4bc 100644 --- a/include/base/SMPProgram.h +++ b/include/base/SMPProgram.h @@ -134,6 +134,7 @@ public: void ProfGranularityFinished(FILE *AnnotFile, FILE *InfoAnnotFile); // notification from ProfilerInformation bool InsertUnsharedFragment(STARS_ea_t TargetAddr); // Add code fragment starting address to set; return false if already in set, true otherwise bool InsertDataToCodeXref(STARS_ea_t TargetAddr); // Data xref to code TargetAddr has been found; record it + void SetFuncAddrCalledFromOrphanedCode(STARS_ea_t TargetAddr); // TargetAddr is called from orphaned code void AddUnreachableBlock(SMPBasicBlock *DeadBlock); // Add unreachable block and its instructions to containers void SetProgramThrowsExceptions(void); // Record detection of __cxa_throw in the binary void AddBlockToRemovalList(SMPBasicBlock *UnreachableBlock); // Add block, e.g. with "call 0" instruction, to later removal list. @@ -145,6 +146,7 @@ public: bool IsUnsharedFragment(STARS_ea_t InstAddr); // Does InstAddr begin an unshared function fragment? bool IsCodeXrefFromData(STARS_ea_t InstAddr) const; // Does InstAddr have a data xref to it? inline bool ProgramThrowsExceptions(void) const { return ThrowsExceptions; }; + bool IsFuncAddrCalledFromOrphanedCode(STARS_ea_t InstAddr) const; // Look up in address set of targets from orphaned code // Printing methods void Dump(void); // debug dump @@ -175,6 +177,7 @@ private: std::list<std::pair<STARS_ea_t, SMPFunction *> > FuncList; // FuncMap entries prioritized in desired order for analysis std::set<STARS_ea_t> UnsharedFragments; // Code fragments incorporated into their callers; remove from FuncMaps std::set<STARS_ea_t> DataToCodeXrefTargets; // Code targets of data xrefs; probably will be called indirectly + std::set<STARS_ea_t> FuncAddrsCalledFromOrphanedCode; // Program CFG is not complete for these funcs due to calls from orphaned code std::map<STARS_ea_t, SMPBasicBlock *> UnreachableInstBlockMap; // unreachable instructions, removed from their functions, mapped to blocks std::vector<SMPBasicBlock *> UnreachableBlocks; // unreachable blocks, removed from their functions diff --git a/src/base/SMPFunction.cpp b/src/base/SMPFunction.cpp index d3d287de..072e7700 100644 --- a/src/base/SMPFunction.cpp +++ b/src/base/SMPFunction.cpp @@ -158,6 +158,7 @@ SMPFunction::SMPFunction(STARS_Function_t *Info, SMPProgram* pgm) { // this->SetSharedChunks(false); this->UnsharedChunks = false; this->MultipleEntryPoints = false; + this->CalledFromOrphanCode = false; this->CallsAlloca = false; this->PushAfterLocalVarAlloc = false; this->LinkerStub = false; @@ -3872,6 +3873,9 @@ void SMPFunction::AnalyzeFunc(void) { this->SetLinks(); this->RPONumberBlocks(); this->DetectLinkerStubFunction(); + if (this->GetProg()->IsFuncAddrCalledFromOrphanedCode(this->GetFirstFuncAddr())) { + this->SetIsCalledFromOrphanedCode(); + } FragmentWorkList.clear(); return; @@ -9613,7 +9617,7 @@ void SMPFunction::EmitReturnTargetAnnotations(void) { bool TailCallFlag = (this->TailReturnTargets.find(RetTargetAddr) != this->TailReturnTargets.end()); global_STARS_program->PrintReturnInstXref(ReturnInstAddr, RetTargetAddr, RetInstSize, TailCallFlag); } - if (!(this->PossibleIndirectCallTarget || this->MultipleEntryPoints)) { + if (!(this->PossibleIndirectCallTarget || this->MultipleEntryPoints || this->IsCalledFromOrphanedCode())) { global_STARS_program->PrintCodeToCodeXrefComplete(ReturnInstAddr, RetInstSize, this->ReturnTargets.size()); } } diff --git a/src/base/SMPProgram.cpp b/src/base/SMPProgram.cpp index e3865363..45286945 100644 --- a/src/base/SMPProgram.cpp +++ b/src/base/SMPProgram.cpp @@ -177,6 +177,12 @@ bool SMPProgram::InsertDataToCodeXref(STARS_ea_t TargetAddr) { return InsertResult.second; } // end of SMPProgram::InsertDataToCodeXref() +// TargetAddr is called from orphaned code +void SMPProgram::SetFuncAddrCalledFromOrphanedCode(STARS_ea_t TargetAddr) { + this->FuncAddrsCalledFromOrphanedCode.insert(TargetAddr); + return; +} + // Add unreachable block and its instructions to containers void SMPProgram::AddUnreachableBlock(SMPBasicBlock *DeadBlock) { assert(NULL != DeadBlock); @@ -224,6 +230,12 @@ bool SMPProgram::IsCodeXrefFromData(STARS_ea_t InstAddr) const { return Found; } +// Look up in address set of targets from orphaned code +bool SMPProgram::IsFuncAddrCalledFromOrphanedCode(STARS_ea_t InstAddr) const { + bool Found = (this->FuncAddrsCalledFromOrphanedCode.find(InstAddr) != this->FuncAddrsCalledFromOrphanedCode.end()); + return Found; +} + // Main program analysis driver. Goes through all functions and // analyzes all functions and global static data. void SMPProgram::Analyze(ProfilerInformation *pi, FILE *AnnotFile, FILE *InfoAnnotFile) { diff --git a/src/drivers/idapro/SMPStaticAnalyzer.cpp b/src/drivers/idapro/SMPStaticAnalyzer.cpp index 76b984de..aa73d8b9 100644 --- a/src/drivers/idapro/SMPStaticAnalyzer.cpp +++ b/src/drivers/idapro/SMPStaticAnalyzer.cpp @@ -83,7 +83,7 @@ int FuncsProcessed = 0; #define SMP_FIXUP_IDB 0 // Try to fix the IDA database? NOTE: Needs lots of updating before re-enabling. #define SMP_DEBUG_FIXUP_IDB 0 // debugging output for FixupIDB chain #define SMP_FIND_ORPHANS 1 // find code outside of functions -#define SMP_DEBUG_CODE_ORPHANS 1 // Detect whether we are causing code to be orphaned +#define SMP_DEBUG_CODE_ORPHANS 0 // Detect whether we are causing code to be orphaned #define SMP_IDAP_RUN_DELAY 0 // Delay in IDAP_run() so we can attach debugger to process. @@ -96,9 +96,7 @@ static SMPProgram *CurrProg = NULL; STARS_Interface_t* global_stars_interface = NULL; STARS_Program_t *global_STARS_program = NULL; -#if SMP_DEBUG_CODE_ORPHANS set<STARS_ea_t> CodeOrphans; -#endif // Should we convert the x86 LOCK prefix byte to a no-op to avoid // IDA Pro problems with instructions that jump past the LOCK @@ -179,6 +177,7 @@ void FindDataInCode(void); void AuditTailChunkOwnership(void); void FindOrphanedCode(STARS_Segment_t *, FILE *, FILE *); void Debug_FindOrphanedCode(STARS_Segment_t *, bool); +void FindLinksFromOrphanedCode(STARS_Segment_t *); void FixCodeIdentification(void); int FixupNewCodeChunks(void); void AuditCodeTargets(void); @@ -428,6 +427,14 @@ void IDAP_run(int arg) { } CurrProg->ProfGranularityFinished(global_STARS_program->GetAnnotFile(), global_STARS_program->GetInfoAnnotFile()); + + RecentAddr = STARS_BADADDR; + for (STARS_Segment_t *seg = SMP_get_first_seg(); NULL != seg; seg = SMP_get_next_seg(RecentAddr)) { + RecentAddr = seg->get_startEA(); + if (seg->IsCodeSegment()) + FindLinksFromOrphanedCode(seg); + } + CurrProg->Analyze(prof_info, global_STARS_program->GetAnnotFile(), global_STARS_program->GetInfoAnnotFile()); if (!global_STARS_program->ShouldSTARSPerformReducedAnalysis()) { CurrProg->EmitAnnotations(global_STARS_program->GetAnnotFile(), global_STARS_program->GetInfoAnnotFile()); @@ -1461,6 +1468,52 @@ void FindOrphanedCode(STARS_Segment_t *CurrSeg, FILE *AnnotFile, FILE *InfoAnnot } // end for (ea_t addr = CurrSeg->startEA; ...) } // end of FindOrphanedCode() +// Find calls and jumps from orphaned code to functions. Mark those functions +// so that we will know that the program CFG is not complete. +void FindLinksFromOrphanedCode(STARS_Segment_t *CurrSeg) { + char disasm[MAXSTR]; + for (STARS_ea_t addr = CurrSeg->get_startEA(); addr < CurrSeg->get_endEA(); addr = SMP_get_item_end(addr)) { + flags_t InstrFlags = getFlags(addr); + if (SMP_isHead(InstrFlags) && SMP_isCode(InstrFlags)) { + // Does IDA Pro think addr is inside a function? + func_t* CurrIDAFunc = ::get_func(addr); + if (NULL == CurrIDAFunc) { + SMPInstr CurrInst(addr); + CurrInst.Analyze(); + // Do machine-dependent fixes for DEF and USE lists. + // The fixes can help produce better annotations. + CurrInst.MDFixupDefUseLists(); + + if (CurrInst.IsAnalyzeable()) { + // If instruction is control flow, see if it reaches an addr in a function. + SMPitype CurrDataFlow = CurrInst.GetDataFlowType(); + if (IsBranchOrCall(CurrDataFlow)) { + STARS_ea_t TargetAddr = CurrInst.GetCallTarget(); + if (STARS_BADADDR == TargetAddr) { + TargetAddr = CurrInst.GetJumpTarget(); + } + if (STARS_BADADDR != TargetAddr) { + // See if TargetAddr is inside a function. + func_t* TargetFunc = ::get_func(TargetAddr); + if (NULL != TargetFunc) { + STARS_ea_t FirstAddrInFunc = TargetFunc->startEA; + if (FirstAddrInFunc != TargetAddr) { + SMP_msg("WARNING: Orphaned code at %llx calls %llx which is inside func starting at %llx\n", + (unsigned long long) addr, (unsigned long long) TargetAddr, (unsigned long long) FirstAddrInFunc); + } + CurrProg->SetFuncAddrCalledFromOrphanedCode(FirstAddrInFunc); + SMP_msg("INFO: Orphaned code at %llx calls func at %llx\n", + (unsigned long long) addr, (unsigned long long) FirstAddrInFunc); + } + } + } + } + } // end if (NULL == CurrFunc) + } // end if addr is code and isHead + } // end for (ea_t addr = CurrSeg->startEA; ...) + return; +} // end of FindLinksFromOrphanedCode() + // Version of FindOrphanedCode that does not emit annotations but can be used // to determine at what point in time code becomes orphaned. void Debug_FindOrphanedCode(STARS_Segment_t *CurrSeg, bool FirstRun) { -- GitLab