From 5ccef726c0954116f8f4b5d6347e0acdbb0b6ce3 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Tue, 27 Jan 2026 11:26:57 -0500 Subject: Perform function lifting and inlining in arch plugins This change allows architecture plugins to override the LiftFunction callback to iterate a function's basic block list and lift entire functions at once. This is required for architectures such as TMS320 C6x, which have non-traditional "delay slots" in that branches, loads, and other instructions take multiple cycles to complete, and branch instructions can reside within the delay slots of other branches. --- binaryninjaapi.h | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) (limited to 'binaryninjaapi.h') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index e28ebfb1..ed0ae371 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -6164,6 +6164,7 @@ namespace BinaryNinja { std::vector> GetRelocationRangesInRange(uint64_t addr, size_t size) const; bool RangeContainsRelocation(uint64_t addr, size_t size) const; std::vector> GetRelocationsAt(uint64_t addr) const; + Ref GetNextRelocation(uint64_t addr, uint64_t maxAddr = 0); /*! Provides a mechanism for receiving callbacks for various analysis events. @@ -9387,6 +9388,44 @@ namespace BinaryNinja { void Finalize(); }; + class FunctionLifterContext + { + Ref m_function; + Ref m_view; + Ref m_platform; + Ref m_logger; + std::vector> m_blocks; + std::set m_noReturnCalls; + std::map m_contextualReturns; + std::map m_inlinedRemapping; + std::map> m_userIndirectBranches; + std::map> m_autoIndirectBranches; + std::set m_inlinedCalls; + bool* m_containsInlinedFunctions; + + public: + BNFunctionLifterContext* m_context; + FunctionLifterContext(LowLevelILFunction* func, BNFunctionLifterContext* context); + Ref& GetView(); + Ref& GetPlatform(); + Ref& GetLogger(); + std::vector>& GetBasicBlocks(); + std::set& GetNoReturnCalls(); + std::map& GetContextualReturns(); + std::map& GetInlinedRemapping(); + std::map>& GetUserIndirectBranches(); + std::map>& GetAutoIndirectBranches(); + std::set& GetInlinedCalls(); + void SetContainsInlinedFunctions(bool value); + + void CheckForInlinedCall(BasicBlock* block, size_t instrCountBefore, size_t instrCountAfter, uint64_t prevAddr, + uint64_t addr, const uint8_t* opcode, size_t len, + std::optional> indirectSource); + void PrepareBlockTranslation(LowLevelILFunction* function, Architecture* arch, uint64_t addr); + std::vector> PrepareToCopyForeignFunction(LowLevelILFunction* function); + Ref GetForeignFunctionLiftedIL(Ref func); + }; + /*! The Architecture class is the base class for all CPU architectures. This provides disassembly, assembly, patching, and IL translation lifting for a given architecture. @@ -9415,6 +9454,7 @@ namespace BinaryNinja { static bool GetInstructionLowLevelILCallback( void* ctxt, const uint8_t* data, uint64_t addr, size_t* len, BNLowLevelILFunction* il); static void AnalyzeBasicBlocksCallback(void *ctxt, BNFunction* function, BNBasicBlockAnalysisContext* context); + static bool LiftFunctionCallback(void* ctxt, BNLowLevelILFunction* function, BNFunctionLifterContext* context); static char* GetRegisterNameCallback(void* ctxt, uint32_t reg); static char* GetFlagNameCallback(void* ctxt, uint32_t flag); static char* GetFlagWriteTypeNameCallback(void* ctxt, uint32_t flags); @@ -9496,6 +9536,16 @@ namespace BinaryNinja { */ static void DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnalysisContext& context); + static bool DefaultLiftFunctionCallback(BNLowLevelILFunction* function, BNFunctionLifterContext* context); + + /*! Default implementation of LiftFunction + + \param function Function to analyze + \param context Context for the analysis + \return Whether lifting was successful + */ + static bool DefaultLiftFunction(LowLevelILFunction* function, FunctionLifterContext& context); + /*! Get an Architecture by name \param name Name of the architecture @@ -9600,6 +9650,14 @@ namespace BinaryNinja { */ virtual void AnalyzeBasicBlocks(Function* function, BasicBlockAnalysisContext& context); + /*! Lift function instructions to IL + + \param function Function to analyze + \param context Context for the analysis + \return Whether lifting was successful + */ + virtual bool LiftFunction(LowLevelILFunction* function, FunctionLifterContext& context); + /*! Gets a register name from a register index. \param reg Register index @@ -9994,6 +10052,7 @@ namespace BinaryNinja { virtual bool GetInstructionLowLevelIL( const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override; virtual void AnalyzeBasicBlocks(Function* function, BasicBlockAnalysisContext& context) override; + virtual bool LiftFunction(LowLevelILFunction* function, FunctionLifterContext& context) override; virtual std::string GetRegisterName(uint32_t reg) override; virtual std::string GetFlagName(uint32_t flag) override; virtual std::string GetFlagWriteTypeName(uint32_t flags) override; @@ -12152,6 +12211,12 @@ namespace BinaryNinja { */ void SetCanExit(bool value); + /*! Determine whether this basic block has instruction data + + \return Whether this basic block has instruction data + */ + bool HasInstructionData() const; + /*! List of dominators for this basic block \param post Whether to get post dominators (default: false) @@ -12327,6 +12392,39 @@ namespace BinaryNinja { Ref GetSourceBlock() const; }; + /*! + \ingroup basicblocks + */ + template + class FastBasicBlockMap + { + T* m_storage; + size_t m_blockCount; + + public: + FastBasicBlockMap(const std::vector>& blocks) + { + m_blockCount = blocks.size(); + m_storage = new T[m_blockCount + 1]; + } + + ~FastBasicBlockMap() { delete[] m_storage; } + + T& operator[](BasicBlock* block) + { + if (block) + return m_storage[block->GetIndex()]; + return m_storage[m_blockCount]; + } + + const T& operator[](BasicBlock* block) const + { + if (block) + return m_storage[block->GetIndex()]; + return m_storage[m_blockCount]; + } + }; + /*! \ingroup function */ @@ -12889,7 +12987,7 @@ namespace BinaryNinja { Ref GetCalleeForAnalysis(Ref platform, uint64_t addr, bool exact); - std::vector GetUnresolvedIndirectBranches(); + std::set GetUnresolvedIndirectBranches(); bool HasUnresolvedIndirectBranches(); /*! \brief Apply an automatic type adjustment to the call at `addr` in `arch`. @@ -13698,6 +13796,7 @@ namespace BinaryNinja { */ uint64_t GetCurrentAddress() const; void SetCurrentAddress(Architecture* arch, uint64_t addr); + void SetCurrentSourceBlock(BasicBlock* source); size_t GetInstructionStart(Architecture* arch, uint64_t addr); std::set GetInstructionsAt(Architecture* arch, uint64_t addr); @@ -13705,6 +13804,7 @@ namespace BinaryNinja { void ClearIndirectBranches(); void SetIndirectBranches(const std::vector& branches); + bool HasIndirectBranches() const; /*! Get a list of registers used in the LLIL function -- cgit v1.3.1