I want to know the logic that
af applies to find functions.
Well... you can read exactly that logic. Radare2 is open source.
In particular, the
r_core_anal_fcn called on line 4243 is the "core" workhorse which goes looking at the actual instructions, creating and crosslinking basic blocks, reconstructing local variables and function arguments signature, etc. Where does it start looking from? The
addr argument. What gets passed in there? Line 4225,
ut64 addr = core->offset;. The
af logic starts from the current address, the one you change by seeking with the
s command (which is the same when set via temporary seek
af @ 0x1234).
See, you can find out a lot from just 1 page of C code. Locating that page can be hard, if you're not strong at navigating big C codebases, but here you go I found it for you.
Why is it not able to find the other functions that follow?
af doesn't "find" functions, it starts exactly where you tell it to (see above). Well, except with
e anal.calls=1 — then it analyses recursively. Or with
e anal.hasnext=1, then it assumes that the just-analysed function will be followed by another one.
If I do
af @ main it seems to find a lot more.
Let's look at the entrypoint-main relation.
First of all,
main is written by your program's author. Far not always: people will use all kinds of stubs, and frameworks, and languages — but let me assume the simplest case for a moment.
The entrypoint code is never written by your program's author. I'm oversimplifying again; rather extreme counterexamples would be programs coded in manual assembly, or r2 eggs. But virtually always, the code at entrypoint is placed there by a compiler — thus, written by a totally different person than your program's author. For that reason, it's marginally less interesting than main. Further, it's usually very generic, contains nothing specific to your program, and therefore boring & useless. Better start analysis at main or higher.
Relatedly, entrypoint logic doesn't reference
main directly, for reasons of having to be generic. There'll be indirections. Simple/naive analysis (i.e. skipping
call rax) won't traverse those indirections — so,
af @ entry0 won't reach
Why is it not able to find the other functions that follow? For example, the functions at 0x004014ed, 0x00401516.
As suggested in comments and explained above,
aaf is more suited to analyze all functions.
afr will deal with recursive functions. You can also seek around and define them manually one-by-one (that's quite a bit faster in the visual mode: switch with
V, cycle to disasm view with
p, and then
df to define function).
Make sure to explore the built-in help
aa? etc. Also see https://book.rada.re. Reading the source can ultimately provide every possible answer.