> On architectures that don't push the return address on the
> stack during the call instruction, the caller of getcallerpc
> will have saved the desired return address somewhere in
> its stack frame, and getcallerpc must root it out.
It appears the implementation below
works well with arm-elf-gcc on arm7tdmi:
/*
* Functions generated by arm-elf-gcc start
* like this (always?):
* mov ip, sp
* stmdb sp!, {fp, ip, lr, pc}
*
* (The first argument, which is still in r0,
* is pushed later, when its address is taken so
* that it can be provided to getcallerpc.)
*
* To get the value of `lr', the return address,
* walk up the stack, starting with x, until a
* value *u is found which is the previous stack
* pointer, i.e. which equals the address u+3.
* In that case, the return address is expected
* to be in u[1].
*
* If no such address is found, return an invalid value.
*/
ulong
getcallerpc(void *x)
{
ulong *u;
int i;
u = (ulong*)x;
for (i=0; i<128; i++, u++)
if (*u == (ulong)(u+3))
return u[1];
return ~0;
}
A helpful document was http://www.cems.uwe.ac.uk/~cduffy/es/5.ppt,
to get an idea of how function arguments are provided
and the stack is managed by the gcc on arm.
If the stack contains a value which matches the
condition for `ip', but which is not ip, getcallerpc
will find it before the real ip/lr, and report a
garbage address.
Michael