Is addr2line available after Ubuntu 20.04?

Viewed 200

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

1 Answers

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) );
    }
}
Related