summaryrefslogtreecommitdiff
path: root/architecture.cpp
diff options
context:
space:
mode:
authorBrandon Miller <brandon@vector35.com>2026-01-27 11:26:57 -0500
committerBrandon Miller <brandon@vector35.com>2026-01-27 11:26:57 -0500
commit5ccef726c0954116f8f4b5d6347e0acdbb0b6ce3 (patch)
treeef347ed0ae08bbdafb53fd5e82ffdfd104377522 /architecture.cpp
parente5805fe927f42d3ac56dd283fc02b394a9739d79 (diff)
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.
Diffstat (limited to 'architecture.cpp')
-rw-r--r--architecture.cpp185
1 files changed, 185 insertions, 0 deletions
diff --git a/architecture.cpp b/architecture.cpp
index 64d3907c..1901438f 100644
--- a/architecture.cpp
+++ b/architecture.cpp
@@ -466,6 +466,169 @@ void BasicBlockAnalysisContext::Finalize()
}
+FunctionLifterContext::FunctionLifterContext(LowLevelILFunction* func, BNFunctionLifterContext* context)
+{
+ m_context = context;
+ m_view = func->GetFunction()->GetView();
+ m_function = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func->GetObject()));
+ m_platform = new Platform(BNNewPlatformReference(context->platform));
+ m_logger = new Logger(BNNewLoggerReference(context->logger));
+ m_blocks.reserve(context->basicBlockCount);
+ for (size_t i = 0; i < context->basicBlockCount; i++)
+ {
+ m_blocks.emplace_back(new BasicBlock(context->basicBlocks[i]));
+ }
+
+ for (size_t i = 0; i < context->noReturnCallsCount; i++)
+ {
+ ArchAndAddr addr(new CoreArchitecture(context->noReturnCalls[i].arch), context->noReturnCalls[i].address);
+ m_noReturnCalls.insert(addr);
+ }
+
+ for (size_t i = 0; i < context->contextualFunctionReturnCount; i++)
+ {
+ ArchAndAddr addr(new CoreArchitecture(context->contextualFunctionReturnLocations[i].arch),
+ context->contextualFunctionReturnLocations[i].address);
+ m_contextualReturns[addr] = context->contextualFunctionReturnValues[i];
+ }
+
+ for (size_t i = 0; i < context->inlinedRemappingEntryCount; i++)
+ {
+ ArchAndAddr key(
+ new CoreArchitecture(context->inlinedRemappingKeys[i].arch), context->inlinedRemappingKeys[i].address);
+ ArchAndAddr value(
+ new CoreArchitecture(context->inlinedRemappingValues[i].arch), context->inlinedRemappingValues[i].address);
+ m_inlinedRemapping[key] = value;
+ }
+
+ for (size_t i = 0; i < context->indirectBranchesCount; i++)
+ {
+ ArchAndAddr src(
+ new CoreArchitecture(context->indirectBranches[i].sourceArch), context->indirectBranches[i].sourceAddr);
+ ArchAndAddr dest(
+ new CoreArchitecture(context->indirectBranches[i].destArch), context->indirectBranches[i].destAddr);
+ if (context->indirectBranches[i].autoDefined)
+ m_autoIndirectBranches[src].insert(dest);
+ else
+ m_userIndirectBranches[src].insert(dest);
+ }
+
+ for (size_t i = 0; i < context->inlinedCallsCount; i++)
+ {
+ m_inlinedCalls.insert(context->inlinedCalls[i]);
+ }
+
+ m_containsInlinedFunctions = context->containsInlinedFunctions;
+}
+
+
+Ref<BinaryView>& FunctionLifterContext::GetView()
+{
+ return m_view;
+}
+
+
+Ref<Platform>& FunctionLifterContext::GetPlatform()
+{
+ return m_platform;
+}
+
+
+std::map<ArchAndAddr, ArchAndAddr>& FunctionLifterContext::GetInlinedRemapping()
+{
+ return m_inlinedRemapping;
+}
+
+
+std::map<ArchAndAddr, std::set<ArchAndAddr>>& FunctionLifterContext::GetUserIndirectBranches()
+{
+ return m_userIndirectBranches;
+}
+
+
+std::map<ArchAndAddr, std::set<ArchAndAddr>>& FunctionLifterContext::GetAutoIndirectBranches()
+{
+ return m_autoIndirectBranches;
+}
+
+
+Ref<Logger>& FunctionLifterContext::GetLogger()
+{
+ return m_logger;
+}
+
+
+vector<Ref<BasicBlock>>& FunctionLifterContext::GetBasicBlocks()
+{
+ return m_blocks;
+}
+
+
+std::set<ArchAndAddr>& FunctionLifterContext::GetNoReturnCalls()
+{
+ return m_noReturnCalls;
+}
+
+
+std::map<ArchAndAddr, bool>& FunctionLifterContext::GetContextualReturns()
+{
+ return m_contextualReturns;
+}
+
+
+std::set<uint64_t>& FunctionLifterContext::GetInlinedCalls()
+{
+ return m_inlinedCalls;
+}
+
+
+void FunctionLifterContext::SetContainsInlinedFunctions(bool value)
+{
+ *m_containsInlinedFunctions = value;
+}
+
+
+void FunctionLifterContext::PrepareBlockTranslation(LowLevelILFunction* function, Architecture* arch, uint64_t addr)
+{
+ BNPrepareBlockTranslation(function->GetObject(), arch->GetObject(), addr);
+}
+
+
+std::vector<Ref<BasicBlock>> FunctionLifterContext::PrepareToCopyForeignFunction(LowLevelILFunction* function)
+{
+ size_t blockCount = 0;
+ BNBasicBlock** bnBlocks =
+ BNPrepareToCopyForeignFunction(m_function->GetObject(), function->GetObject(), &blockCount);
+ std::vector<Ref<BasicBlock>> blocks;
+ blocks.reserve(blockCount);
+ for (size_t i = 0; i < blockCount; i++)
+ blocks.emplace_back(new BasicBlock(BNNewBasicBlockReference(bnBlocks[i])));
+
+ BNFreeBasicBlockList(bnBlocks, blockCount);
+ return blocks;
+}
+
+
+Ref<LowLevelILFunction> FunctionLifterContext::GetForeignFunctionLiftedIL(Ref<Function> func)
+{
+ size_t inlinedCallsCount = m_inlinedCalls.size();
+ uint64_t* inlinedCalls = nullptr;
+ if (inlinedCallsCount)
+ inlinedCalls = new uint64_t[inlinedCallsCount];
+
+ BNLowLevelILFunction* il =
+ BNGetForeignFunctionLiftedIL(func->GetObject(), m_logger->GetObject(), inlinedCallsCount, inlinedCalls);
+
+ if (inlinedCalls)
+ delete[] inlinedCalls;
+
+ if (!il)
+ return nullptr;
+
+ return new LowLevelILFunction(il);
+}
+
+
Architecture::Architecture(BNArchitecture* arch)
{
m_object = arch;
@@ -600,6 +763,15 @@ void Architecture::AnalyzeBasicBlocksCallback(void *ctxt, BNFunction* function,
}
+bool Architecture::LiftFunctionCallback(void* ctxt, BNLowLevelILFunction* function, BNFunctionLifterContext* context)
+{
+ CallbackRef<Architecture> arch(ctxt);
+ Ref func(new LowLevelILFunction(BNNewLowLevelILFunctionReference(function)));
+ FunctionLifterContext flc(func, context);
+ return arch->LiftFunction(func, flc);
+}
+
+
char* Architecture::GetRegisterNameCallback(void* ctxt, uint32_t reg)
{
CallbackRef<Architecture> arch(ctxt);
@@ -1091,6 +1263,7 @@ void Architecture::Register(Architecture* arch)
callbacks.freeInstructionText = FreeInstructionTextCallback;
callbacks.getInstructionLowLevelIL = GetInstructionLowLevelILCallback;
callbacks.analyzeBasicBlocks = AnalyzeBasicBlocksCallback;
+ callbacks.liftFunction = LiftFunctionCallback;
callbacks.getRegisterName = GetRegisterNameCallback;
callbacks.getFlagName = GetFlagNameCallback;
callbacks.getFlagWriteTypeName = GetFlagWriteTypeNameCallback;
@@ -1225,6 +1398,12 @@ void Architecture::AnalyzeBasicBlocks(Function* function, BasicBlockAnalysisCont
}
+bool Architecture::LiftFunction(LowLevelILFunction* function, FunctionLifterContext& context)
+{
+ return DefaultLiftFunction(function, context);
+}
+
+
string Architecture::GetRegisterName(uint32_t reg)
{
return fmt::format("r{}", reg);
@@ -1792,6 +1971,12 @@ void CoreArchitecture::AnalyzeBasicBlocks(Function* function, BasicBlockAnalysis
}
+bool CoreArchitecture::LiftFunction(LowLevelILFunction* function, FunctionLifterContext& context)
+{
+ return BNArchitectureLiftFunction(m_object, function->GetObject(), context.m_context);
+}
+
+
string CoreArchitecture::GetRegisterName(uint32_t reg)
{
char* name = BNGetArchitectureRegisterName(m_object, reg);