Question on finding the caller function.

R

Ravi_G

Hi,

I would like to know how can I get the function name of the caller in
c?.

Like
// c code

void foo(void)
{

bar();
}

void bar(void)
{
// who is my caller?
}

I don't want to change the caller function code to add arguments
etc. Even I don't have access to the caller function source code.
I am doing this for a debug which shall run on ARM.

Thanks for your help.
 
J

James Kuyper

Ravi_G said:
Hi,

I would like to know how can I get the function name of the caller in
c?.

Like
// c code

void foo(void)
{

bar();
}

void bar(void)
{
// who is my caller?
}

I don't want to change the caller function code to add arguments
etc. Even I don't have access to the caller function source code.
I am doing this for a debug which shall run on ARM.

There's no portable way to do this, and I'm not familiar with any
non-portable ways to do it. If there is a non-portable way to do it,
you'll need to get the details in a forum specific to the
implementations or operating systems that provide that feature.
 
N

Nate Eldredge

Ravi_G said:
Hi,

I would like to know how can I get the function name of the caller in
c?.

Like
// c code

void foo(void)
{

bar();
}

void bar(void)
{
// who is my caller?
}

I don't want to change the caller function code to add arguments
etc. Even I don't have access to the caller function source code.
I am doing this for a debug which shall run on ARM.

You can't do this portably, so this is outside the realm of standard C.

Even non-portably, you may not be able to find the name of the caller.
If the executable's been stripped, or symbol information is otherwise
not provided, the name may no longer be recorded anywhere.

It is usually possible (non-portably) to find the address from which
bar() was called. If you're using gcc, you can use the non-standard
function __builtin__return_address(0). If you do have symbol
infomation, or a linker listing or something, you might be able to
cross-reference this to find the name of the calling function.

If you're using Linux or another glibc system, you might be able to make
use of glibc's backtrace functionality. See
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html#Backtraces
 
H

hal2k

Hi,

I would like to know how can I get the function name of the caller in
c?.

Like
// c code

void foo(void)
{

bar();
}

void bar(void)
{
// who is my caller?
}

I don't want to change the caller function code to add arguments
etc. Even I don't have access to the caller function source code.
I am doing this for a debug which shall run on ARM.

Thanks for your help.

I think this will do that.

void __cdecl bar(void FakeParam)
{
unsigned int *pArg;

pArg = (unsigned int*)&FakeParam;
pArg--;

printf("My Caller is: 0x%08X\n", *pArg);
}
 
K

Keith Thompson

hal2k said:
I would like to know how can I get the function name of the caller in
c?.
[snip]
I think this will do that.

void __cdecl bar(void FakeParam)
{
unsigned int *pArg;

pArg = (unsigned int*)&FakeParam;
pArg--;

printf("My Caller is: 0x%08X\n", *pArg);
}

Um, no. __cdecl is non-standard. You can't have a parameter of type
void (did you mean void*)? Apart from that, your technique *might* do
something meaningful on some implementations, but it's extremely
system-specific. It looks like you're making assumptions about stack
frame layout, in particular that the return address is at a particular
location relative to some parameter, and that the return address is
the same size as an unsigned int. Even assuming all your assumptions
are correct for a particular implementation, what you're printing is
the return address, which is going to point just after the call to the
current function, not to (the beginning of) the function that made the
call. Finally, the most you can hope to get from this is an address;
the OP is looking for a name.

The OP said this is for a debugger. He would be well advised to look
at how existing debuggers do this kind of thing; a number of them are
open source (gdb is one example).
 
J

jameskuyper

hal2k said:
I think this will do that.

void __cdecl bar(void FakeParam)
{
unsigned int *pArg;

pArg = (unsigned int*)&FakeParam;
pArg--;

printf("My Caller is: 0x%08X\n", *pArg);
}

That code has undefined behavior, starting with the -- operator. It
might give you the machine address of the calling function on some
systems, but it most certainly will not do so on many others. Finally,
he specifed that he wanted the function's name, not it's address.
 
M

Mark Wooding

James Kuyper said:
There's no portable way to do this, and I'm not familiar with any
non-portable ways to do it.

One most bletcherous technique, which may work on many kinds of systems
but will need non-portable code to implement: compile your code with
debugging symbols, and invoke a debugger (e.g., gdb) to attach to your
process, print a stack backtrace, and detach again; then parse your
caller's identity out of the backtrace.

-- [mdw]
 
K

Keith Thompson

Mark Wooding said:
One most bletcherous technique, which may work on many kinds of systems
but will need non-portable code to implement: compile your code with
debugging symbols, and invoke a debugger (e.g., gdb) to attach to your
process, print a stack backtrace, and detach again; then parse your
caller's identity out of the backtrace.

The OP apparently is trying to implement a debugger. Actually, the OP
wrote:
I am doing this for a debug which shall run on ARM.
I'm assuming "debug" was a typo for "debugger".
 
R

Ravi_G

The OP apparently is trying to implement a debugger.  Actually, the OP
wrote:
    I am doing this for a debug which shall run on ARM.
I'm assuming "debug" was a typo for "debugger".


yes. And I use gcc on Linux.
 
I

ionic

You could generate .map file, and write a (map parser) function taking
the return address from bar() and returning the caller name. The mar
parser function should load the map file into array {address, name}
sorted by address, and just search for the first node with .address
greater than the received return address.
Why .map file? Because it is a storage for all symbols used in your
executable, even hidden library symbols are there.

void bar()
{
void *retaddr = initialize_me; // [esp] or [ebp+4]
puts(get_func_name(retaddr));
}

char* get_func_name(void *retaddr)
{
int count;
NODE* mapnodes = load_map_file("path", &count); // from file or
resource
sort_ascending_by_address(mapnodes, count);
// todo: delete mapnodes before returning
for (int a=0; a<count; a++)
{
if (mapnodes[a].address > retaddr) return mapnodes[a].name;
}
return "not found";
}
 
R

Ravi_G

However, there are many platform-specific functions available on many
Thanks to all of you for your inputs.
 
J

JosephKK

yes. And I use gcc on Linux.
OK. Then you can start with debugging compiled natively with gdb/db
support, and continue with qemu variation of your target that supports
gdb.
It sounds like a lot of effort to debug what careful coding could
prevent.
 
D

David Thompson

You could generate .map file, and write a (map parser) function taking
the return address from bar() and returning the caller name. The mar
parser function should load the map file into array {address, name}
sorted by address, and just search for the first node with .address
greater than the received return address.
Why .map file? Because it is a storage for all symbols used in your
executable, even hidden library symbols are there.
Assuming each routine is a contiguous code linearly following a label
(as is common, but not universal and not required) and direct calls,
you want the LAST label BEFORE the callsite.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,281
Latest member
Pedroaciny

Latest Threads

Top