namhyung/uftrace

record: Library functions not traced

clementguidi opened this issue · 5 comments

Hey,

On my machine (Oracle 7 x86_64 GCC-6.3), f7ecadb breaks test 001 basic and many more. getpid() is missing from the output (see below).

Is that related to entry size?

Compiler                  gc
Runtime test case         pg
------------------------: O0
build command: gcc -o t-abc -fno-inline -fno-builtin -fno-ipa-cp -fno-omit-frame-pointer -D_FORTIFY_SOURCE=0  -pg -O0 -fno-ipa-sra  s-abc.c
test command: /localdisk/uftrace/uftrace live --no-pager --no-event --libmcount-path=/localdisk/uftrace   -N memcpy t-abc
=========== original ===========
# DURATION     TID     FUNCTION
            [ 25525] | main() {
            [ 25525] |   a() {
            [ 25525] |     b() {
   0.629 us [ 25525] |       c();
   1.889 us [ 25525] |     } /* b */
   2.242 us [ 25525] |   } /* a */
   3.181 us [ 25525] | } /* main */

===========  result  ===========
main() {
   a() {
     b() {
       c();
     } /* b */
   } /* a */
 } /* main */
=========== expected ===========
main() {
   a() {
     b() {
       c() {
         getpid();
       } /* c */
     } /* b */
   } /* a */
 } /* main */
001 basic               : NG

Probably. Can you please run the test program (or anything simple) with -v option? And also please share the output of readelf -SW <your-binary>.

Right, I spotted the plthook: cannot find REL(A)ENT size line.
I'm using tests/s-abc.c as source.

$ gcc -o t-abc -fno-inline -fno-builtin -fno-ipa-cp -fno-omit-frame-pointer -D_FORTIFY_SOURCE=0  -pg -O0 -fno-ipa-sra  s-abc.c
$ uftrace -v t-abc
uftrace: running uftrace v0.14-97-gf7ec ( x86_64 dwarf python3 tui perf sched dynamic )
uftrace: checking binary t-abc
uftrace: using /usr/local/lib/uftrace/libmcount.so library for tracing
uftrace: creating 3 thread(s) for recording
mcount: initializing mcount library
plthook: setup PLT hooking "/localdisk/uftrace/tests/t-abc"
plthook: cannot find REL(A)ENT size
mcount: mcount setup done
mcount: new session started: d1d99009924f59b3: t-abc
mcount: mcount trace finished
mcount: exit from libmcount
uftrace: child terminated with exit code: 0
uftrace: cannot read build-id section
uftrace: reading /tmp/uftrace-live-OTKMLH/task.txt file
uftrace: flushing /uftrace-d1d99009924f59b3-27908-000
uftrace: live-record finished..
uftrace: start live-replaying...
uftrace: reading /tmp/uftrace-live-OTKMLH/task.txt file
fstack: fixup for some special functions
uftrace: add field "duration"
uftrace: add field "tid"
# DURATION     TID     FUNCTION
            [ 27908] | main() {
            [ 27908] |   a() {
            [ 27908] |     b() {
   0.530 us [ 27908] |       c();
   1.993 us [ 27908] |     } /* b */
   2.357 us [ 27908] |   } /* a */
   3.267 us [ 27908] | } /* main */
uftrace: removing /tmp/uftrace-live-OTKMLH directory
$ readelf -SW t-abc
There are 27 section headers, starting at offset 0x1ab8:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000400238 000238 00001c 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            0000000000400254 000254 000020 00   A  0   0  4
  [ 3] .hash             HASH            0000000000400278 000278 000034 04   A  4   0  8
  [ 4] .dynsym           DYNSYM          00000000004002b0 0002b0 0000c0 18   A  5   1  8
  [ 5] .dynstr           STRTAB          0000000000400370 000370 000060 00   A  0   0  1
  [ 6] .gnu.version      VERSYM          00000000004003d0 0003d0 000010 02   A  4   0  2
  [ 7] .gnu.version_r    VERNEED         00000000004003e0 0003e0 000020 00   A  5   1  8
  [ 8] .rela.plt         RELA            0000000000400400 000400 0000a8 18  AI  4  20  8
  [ 9] .init             PROGBITS        00000000004004a8 0004a8 00001a 00  AX  0   0  4
  [10] .plt              PROGBITS        00000000004004d0 0004d0 000080 10  AX  0   0 16
  [11] .text             PROGBITS        0000000000400550 000550 00027c 00  AX  0   0 16
  [12] .fini             PROGBITS        00000000004007cc 0007cc 000009 00  AX  0   0  4
  [13] .rodata           PROGBITS        00000000004007d8 0007d8 000004 04  AM  0   0  4
  [14] .eh_frame_hdr     PROGBITS        00000000004007dc 0007dc 00005c 00   A  0   0  4
  [15] .eh_frame         PROGBITS        0000000000400838 000838 000184 00   A  0   0  8
  [16] .init_array       INIT_ARRAY      0000000000600e48 000e48 000008 08  WA  0   0  8
  [17] .fini_array       FINI_ARRAY      0000000000600e50 000e50 000008 08  WA  0   0  8
  [18] .jcr              PROGBITS        0000000000600e58 000e58 000008 00  WA  0   0  8
  [19] .dynamic          DYNAMIC         0000000000600e60 000e60 0001a0 10  WA  5   0  8
  [20] .got.plt          PROGBITS        0000000000601000 001000 000050 08  WA  0   0  8
  [21] .data             PROGBITS        0000000000601050 001050 000010 00  WA  0   0  8
  [22] .bss              NOBITS          0000000000601060 001060 000008 00  WA  0   0 16
  [23] .comment          PROGBITS        0000000000000000 001060 000042 01  MS  0   0  1
  [24] .symtab           SYMTAB          0000000000000000 0010a8 0006c0 18     25  48  8
  [25] .strtab           STRTAB          0000000000000000 001768 00026e 00      0   0  1
  [26] .shstrtab         STRTAB          0000000000000000 0019d6 0000e2 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

Ok, it seems the dynamic section doesn't have the data. But the section header (.rela.plt) has the entry size so we can fallback to read it.

How about this?

diff --git a/libmcount/plthook.c b/libmcount/plthook.c
index 59f8e00b..bbc9c433 100644
--- a/libmcount/plthook.c
+++ b/libmcount/plthook.c
@@ -246,8 +246,22 @@ static int find_got(struct uftrace_elf_data *elf, struct uftrace_elf_iter *iter,
        }
 
        if (jmprel_ent_size == 0) {
-               pr_dbg("cannot find REL(A)ENT size\n");
-               return 0;
+               /*
+                * Some compilers didn't generate DT_REL(A)ENT entry.
+                * Check the section header for the entry size.
+                */
+               elf_for_each_shdr(elf, &sec_iter) {
+                       if (sec_iter.shdr.sh_type == SHT_REL ||
+                           sec_iter.shdr.sh_type == SHT_RELA) {
+                               jmprel_ent_size = sec_iter.shdr.sh_entsize;
+                               break;
+                       }
+               }
+
+               if (jmprel_ent_size == 0) {
+                       pr_dbg("cannot find REL(A)ENT size\n");
+                       return 0;
+               }
        }
 
        elf_for_each_shdr(elf, &sec_iter) {

That solves the problem on my machine. Thank you.