@@ -75,6 +75,7 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnaly
7575 auto & directRefs = context.GetDirectCodeReferences ();
7676 auto & directNoReturnCalls = context.GetDirectNoReturnCalls ();
7777 auto & haltedDisassemblyAddresses = context.GetHaltedDisassemblyAddresses ();
78+ auto & inlinedUnresolvedIndirectBranches = context.GetInlinedUnresolvedIndirectBranches ();
7879
7980 bool hasInvalidInstructions = false ;
8081 set<ArchAndAddr> guidedSourceBlockTargets;
@@ -325,6 +326,81 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnaly
325326 {
326327 bool fastPath;
327328
329+ auto handleAsFallback = [&]() {
330+ // Undefined type or target, check for targets from analysis and stop disassembling this block
331+ endsBlock = true ;
332+
333+ if (info.branchType [i] == IndirectBranch)
334+ {
335+ // Indirect calls need not end the block early.
336+ Ref<LowLevelILFunction> ilFunc = new LowLevelILFunction (location.arch , nullptr );
337+ location.arch ->GetInstructionLowLevelIL (opcode, location.address , maxLen, *ilFunc);
338+ for (size_t idx = 0 ; idx < ilFunc->GetInstructionCount (); idx++)
339+ {
340+ if ((*ilFunc)[idx].operation == LLIL_CALL)
341+ {
342+ endsBlock = false ;
343+ break ;
344+ }
345+ }
346+ }
347+
348+ indirectBranchIter = indirectBranches.find (location);
349+ endIter = indirectBranches.end ();
350+ if (indirectBranchIter != endIter)
351+ {
352+ for (auto & branch : indirectBranchIter->second )
353+ {
354+ directRefs[branch.address ].emplace (location);
355+ Ref<Platform> targetPlatform = funcPlatform;
356+ if (branch.arch != function->GetArchitecture ())
357+ targetPlatform = funcPlatform->GetRelatedPlatform (branch.arch );
358+
359+ // Normal analysis should not inline indirect targets that are function starts
360+ if (translateTailCalls && data->GetAnalysisFunction (targetPlatform, branch.address ))
361+ continue ;
362+
363+ if (isGuidedSourceBlock)
364+ guidedSourceBlockTargets.insert (branch);
365+
366+ block->AddPendingOutgoingEdge (IndirectBranch, branch.address , branch.arch );
367+ if (seenBlocks.count (branch) == 0 )
368+ {
369+ blocksToProcess.push (branch);
370+ seenBlocks.insert (branch);
371+ }
372+ }
373+ }
374+ else if (info.branchType [i] == ExceptionBranch)
375+ {
376+ block->SetCanExit (false );
377+ }
378+ else if (info.branchType [i] == FunctionReturn && function->CanReturn ().GetValue ())
379+ {
380+ // Support for contextual function returns. This is mainly used for ARM/Thumb with 'blx lr'. It's most common for this to be treated
381+ // as a function return, however it can also be a function call. For now this transform is described as follows:
382+ // 1) Architecture lifts a call instruction as LLIL_CALL with a branch type of FunctionReturn
383+ // 2) By default, contextualFunctionReturns is used to translate this to a LLIL_RET (conservative)
384+ // 3) Downstream analysis uses dataflow to validate the return target
385+ // 4) If the target is not the ReturnAddressValue, then we avoid the translation to a return and leave the instruction as a call
386+ if (auto it = contextualFunctionReturns.find (location); it != contextualFunctionReturns.end ())
387+ endsBlock = it->second ;
388+ else
389+ {
390+ Ref<LowLevelILFunction> ilFunc = new LowLevelILFunction (location.arch , nullptr );
391+ location.arch ->GetInstructionLowLevelIL (opcode, location.address , maxLen, *ilFunc);
392+ if (ilFunc->GetInstructionCount () && ((*ilFunc)[0 ].operation == LLIL_CALL))
393+ contextualFunctionReturns[location] = true ;
394+ }
395+ }
396+ else
397+ {
398+ // If analysis did not find any valid branch targets, don't assume anything about global
399+ // function state, such as __noreturn analysis, since we can't see the entire function->
400+ block->SetUndeterminedOutgoingEdges (true );
401+ }
402+ };
403+
328404 switch (info.branchType [i])
329405 {
330406 case UnconditionalBranch:
@@ -375,7 +451,7 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnaly
375451 calledFunctions.insert (otherFunc);
376452 if (info.branchType [i] == UnconditionalBranch)
377453 {
378- if (!otherFunc->CanReturn ())
454+ if (!otherFunc->CanReturn () && !otherFunc-> IsInlinedDuringAnalysis (). GetValue () )
379455 {
380456 directNoReturnCalls.insert (location);
381457 endsBlock = true ;
@@ -465,98 +541,39 @@ void Architecture::DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnaly
465541 break ;
466542 }
467543
468- directRefs[target.address ].emplace (location);
469- if (!func->CanReturn ())
470- {
471- directNoReturnCalls.insert (location);
472- endsBlock = true ;
473- block->SetCanExit (false );
474- }
475544
476545 // Add function as an early reference in case it gets updated before this
477546 // function finishes analysis.
478547 context.AddTempOutgoingReference (func);
479548
480549 calledFunctions.emplace (func);
481- }
482- break ;
483550
484- case SystemCall:
485- break ;
486-
487- default :
488- // Undefined type or target, check for targets from analysis and stop disassembling this block
489- endsBlock = true ;
490-
491- if (info.branchType [i] == IndirectBranch)
492- {
493- // Indirect calls need not end the block early.
494- Ref<LowLevelILFunction> ilFunc = new LowLevelILFunction (location.arch , nullptr );
495- location.arch ->GetInstructionLowLevelIL (opcode, location.address , maxLen, *ilFunc);
496- for (size_t idx = 0 ; idx < ilFunc->GetInstructionCount (); idx++)
551+ directRefs[target.address ].emplace (location);
552+ if (!func->CanReturn ())
497553 {
498- if ((*ilFunc)[idx]. operation == LLIL_CALL )
554+ if (func-> IsInlinedDuringAnalysis (). GetValue () && func-> HasUnresolvedIndirectBranches () )
499555 {
500- endsBlock = false ;
501- break ;
556+ auto unresolved = func->GetUnresolvedIndirectBranches ();
557+ if (unresolved.size () == 1 )
558+ {
559+ inlinedUnresolvedIndirectBranches[location] = *unresolved.begin ();
560+ handleAsFallback ();
561+ break ;
562+ }
502563 }
564+
565+ directNoReturnCalls.insert (location);
566+ endsBlock = true ;
567+ block->SetCanExit (false );
503568 }
504569 }
570+ break ;
505571
506- indirectBranchIter = indirectBranches.find (location);
507- endIter = indirectBranches.end ();
508- if (indirectBranchIter != endIter)
509- {
510- for (auto & branch : indirectBranchIter->second )
511- {
512- directRefs[branch.address ].emplace (location);
513- Ref<Platform> targetPlatform = funcPlatform;
514- if (branch.arch != function->GetArchitecture ())
515- targetPlatform = funcPlatform->GetRelatedPlatform (branch.arch );
516-
517- // Normal analysis should not inline indirect targets that are function starts
518- if (translateTailCalls && data->GetAnalysisFunction (targetPlatform, branch.address ))
519- continue ;
520-
521- if (isGuidedSourceBlock)
522- guidedSourceBlockTargets.insert (branch);
572+ case SystemCall:
573+ break ;
523574
524- block->AddPendingOutgoingEdge (IndirectBranch, branch.address , branch.arch );
525- if (seenBlocks.count (branch) == 0 )
526- {
527- blocksToProcess.push (branch);
528- seenBlocks.insert (branch);
529- }
530- }
531- }
532- else if (info.branchType [i] == ExceptionBranch)
533- {
534- block->SetCanExit (false );
535- }
536- else if (info.branchType [i] == FunctionReturn)
537- {
538- // Support for contextual function returns. This is mainly used for ARM/Thumb with 'blx lr'. It's most common for this to be treated
539- // as a function return, however it can also be a function call. For now this transform is described as follows:
540- // 1) Architecture lifts a call instruction as LLIL_CALL with a branch type of FunctionReturn
541- // 2) By default, contextualFunctionReturns is used to translate this to a LLIL_RET (conservative)
542- // 3) Downstream analysis uses dataflow to validate the return target
543- // 4) If the target is not the ReturnAddressValue, then we avoid the translation to a return and leave the instruction as a call
544- if (auto it = contextualFunctionReturns.find (location); it != contextualFunctionReturns.end ())
545- endsBlock = it->second ;
546- else
547- {
548- Ref<LowLevelILFunction> ilFunc = new LowLevelILFunction (location.arch , nullptr );
549- location.arch ->GetInstructionLowLevelIL (opcode, location.address , maxLen, *ilFunc);
550- if (ilFunc->GetInstructionCount () && ((*ilFunc)[0 ].operation == LLIL_CALL))
551- contextualFunctionReturns[location] = true ;
552- }
553- }
554- else
555- {
556- // If analysis did not find any valid branch targets, don't assume anything about global
557- // function state, such as __noreturn analysis, since we can't see the entire function->
558- block->SetUndeterminedOutgoingEdges (true );
559- }
575+ default :
576+ handleAsFallback ();
560577 break ;
561578 }
562579 }
0 commit comments