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:
parent
e7665c11eb
commit
14c3b8a382
|
@ -354,6 +354,7 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||||
GetOrInsertFunction(target);
|
GetOrInsertFunction(target);
|
||||||
} else {
|
} else {
|
||||||
XELOGSDB("b %.8X -> %.8X", addr, target);
|
XELOGSDB("b %.8X -> %.8X", addr, target);
|
||||||
|
|
||||||
// If the target is back into the function and there's no further target
|
// If the target is back into the function and there's no further target
|
||||||
// we are at the end of a function.
|
// we are at the end of a function.
|
||||||
if (target >= fn->start_address &&
|
if (target >= fn->start_address &&
|
||||||
|
@ -362,6 +363,14 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||||
ends_fn = true;
|
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.
|
// 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*
|
// Note that sometimes functions stick this in a basic block *inside*
|
||||||
// of the function somewhere, so ensure we don't have any branches over
|
// of the function somewhere, so ensure we don't have any branches over
|
||||||
|
@ -379,12 +388,32 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||||
// b KeBugCheck
|
// b KeBugCheck
|
||||||
// This check may hit on functions that jump over data code, so only
|
// This check may hit on functions that jump over data code, so only
|
||||||
// trigger this check in leaf functions (no mfspr lr/prolog).
|
// 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) {
|
fn->blocks.size() == 1) {
|
||||||
XELOGSDB("simple leaf thunk detected, ending");
|
XELOGSDB("HEURISTIC: ending at simple leaf thunk %.8X", addr);
|
||||||
ends_fn = true;
|
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) {
|
if (!ends_fn) {
|
||||||
furthest_target = MAX(furthest_target, target);
|
furthest_target = MAX(furthest_target, target);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue