1

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?

banarun
  • 2,305
  • 2
  • 23
  • 40
  • 2
    do you mean the [stacktrace](http://en.wikipedia.org/wiki/Stack_trace), if so you can look at http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes – Karthik T Jul 02 '13 at 10:05
  • 1
    Which compiler are you using? – alk Jul 02 '13 at 10:06
  • If using gcc this might help: http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-finstrument_002dfunctions-2387 – alk Jul 02 '13 at 10:14
  • Is there a good reason you can't just use a debugger? – Philip Kendall Jul 02 '13 at 10:37

4 Answers4

2

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
alk
  • 69,737
  • 10
  • 105
  • 255
  • 1
    You can convert the addresses to function names using `addr2line`. – ams Jul 02 '13 at 10:40
  • Thanks for the answer. Here by doing the instrumentation the extra code will be added in the executable file. Further increasing the size of executable and also increasing the load on system. Is there any other way to do this? – user2542088 Jul 03 '13 at 04:01
  • `addr2line` doesn't work. I copy-pasted this example and I get `??:0` when I do `addr2line -e main -p 0x55858295a230`. I'm using WSL-2 Ubuntu, does that matter? – Bob Apr 10 '23 at 18:47
1

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)

Alexis
  • 2,149
  • 2
  • 25
  • 39
0

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.

Remo.D
  • 16,122
  • 6
  • 43
  • 74
0

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.

How Chen
  • 1,340
  • 2
  • 17
  • 37
  • Thanks for the answer. Here by doing the instrumentation the extra code will be added in the executable file. Further increasing the size of executable and also increasing the load on system. Is there any other way to do this? – user2542088 Jul 03 '13 at 04:02
  • @user2542088, I think you can add flag like `-DDEBUG` or `-DRELEASE` to seperate you target file, in debug version you will enable this feature, but for release verion, you disable this feature – How Chen Jul 05 '13 at 07:03