summaryrefslogtreecommitdiff
path: root/defaultabb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'defaultabb.cpp')
-rw-r--r--defaultabb.cpp645
1 files changed, 0 insertions, 645 deletions
diff --git a/defaultabb.cpp b/defaultabb.cpp
deleted file mode 100644
index 71823dd1..00000000
--- a/defaultabb.cpp
+++ /dev/null
@@ -1,645 +0,0 @@
-#include <map>
-#include <set>
-#include <queue>
-#include <inttypes.h>
-#include "binaryninjaapi.h"
-#include "binaryninjacore.h"
-#include "lowlevelilinstruction.h"
-
-using namespace std;
-using namespace BinaryNinja;
-
-static bool GetNextFunctionAfterAddress(Ref<BinaryView> data, Ref<Platform> platform, uint64_t address, Ref<Function>& nextFunc)
-{
- uint64_t nextFuncAddr = data->GetNextFunctionStartAfterAddress(address);
- nextFunc = data->GetAnalysisFunction(platform, nextFuncAddr);
- return nextFunc != nullptr;
-}
-
-
-void Architecture::DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnalysisContext& context)
-{
- auto data = function->GetView();
- queue<ArchAndAddr> blocksToProcess;
- map<ArchAndAddr, Ref<BasicBlock>> instrBlocks;
- set<ArchAndAddr> seenBlocks;
-
- bool guidedAnalysisMode = context.GetGuidedAnalysisMode();
- bool triggerGuidedOnInvalidInstruction = context.GetTriggerGuidedOnInvalidInstruction();
- bool translateTailCalls = context.GetTranslateTailCalls();
- bool disallowBranchToString = context.GetDisallowBranchToString();
-
- auto& indirectBranches = context.GetIndirectBranches();
- auto& indirectNoReturnCalls = context.GetIndirectNoReturnCalls();
-
- auto& contextualFunctionReturns = context.GetContextualReturns();
-
- auto& directRefs = context.GetDirectCodeReferences();
- auto& directNoReturnCalls = context.GetDirectNoReturnCalls();
- auto& haltedDisassemblyAddresses = context.GetHaltedDisassemblyAddresses();
- auto& inlinedUnresolvedIndirectBranches = context.GetInlinedUnresolvedIndirectBranches();
-
- bool hasInvalidInstructions = false;
- set<ArchAndAddr> guidedSourceBlockTargets;
- auto guidedSourceBlocks = function->GetGuidedSourceBlocks();
- set<ArchAndAddr> guidedSourceBlocksSet;
- for (const auto& block : guidedSourceBlocks)
- guidedSourceBlocksSet.insert(block);
-
- BNStringReference strRef;
- auto targetExceedsByteLimit = [](const BNStringReference& strRef) {
- size_t byteLimit = 8;
- if (strRef.type == Utf16String) byteLimit *= 2;
- else if (strRef.type == Utf32String) byteLimit *= 4;
- return (strRef.length >= byteLimit);
- };
-
- // Start by processing the entry point of the function
- Ref<Platform> funcPlatform = function->GetPlatform();
- auto start = function->GetStart();
- blocksToProcess.emplace(funcPlatform->GetArchitecture(), start);
- seenBlocks.emplace(funcPlatform->GetArchitecture(), start);
-
- // Only validate that branch destinations are executable if the start of the function is executable. This allows
- // data to be disassembled manually
- bool validateExecutable = data->IsOffsetExecutable(start);
-
- bool fastValidate = false;
- uint64_t fastEndAddr = 0;
- uint64_t fastStartAddr = UINT64_MAX;
- if (validateExecutable)
- {
- // Extract the bounds of the section containing this
- // function, to avoid calling into the BinaryView on
- // every instruction.
- for (auto& sec : data->GetSectionsAt(start))
- {
- if (sec->GetSemantics() == ReadOnlyDataSectionSemantics)
- continue;
- if (sec->GetSemantics() == ReadWriteDataSectionSemantics)
- continue;
- if (!data->IsOffsetBackedByFile(sec->GetStart()))
- continue;
- if (!data->IsOffsetExecutable(sec->GetStart()))
- continue;
- if (fastStartAddr > sec->GetStart())
- fastStartAddr = sec->GetStart();
- if (fastEndAddr < (sec->GetEnd() - 1))
- {
- fastEndAddr = sec->GetEnd() - 1;
- Ref<Segment> segment = data->GetSegmentAt(fastEndAddr);
- if (segment)
- fastEndAddr = (std::min)(fastEndAddr, segment->GetDataEnd() - 1);
- }
- fastValidate = true;
- break;
- }
- }
-
- uint64_t totalSize = 0;
- uint64_t maxSize = context.GetMaxFunctionSize();
- bool maxSizeReached = false;
- while (blocksToProcess.size() != 0)
- {
- if (data->AnalysisIsAborted())
- return;
-
- // Get the next block to process
- ArchAndAddr location = blocksToProcess.front();
- ArchAndAddr instructionGroupStart = location;
- blocksToProcess.pop();
-
- bool isGuidedSourceBlock = guidedSourceBlocksSet.count(location) ? true : false;
-
- // Create a new basic block
- Ref<BasicBlock> block = context.CreateBasicBlock(location.arch, location.address);
-
- // Get the next function to prevent disassembling into the next function if the block falls through
- Ref<Function> nextFunc;
- bool hasNextFunc = GetNextFunctionAfterAddress(data, funcPlatform, location.address, nextFunc);
- uint64_t nextFuncAddr = (hasNextFunc && nextFunc) ? nextFunc->GetStart() : 0;
- set<Ref<Function>> calledFunctions;
-
- // we mostly only case if this is 0, or more than 0. after handling an instruction,
- // we decrement. the architecture can change this value arbitrarily during callbacks.
- uint8_t delaySlotCount = 0;
- bool delayInstructionEndsBlock = false;
-
- // Disassemble the instructions in the block
- while (true)
- {
- if (data->AnalysisIsAborted())
- return;
-
- if (!delaySlotCount)
- {
- auto blockIter = instrBlocks.find(location);
- if (blockIter != instrBlocks.end())
- {
- // This instruction has already been seen, go to it directly insread of creating a copy
- Ref<BasicBlock> targetBlock = blockIter->second;
- if (targetBlock->GetStart() == location.address)
- {
- // Instruction is the start of a block, add an unconditional branch to it
- block->AddPendingOutgoingEdge(UnconditionalBranch, location.address, nullptr,
- (block->GetStart() != location.address));
- break;
- }
- else
- {
- // Instruction is in the middle of a block, need to split the basic block into two
- Ref<BasicBlock> splitBlock = context.CreateBasicBlock(location.arch, location.address);
- size_t instrDataLen;
- const uint8_t* instrData = targetBlock->GetInstructionData(location.address, &instrDataLen);
- splitBlock->AddInstructionData(instrData, instrDataLen);
- splitBlock->SetFallThroughToFunction(targetBlock->IsFallThroughToFunction());
- splitBlock->SetUndeterminedOutgoingEdges(targetBlock->HasUndeterminedOutgoingEdges());
- splitBlock->SetCanExit(targetBlock->CanExit());
- splitBlock->SetEnd(targetBlock->GetEnd());
-
- targetBlock->SetFallThroughToFunction(false);
- targetBlock->SetUndeterminedOutgoingEdges(false);
- targetBlock->SetCanExit(true);
- targetBlock->SetEnd(location.address);
-
- // Place instructions after the split point into the new block
- for (size_t j = location.address; j < splitBlock->GetEnd(); j++)
- {
- auto k = instrBlocks.find(ArchAndAddr(location.arch, j));
- if ((k != instrBlocks.end()) && (k->second == targetBlock))
- k->second = splitBlock;
- }
-
- for (auto& k : targetBlock->GetPendingOutgoingEdges())
- splitBlock->AddPendingOutgoingEdge(k.type, k.target, k.arch, k.fallThrough);
- targetBlock->ClearPendingOutgoingEdges();
- targetBlock->AddPendingOutgoingEdge(UnconditionalBranch, location.address, nullptr, true);
-
- // Mark the new block so that it will not be processed again
- seenBlocks.insert(location);
- context.AddFunctionBasicBlock(splitBlock);
-
- // Add an outgoing edge from the current block to the new block
- block->AddPendingOutgoingEdge(UnconditionalBranch, location.address);
- break;
- }
- }
- }
-
- uint8_t opcode[BN_MAX_INSTRUCTION_LENGTH];
- size_t maxLen = data->Read(opcode, location.address, location.arch->GetMaxInstructionLength());
- if (maxLen == 0)
- {
- string text = fmt::format("Could not read instruction at {:#x}", location.address);
- function->CreateAutoAddressTag(location.arch, location.address, "Invalid Instruction", text, true);
- if (location.arch->GetInstructionAlignment() == 0)
- location.address++;
- else
- location.address += location.arch->GetInstructionAlignment();
- block->SetHasInvalidInstructions(true);
- break;
- }
-
- InstructionInfo info;
- info.delaySlots = delaySlotCount;
- if (!location.arch->GetInstructionInfo(opcode, location.address, maxLen, info))
- {
- string text = fmt::format("Could not get instruction info at {:#x}", location.address);
- function->CreateAutoAddressTag(location.arch, location.address, "Invalid Instruction", text, true);
- if (location.arch->GetInstructionAlignment() == 0)
- location.address++;
- else
- location.address += location.arch->GetInstructionAlignment();
- block->SetHasInvalidInstructions(true);
- break;
- }
-
- // The instruction is invalid if it has no length or is above maximum length
- if ((info.length == 0) || (info.length > maxLen))
- {
- string text = fmt::format("Instruction of invalid length at {:#x}", location.address);
- function->CreateAutoAddressTag(location.arch, location.address, "Invalid Instruction", text, true);
- if (location.arch->GetInstructionAlignment() == 0)
- location.address++;
- else
- location.address += location.arch->GetInstructionAlignment();
- block->SetHasInvalidInstructions(true);
- break;
- }
-
- // Instruction is invalid when straddling a boundary to a section that is non-code, or not back by file
- uint64_t instrEnd = location.address + info.length - 1;
- bool slowPath = !fastValidate || (instrEnd < fastStartAddr) || (instrEnd > fastEndAddr);
- if (slowPath &&
- ((!data->IsOffsetCodeSemantics(instrEnd) && data->IsOffsetCodeSemantics(location.address)) ||
- (!data->IsOffsetBackedByFile(instrEnd) && data->IsOffsetBackedByFile(location.address))))
- {
- string text = fmt::format("Instruction at {:#x} straddles a non-code section", location.address);
- function->CreateAutoAddressTag(location.arch, location.address, "Invalid Instruction", text, true);
- if (location.arch->GetInstructionAlignment() == 0)
- location.address++;
- else
- location.address += location.arch->GetInstructionAlignment();
- block->SetHasInvalidInstructions(true);
- break;
- }
-
- bool endsBlock = false;
- ArchAndAddr target;
- map<ArchAndAddr, set<ArchAndAddr>>::const_iterator indirectBranchIter, endIter;
- if (!delaySlotCount)
- {
- // Register the address as belonging to this block if not in a delay slot,
- // this prevents basic blocks from being split between an instruction and
- // any of its delay slots
- instrBlocks[location] = block;
-
- // Keep track of where the current 'group' of instructions started. A 'group'
- // is an instruction and all of its delay slot instructions.
- instructionGroupStart = location;
-
- // Don't process branches in delay slots
- for (size_t i = 0; i < info.branchCount; i++)
- {
- bool fastPath;
-
- auto handleAsFallback = [&]() {
- // Undefined type or target, check for targets from analysis and stop disassembling this block
- endsBlock = true;
-
- if (info.branchType[i] == IndirectBranch)
- {
- // Indirect calls need not end the block early.
- Ref<LowLevelILFunction> ilFunc = new LowLevelILFunction(location.arch, nullptr);
- location.arch->GetInstructionLowLevelIL(opcode, location.address, maxLen, *ilFunc);
- for (size_t idx = 0; idx < ilFunc->GetInstructionCount(); idx++)
- {
- if ((*ilFunc)[idx].operation == LLIL_CALL)
- {
- endsBlock = false;
- break;
- }
- }
- }
-
- indirectBranchIter = indirectBranches.find(location);
- endIter = indirectBranches.end();
- if (indirectBranchIter != endIter)
- {
- for (auto& branch : indirectBranchIter->second)
- {
- directRefs[branch.address].emplace(location);
- Ref<Platform> targetPlatform = funcPlatform;
- if (branch.arch != function->GetArchitecture())
- targetPlatform = funcPlatform->GetRelatedPlatform(branch.arch);
-
- // Normal analysis should not inline indirect targets that are function starts
- if (translateTailCalls && data->GetAnalysisFunction(targetPlatform, branch.address))
- continue;
-
- if (isGuidedSourceBlock)
- guidedSourceBlockTargets.insert(branch);
-
- block->AddPendingOutgoingEdge(IndirectBranch, branch.address, branch.arch);
- if (seenBlocks.count(branch) == 0)
- {
- blocksToProcess.push(branch);
- seenBlocks.insert(branch);
- }
- }
- }
- else if (info.branchType[i] == ExceptionBranch)
- {
- block->SetCanExit(false);
- }
- else if (info.branchType[i] == FunctionReturn && function->CanReturn().GetValue())
- {
- // Support for contextual function returns. This is mainly used for ARM/Thumb with 'blx lr'. It's most common for this to be treated
- // as a function return, however it can also be a function call. For now this transform is described as follows:
- // 1) Architecture lifts a call instruction as LLIL_CALL with a branch type of FunctionReturn
- // 2) By default, contextualFunctionReturns is used to translate this to a LLIL_RET (conservative)
- // 3) Downstream analysis uses dataflow to validate the return target
- // 4) If the target is not the ReturnAddressValue, then we avoid the translation to a return and leave the instruction as a call
- if (auto it = contextualFunctionReturns.find(location); it != contextualFunctionReturns.end())
- endsBlock = it->second;
- else
- {
- Ref<LowLevelILFunction> ilFunc = new LowLevelILFunction(location.arch, nullptr);
- location.arch->GetInstructionLowLevelIL(opcode, location.address, maxLen, *ilFunc);
- if (ilFunc->GetInstructionCount() && ((*ilFunc)[0].operation == LLIL_CALL))
- contextualFunctionReturns[location] = true;
- }
- }
- else
- {
- // If analysis did not find any valid branch targets, don't assume anything about global
- // function state, such as __noreturn analysis, since we can't see the entire function->
- block->SetUndeterminedOutgoingEdges(true);
- }
- };
-
- switch (info.branchType[i])
- {
- case UnconditionalBranch:
- case TrueBranch:
- case FalseBranch:
- // Normal branch, resume disassembly at targets
- endsBlock = true;
- // Target of a call instruction, add the function to the analysis
- if (data->IsOffsetExternSemantics(info.branchTarget[i]))
- {
- // Deal with direct pointers into the extern section
- DataVariable dataVar;
- if (data->GetDataVariableAtAddress(info.branchTarget[i], dataVar)
- && (dataVar.address == info.branchTarget[i]) && dataVar.type.GetValue()
- && (dataVar.type->GetClass() == FunctionTypeClass))
- {
- directRefs[info.branchTarget[i]].emplace(location);
- if (!dataVar.type->CanReturn())
- {
- directNoReturnCalls.insert(location);
- endsBlock = true;
- block->SetCanExit(false);
- }
- }
- break;
- }
-
- fastPath = fastValidate && (info.branchTarget[i] >= fastStartAddr) && (info.branchTarget[i] <= fastEndAddr);
- if (fastPath || (data->IsValidOffset(info.branchTarget[i]) &&
- data->IsOffsetBackedByFile(info.branchTarget[i]) &&
- ((!validateExecutable) || data->IsOffsetExecutable(info.branchTarget[i]))))
- {
- target = ArchAndAddr(info.branchArch[i] ? new CoreArchitecture(info.branchArch[i]) : location.arch, info.branchTarget[i]);
-
- // Check if valid target
- if (data->ShouldSkipTargetAnalysis(location, function, instrEnd, target))
- break;
-
- Ref<Platform> targetPlatform = funcPlatform;
- if (target.arch != funcPlatform->GetArchitecture())
- targetPlatform = funcPlatform->GetRelatedPlatform(target.arch);
-
- directRefs[info.branchTarget[i]].insert(location);
-
- auto otherFunc = function->GetCalleeForAnalysis(targetPlatform, target.address, true);
- if (translateTailCalls && targetPlatform && otherFunc && (otherFunc->GetStart() != function->GetStart()))
- {
- calledFunctions.insert(otherFunc);
- if (info.branchType[i] == UnconditionalBranch)
- {
- if (!otherFunc->CanReturn() && !otherFunc->IsInlinedDuringAnalysis().GetValue())
- {
- directNoReturnCalls.insert(location);
- endsBlock = true;
- block->SetCanExit(false);
- }
-
- break;
- }
- }
- else if (disallowBranchToString && data->GetStringAtAddress(target.address, strRef) && targetExceedsByteLimit(strRef))
- {
- BNLogInfo("Not adding branch target from 0x%" PRIx64 " to string at 0x%" PRIx64
- " length:%zu",
- location.address, target.address, strRef.length);
- break;
- }
- else
- {
- if (isGuidedSourceBlock)
- guidedSourceBlockTargets.insert(target);
-
- block->AddPendingOutgoingEdge(info.branchType[i], target.address, target.arch);
- // Add the block to the list of blocks to process if it is not already processed
- if (seenBlocks.count(target) == 0)
- {
- blocksToProcess.push(target);
- seenBlocks.insert(target);
- }
- }
- }
- break;
-
- case CallDestination:
- // Target of a call instruction, add the function to the analysis
- if (data->IsOffsetExternSemantics(info.branchTarget[i]))
- {
- // Deal with direct pointers into the extern section
- DataVariable dataVar;
- if (data->GetDataVariableAtAddress(info.branchTarget[i], dataVar)
- && (dataVar.address == info.branchTarget[i]) && dataVar.type.GetValue()
- && (dataVar.type->GetClass() == FunctionTypeClass))
- {
- directRefs[info.branchTarget[i]].emplace(location);
- if (!dataVar.type->CanReturn())
- {
- directNoReturnCalls.insert(location);
- endsBlock = true;
- block->SetCanExit(false);
- }
- // No need to add the target to the calledFunctions list since a call to external code
- // can never be the 'next' function
- }
- break;
- }
-
- fastPath = fastValidate && (info.branchTarget[i] >= fastStartAddr) && (info.branchTarget[i] <= fastEndAddr);
- if (fastPath || (data->IsValidOffset(info.branchTarget[i]) && data->IsOffsetBackedByFile(info.branchTarget[i]) &&
- ((!validateExecutable) || data->IsOffsetExecutable(info.branchTarget[i]))))
- {
- target = ArchAndAddr(info.branchArch[i] ? new CoreArchitecture(info.branchArch[i]) : location.arch, info.branchTarget[i]);
-
- if (!fastPath && !data->IsOffsetCodeSemantics(target.address) && data->IsOffsetCodeSemantics(location.address))
- {
- string message = fmt::format("Non-code call target {:#x}", target.address);
- function->CreateAutoAddressTag(target.arch, location.address, "Non-code Branch", message, true);
- break;
- }
-
- Ref<Platform> platform = funcPlatform;
- if (target.arch != platform->GetArchitecture())
- {
- platform = funcPlatform->GetRelatedPlatform(target.arch);
- if (!platform)
- platform = funcPlatform;
- }
-
- // Check if valid target
- if (data->ShouldSkipTargetAnalysis(location, function, instrEnd, target))
- break;
-
- Ref<Function> func = data->AddFunctionForAnalysis(platform, target.address, true);
- if (!func)
- {
- if (!data->IsOffsetBackedByFile(target.address))
- BNLogError("Function at 0x%" PRIx64 " failed to add target not backed by file.", function->GetStart());
- break;
- }
-
-
- // Add function as an early reference in case it gets updated before this
- // function finishes analysis.
- context.AddTempOutgoingReference(func);
-
- calledFunctions.emplace(func);
-
- directRefs[target.address].emplace(location);
- if (!func->CanReturn())
- {
- if (func->IsInlinedDuringAnalysis().GetValue() && func->HasUnresolvedIndirectBranches())
- {
- auto unresolved = func->GetUnresolvedIndirectBranches();
- if (unresolved.size() == 1)
- {
- inlinedUnresolvedIndirectBranches[location] = *unresolved.begin();
- handleAsFallback();
- break;
- }
- }
-
- directNoReturnCalls.insert(location);
- endsBlock = true;
- block->SetCanExit(false);
- }
- }
- break;
-
- case SystemCall:
- break;
-
- default:
- handleAsFallback();
- break;
- }
- }
- }
-
- if (indirectNoReturnCalls.count(location))
- {
- size_t instrLength = info.length;
- if (info.delaySlots)
- {
- InstructionInfo delayInfo;
- delayInfo.delaySlots = info.delaySlots; // we'll decrement this inside the loop
- size_t archMax = location.arch->GetMaxInstructionLength();
- uint8_t delayOpcode[BN_MAX_INSTRUCTION_LENGTH];
- do
- {
- delayInfo.delaySlots--;
- if (!location.arch->GetInstructionInfo(delayOpcode, location.address + instrLength, archMax - instrLength, delayInfo))
- break;
- instrLength += delayInfo.length;
- } while (delayInfo.delaySlots && (instrLength < archMax));
- }
-
- // Conditional Call Support (Part 1)
- // Do not halt basic block analysis if this is a conditional call to a function that is 'no return'
- // This works for both direct and indirect calls.
- // Note: Do not lift a conditional call (direct or not) with branch information.
- Ref<LowLevelILFunction> ilFunc = new LowLevelILFunction(location.arch, nullptr);
- ilFunc->SetCurrentAddress(location.arch, location.address);
- location.arch->GetInstructionLowLevelIL(opcode, location.address, maxLen, *ilFunc);
- if (!(ilFunc->GetInstructionCount() && ((*ilFunc)[0].operation == LLIL_IF)))
- {
- endsBlock = true;
- block->SetCanExit(false);
- }
- }
-
- location.address += info.length;
- block->AddInstructionData(opcode, info.length);
-
- if (endsBlock && !info.delaySlots)
- break;
-
- // Respect the 'analysis.limits.maxFunctionSize' setting while allowing for overridable behavior as well.
- // We prefer to allow disassembly when function analysis is disabled, but only up to the maximum size.
- // The log message and tag are generated in ProcessAnalysisSkip
- totalSize += info.length;
- auto analysisSkipOverride = context.GetAnalysisSkipOverride();
- if (analysisSkipOverride == NeverSkipFunctionAnalysis)
- maxSize = 0;
- else if (!maxSize && (analysisSkipOverride == AlwaysSkipFunctionAnalysis))
- maxSize = context.GetMaxFunctionSize();
-
- if (maxSize && (totalSize > maxSize))
- {
- maxSizeReached = true;
- break;
- }
-
- if (delaySlotCount)
- {
- delaySlotCount--;
- if (!delaySlotCount && delayInstructionEndsBlock)
- break;
- }
- else
- {
- delaySlotCount = info.delaySlots;
- delayInstructionEndsBlock = endsBlock;
- }
-
- if (block->CanExit() && translateTailCalls && !delaySlotCount && hasNextFunc && (location.address == nextFuncAddr))
- {
- // Falling through into another function-> Don't consider this a tail call if the current block
- // called the function, as this indicates a get PC construct.
- if (calledFunctions.count(nextFunc) == 0)
- {
- block->SetFallThroughToFunction(true);
- if (!nextFunc->CanReturn())
- {
- directNoReturnCalls.insert(instructionGroupStart);
- block->SetCanExit(false);
- }
- break;
- }
- hasNextFunc = GetNextFunctionAfterAddress(data, funcPlatform, location.address, nextFunc);
- nextFuncAddr = (hasNextFunc && nextFunc) ? nextFunc->GetStart() : 0;
- }
- }
-
- if (location.address != block->GetStart())
- {
- // Block has one or more instructions, add it to the fucntion
- block->SetEnd(location.address);
- context.AddFunctionBasicBlock(block);
- }
-
- if (maxSizeReached)
- break;
-
- if (triggerGuidedOnInvalidInstruction && block->HasInvalidInstructions())
- hasInvalidInstructions = true;
-
- if (guidedAnalysisMode || hasInvalidInstructions || guidedSourceBlocksSet.size())
- {
- queue<ArchAndAddr> guidedBlocksToProcess;
- while (!blocksToProcess.empty())
- {
- auto i = blocksToProcess.front();
- blocksToProcess.pop();
- if (guidedSourceBlockTargets.count(i))
- guidedBlocksToProcess.emplace(i);
- else
- haltedDisassemblyAddresses.emplace(i);
- }
- blocksToProcess = guidedBlocksToProcess;
- }
- }
-
- if (maxSizeReached)
- context.SetMaxSizeReached(true);
-
- // Finalize the function basic block list
- context.Finalize();
-}
-
-
-void Architecture::DefaultAnalyzeBasicBlocksCallback(BNFunction* function, BNBasicBlockAnalysisContext* context)
-{
- Ref<Function> func(new Function(BNNewFunctionReference(function)));
- BasicBlockAnalysisContext abbc(context);
- Architecture::DefaultAnalyzeBasicBlocks(func, abbc);
-}