On Linux, you can use dladdr() to solve the calling function using:
#define _GNU_SOURCE #include <dlfcn.h> ... void *retAddr = __builtin_extract_return_addr(__builtin_return_address(0)); Dl_info d; (void)dladdr(retAddr, &d); printf("%s called from %s + 0x%p\n", __FUNC__, d.dli_sname, (retAddr - d.dli_saddr));
See the GCC docs, __builtin_return_address() and the Linux man page dladdr(3) for more details.
The dladdr() function is also available on Solaris / MacOSX / * BSD, but requires a different preprocessor than _GNU_SOURCE to get visibility; see files for the relevant operating system (s) ...
Edit: Please note that since this depends on the presence of a character table, it may not be successfully resolved in shared binaries. I did not try to add error handling above; in general, support for any type of automatic return (with support for resolving function names) does not mean that symbol tables are deleted.
For really fast, sometimes I just use:
#include <execinfo.h> ... void *retAddr[10]; backtrace_symbols_fd(retAddr, backtrace(retaddr, 10), STDERR_FILENO);
as it gets ten-digit stack depth. Again, relying on the lack of withdrawal of the characters. There is a performance penalty for this, since you allow more than one address.
Edit2: Without symbol tables (which, among other things, contain the starting address and size for functions in the executable file / library), information that the "starting address" does not make sense; as far as the CPU itself is concerned, in fact there is no record of how the instruction pointer arrived at the place where it is at a certain moment - the equivalent of the goto assembly ( jmp ) or other strange bows of the self - modulating instructions are also "valid" for the CPU , as correctly structured, generated by the compiler codes. The x86 instructions are variable sizes, and the card of the operation code is quite dense, so almost any random sequence of bytes constitutes a "valid" stream of instructions; therefore heuristic reverse disassembly - binary disassembly is not a 100% safe thing.
Character tables in this sense also set βmarkersβ for debuggers. You can expect that you will find a valid flow of commands if you start parsing the functions at the start addresses, as written in the symbol table, and you can cross-check this by confirming that any return addresses found in the return traces are preceded by a call statement.