Issue
Recently, I'm trying to use addr2line
after gcc compiling with flag -finstrument-functions
. The sample code is found in link and my result is totally different. (getting bad result:??:0
)
Expected result is:
$ ./readtracelog.sh main trace.out
Enter main at 2010-10-06T15:35:53+0200, called from ?? (??:0)
Enter foo at 2010-10-06T15:35:53+0200, called from main (main.c:9)
Exit foo at 2010-10-06T15:35:53+0200
Exit main at 2010-10-06T15:35:53+0200
My result is:
Enter ?? at 2021-02-13T15:35:56+08:00, called from ?? (??:0)
Enter ?? at 2021-02-13T15:35:56+08:00, called from ?? (??:0)
Exit ?? at 2021-02-13T15:35:56+08:00
Exit ?? at 2021-02-13T15:35:56+08:00
Following is full code:
main.c:
#include <stdio.h>
void foo() {
printf("foo\n");
}
int main() {
foo();
return 0;
}
trace.c:
#include <stdio.h>
#include <time.h>
static FILE *fp_trace;
void
__attribute__ ((constructor))
trace_begin (void)
{
fp_trace = fopen("trace.out", "w");
}
void
__attribute__ ((destructor))
trace_end (void)
{
if(fp_trace != NULL) {
fclose(fp_trace);
}
}
void
__cyg_profile_func_enter (void *func, void *caller)
{
if(fp_trace != NULL) {
fprintf(fp_trace, "e %p %p %lu\n", func, caller, time(NULL) );
}
}
void
__cyg_profile_func_exit (void *func, void *caller)
{
if(fp_trace != NULL) {
fprintf(fp_trace, "x %p %p %lu\n", func, caller, time(NULL));
}
}
build:
$ gcc -finstrument-functions -g -c -o main.o main.c
$ gcc -c -o trace.o trace.c
$ gcc main.o trace.o -o main
$ ./main
foo
$ cat trace.out
e 0x400679 0x394281c40b 1286372153
e 0x400648 0x40069a 1286372153
x 0x400648 0x40069a 1286372153
x 0x400679 0x394281c40b 1286372153
using script:
#!/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}"
My kernel version is 5.9.12-050912-generic
and gcc
version is 9.3.0
Solution
Problem doesn't occur in addr2line
. Instead, we need to convert absolute address into relative one. Following is code need to change to:
__cyg_profile_func_enter (void *func, void *caller)
{
if(fp_trace != NULL) {
Dl_info a, b;
struct link_map* link_mapa;
struct link_map* link_mapb;
dladdr1((void*)func,&a,(void**)&link_mapa,RTLD_DL_LINKMAP);
dladdr1((void*)caller,&b,(void**)&link_mapb,RTLD_DL_LINKMAP);
fprintf(fp_trace, "e %p %p %lu\n", func-link_mapa->l_addr, caller-link_mapb->l_addr, time(NULL) );
}
}
Answered By - Steven