/* test.c 2013. 8. 28. */ #include <stdio.h> #include <stdlib.h> __attribute__ ((no_instrument_function)) void __cyg_profile_func_enter(void *this, void *callsite) { printf ("__cyg_profile_func_enter\n"); } __attribute__ ((no_instrument_function)) void __cyg_profile_func_exit(void *this, void *callsite) { printf ("__cyg_profile_func_exit\n"); } __attribute__ ((constructor)) void myConstructor( void ) { printf ("constructor\n"); } __attribute__ ((destructor)) void myDestructor( void ) { printf ("destuctor!\n"); } void func_a( void ) { printf ("func_a\n"); return; } __attribute__ ((no_instrument_function)) void func_b( void ) { printf ("func_b\n"); return; } int main() { printf ("main\n"); func_a(); func_b(); return 0; }
constructor, destructor는 생략해도 된다.
결과는,
dqxt@dons-pleiades ~/study/kernel/instrument_fn $ gcc -o test -finstrument-functions test.c dqxt@dons-pleiades ~/study/kernel/instrument_fn $ ./test __cyg_profile_func_enter constructor __cyg_profile_func_exit __cyg_profile_func_enter main __cyg_profile_func_enter func_a __cyg_profile_func_exit func_b __cyg_profile_func_exit __cyg_profile_func_enter destuctor! __cyg_profile_func_exit dqxt@dons-pleiades ~/study/kernel/instrument_fn $
또 다른 예제.
/* test2.c 2013. 8. 28. */ #include <stdio.h> #include <stdlib.h> #include <time.h> static FILE *fp_trace; __attribute__ ((constructor)) void trace_begin (void) { printf ("constructor.\n"); fp_trace = fopen("trace.out", "w"); } __attribute__ ((destructor)) void trace_end (void) { printf ("destructor.\n"); if (fp_trace != NULL) { fclose(fp_trace); } } __attribute__ ((no_instrument_function)) void __cyg_profile_func_enter (void *func, void *caller) { printf ("__cyg_profile_func_enter.\n"); if (fp_trace != NULL) { fprintf(fp_trace, "e %p %p %lu\n", func, caller, time(NULL) ); } } __attribute__ ((no_instrument_function)) void __cyg_profile_func_exit (void *func, void *caller) { printf ("__cyg_profile_func_exit.\n"); if(fp_trace != NULL) { fprintf(fp_trace, "x %p %p %lu\n", func, caller, time(NULL)); } } void func_a( void ) { printf ("in function_a.\n"); return; } __attribute__ ((no_instrument_function)) void func_b( void ) { printf ("in function_b.\n"); return; } int main() { printf ("in main.\n"); func_a(); func_b(); return 0; }
결과는,
dqxt@dons-pleiades ~/study/kernel/instrument_fn $ gcc -o test2 -finstrument-functions test2.c dqxt@dons-pleiades ~/study/kernel/instrument_fn $ ./test2 __cyg_profile_func_enter. constructor. __cyg_profile_func_exit. __cyg_profile_func_enter. in main. __cyg_profile_func_enter. in function_a. __cyg_profile_func_exit. in function_b. __cyg_profile_func_exit. __cyg_profile_func_enter. destructor. __cyg_profile_func_exit. dqxt@dons-pleiades ~/study/kernel/instrument_fn $ ./readtracelog.sh test2 trace.out Exit trace_begin at 2013-08-28T16:12:39+0900 Enter main at 2013-08-28T16:12:39+0900, called from ?? (??:0) Enter func_a at 2013-08-28T16:12:39+0900, called from main (??:?) Exit func_a at 2013-08-28T16:12:39+0900 Exit main at 2013-08-28T16:12:39+0900 Enter trace_end at 2013-08-28T16:12:39+0900, called from ?? (??:0) dqxt@dons-pleiades ~/study/kernel/instrument_fn $
readtracelog.sh의 내용은,
#!/bin/sh if test ! -f "$1" then echo "Error: executable $1 does not exist." exit 1 fi if test ! -f "$2" then echo "Error: trace log $2 does not exist." exit 1 fi EXECUTABLE="$1" TRACELOG="$2" while read LINETYPE FADDR CADDR CTIME; do FNAME="$(addr2line -f -e ${EXECUTABLE} ${FADDR}|head -1)" CDATE="$(date -Iseconds -d @${CTIME})" if test "${LINETYPE}" = "e" then CNAME="$(addr2line -f -e ${EXECUTABLE} ${CADDR}|head -1)" CLINE="$(addr2line -s -e ${EXECUTABLE} ${CADDR})" echo "Enter ${FNAME} at ${CDATE}, called from ${CNAME} (${CLINE})" fi if test "${LINETYPE}" = "x" then echo "Exit ${FNAME} at ${CDATE}" fi done < "${TRACELOG}"