user2542088
user2542088

Reputation: 1

How to store the function addresses when it is called in C?

I want to store the called functions addresses or names from the start up of the system to crash of the system. Is there any way to retrieve these function addresses from any hardware register when they called during program execution?

Upvotes: 1

Views: 1007

Answers (4)

How Chen
How Chen

Reputation: 1370

I ONLY did some similar work under *nix system, therefore I provide my solution for you base on *nix.

I assumed you use gcc as your default compiler, and then you'd better enable both -finstrument-functions and -fdump-rtl-expand in your makefile, for example:

CFLAGS += -Wall -O -ggdb -Wstrict-prototypes -Wno-pointer-sign -finstrument-functions -fdump-rtl-expand

After this, you can implement the trace function, for example, your_trace.c:

#include <stdio.h>
#include <stdlib.h>

/* Function prototypes with attributes */
void main_constructor( void )
    __attribute__ ((no_instrument_function, constructor));

void main_destructor( void )
    __attribute__ ((no_instrument_function, destructor));

void __cyg_profile_func_enter( void *, void * ) 
    __attribute__ ((no_instrument_function));

void __cyg_profile_func_exit( void *, void * )
    __attribute__ ((no_instrument_function));


static FILE *fp;


void main_constructor( void )
{
  fp = fopen( "trace.txt", "w" );
  if (fp == NULL) exit(-1);
}


void main_deconstructor( void )
{
  fclose( fp );
}


void __cyg_profile_func_enter( void *this, void *callsite )
{
  fprintf(fp, "E%p\n", (int *)this);
}


void __cyg_profile_func_exit( void *this, void *callsite )
{
  fprintf(fp, "X%p\n", (int *)this);
}

After these, after compile your code, you will see a *.map file, which contain function information. Also compiled with trace.c, and if simply run you output file after compile, and it will generate function call information, namely, trace.txt file, it has function address, you can use add2line to see each of them or you can use pvtrace tool to get the function call with trace.txt, for example, my compiled program named DEMO, then:

-> pvtrace ./DEMO

You will get graph.dot and it recorded your run time function call.

OR

use just enable -ggdb and use debug tool to see each function address, like DDD or GDB.

Upvotes: 0

alk
alk

Reputation: 70921

From the gcc documentation:

Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site. (On some platforms, __builtin_return_address does not work beyond the current function, so the call site information may not be available to the profiling functions otherwise.)

     void __cyg_profile_func_enter (void *this_fn,
                                     void *call_site);
     void __cyg_profile_func_exit  (void *this_fn,
                                     void *call_site);

Example:

#include <stdio.h>

void __cyg_profile_func_enter(void * this_fn, void * call_site)
{
  fprintf(stderr, "enter: %p %p\n", this_fn, call_site);
}

void __cyg_profile_func_exit(void * this_fn, void * call_site)
{
  fprintf(stderr, " exit: %p %p\n", this_fn, call_site);
}

void foo(void);
void bar(void);

void foo(void)
{
  bar();

  return;
}

void bar(void)
{
  return;
}

int main(void)
{
  bar();
  foo();

  return 0;
}

Compile and link this using:

gcc -finstrument-functions -finstrument-functions-exclude-function-list=__cyg_profile_func_enter,__cyg_profile_func_exit -Wall -g -o main main.c 

The expected output would look similar to this:

enter: 0x400665 0x7fcfedaf6c8d
enter: 0x400643 0x400681
 exit: 0x400643 0x400681
enter: 0x40061c 0x400686
enter: 0x400643 0x400633
 exit: 0x400643 0x400633
 exit: 0x40061c 0x400686
 exit: 0x400665 0x7fcfedaf6c8d

Upvotes: 2

Remo.D
Remo.D

Reputation: 16512

You can't save the function address from within the function itself and you can't access the function name during the execution but you can save it before invoking the function:

 savefptr(myfunction);
 savefname("myfunction");
 myfunction(a,b,c);

With the appropriate definition of savefptr() and savefname().

If this is done for tracing/debugging (e.g. you want to produce a log to know what's going on in the code) it might be good enoug to trace the file name and line of code using the __FILE__ and __LINE__ macros:

 fprintf (stderr, "I'm in:'%s' line %d.",
                          __FILE__, __LINE__);

I would advice against using compiler or OS specifics if can avoid them.

Upvotes: 0

Alexis
Alexis

Reputation: 2179

If you are on linux:

You can trace your program using ptrace and check the register.

To get the informations about your functions you can use the libelf. (or use nm & objdump)

Upvotes: 1

Related Questions