Adding a case for tail calls.

Still missing the forward tail call case, as there is legit code that
does weird branches like that.
This commit is contained in:
Ben Vanik 2013-05-30 23:41:25 -07:00
parent e7665c11eb
commit 14c3b8a382
1 changed files with 31 additions and 2 deletions

View File

@ -354,6 +354,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
GetOrInsertFunction(target);
} else {
XELOGSDB("b %.8X -> %.8X", addr, target);
// If the target is back into the function and there's no further target
// we are at the end of a function.
if (target >= fn->start_address &&
@ -362,6 +363,14 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
ends_fn = true;
}
// If the target is not a branch and it goes to before the current
// address it's definitely a tail call.
if (!ends_fn &&
target < addr) {
XELOGSDB("function end %.8X (back b before addr)", addr);
ends_fn = true;
}
// If the target is a __restgprlr_* method it's the end of a function.
// Note that sometimes functions stick this in a basic block *inside*
// of the function somewhere, so ensure we don't have any branches over
@ -379,12 +388,32 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
// b KeBugCheck
// This check may hit on functions that jump over data code, so only
// trigger this check in leaf functions (no mfspr lr/prolog).
if (!starts_with_mfspr_lr &&
if (!ends_fn &&
!starts_with_mfspr_lr &&
fn->blocks.size() == 1) {
XELOGSDB("simple leaf thunk detected, ending");
XELOGSDB("HEURISTIC: ending at simple leaf thunk %.8X", addr);
ends_fn = true;
}
// Heuristic: if this is an unconditional branch at the end of the
// function (nothing jumps over us) and we are jumping forward there's
// a good chance it's a tail call.
// This may not be true if the code is jumping over data/etc.
// TODO(benvanik): figure out how to do this reliably. This check as is
// is too aggressive and turns a lot of valid branches into tail calls.
// It seems like a lot of functions end up with some prologue bit then
// jump deep inside only to jump back towards the top soon after. May
// need something more complex than just a simple 1-pass system to
// detect these, unless more signals can be found.
/*
if (!ends_fn &&
target > addr &&
furthest_target < addr) {
XELOGSDB("HEURISTIC: ending at tail call branch %.8X", addr);
ends_fn = true;
}
*/
if (!ends_fn) {
furthest_target = MAX(furthest_target, target);