public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Missing DW_TAG_call_site on tail optimized function pointer call
@ 2020-07-06 19:46 Gabriel-Andrew Pollo Guilbert
  0 siblings, 0 replies; only message in thread
From: Gabriel-Andrew Pollo Guilbert @ 2020-07-06 19:46 UTC (permalink / raw)
  To: gcc-help

Hi, the DWARF5 standard adds the `DW_TAG_call_site` into the debug
information. It is used by the debugger to obtain more information about
when a function called

The problem that I'm having is that GCC (version 10.1.0) doesn't seem to
generate a `DW_TAG_call_site` on indirect function calls (function pointers)
that are tail optimized.

Here I have the following piece of code:

```
#include <stdio.h>

void __attribute__((noinline)) print_hello(void) {
    printf("hello\n");
}

void __attribute__((noinline)) print_world(void) {
    printf("world\n");
}

/* the important function, both call get tail optmized */
void __attribute__((noinline)) call(int argc, void (*f)(void)) {
    if (argc % 2 == 0 || argc % 3 == 0 || argc % 5 == 0) {
        f();
    } else {
        print_hello();
    }
}

int main(int argc, char** argv) {
    if (argc % 2 == 0) {
        call(argc, print_hello);
    } else {
        call(argc, print_world);
    }

    return 0;
}
```

Using the following command to compile.

$ gcc -v -save-temps -Wall -O2 -gdwarf-5 main.c

```
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc/configure --prefix=/opt/gcc/
--enable-languages=c,c++ --with-isl --with-linker-hash-style=gnu
--with-system-zlib --enable-__cxa_atexit --enable-cet=auto
--enable-checking=release --enable-clocale=gnu --enable-default-pie
--enable-default-ssp --enable-gnu-indirect-function
--enable-gnu-unique-object --enable-install-libiberty
--enable-linker-build-id --enable-lto --enable-multilib
--enable-plugin --enable-shared --enable-threads=posix
--disable-libssp --disable-libstdcxx-pch
--disable-libunwind-exceptions --disable-werror
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.0.0 20200706 (experimental) (GCC)
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O2' '-gdwarf-5'
'-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/cc1 -E -quiet -v
main.c -mtune=generic -march=x86-64 -Wall -gdwarf-5
-fworking-directory -O2 -fpch-preprocess -o a-main.i
ignoring nonexistent directory
"/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/include
 /usr/local/include
 /opt/gcc/include
 /opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/include-fixed
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O2' '-gdwarf-5'
'-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/cc1 -fpreprocessed
a-main.i -quiet -dumpdir a- -dumpbase main.c -dumpbase-ext .c
-mtune=generic -march=x86-64 -gdwarf-5 -O2 -Wall -version -o a-main.s
GNU C17 (GCC) version 11.0.0 20200706 (experimental) (x86_64-pc-linux-gnu)
        compiled by GNU C version 11.0.0 20200706 (experimental), GMP
version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version
isl-0.22.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C17 (GCC) version 11.0.0 20200706 (experimental) (x86_64-pc-linux-gnu)
        compiled by GNU C version 11.0.0 20200706 (experimental), GMP
version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version
isl-0.22.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: ab66556b79ab5f25cdbd6eb42043f35c
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O2' '-gdwarf-5'
'-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 as -v --64 -o a-main.o a-main.s
GNU assembler version 2.34.0 (x86_64-pc-linux-gnu) using BFD version
(GNU Binutils) 2.34.0
COMPILER_PATH=/opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/:/opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/:/opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/:/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/:/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/:/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O2' '-gdwarf-5'
'-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'
 /opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/collect2 -plugin
/opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/liblto_plugin.so
-plugin-opt=/opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/lto-wrapper
-plugin-opt=-fresolution=a.res -plugin-opt=-pass-through=-lgcc
-plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s
--build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64
-dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie /lib/../lib64/Scrt1.o
/lib/../lib64/crti.o
/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/crtbeginS.o
-L/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0
-L/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../../../lib64
-L/lib/../lib64 -L/usr/lib/../lib64
-L/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/../../.. a-main.o -lgcc
--push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state
--as-needed -lgcc_s --pop-state
/opt/gcc/lib/gcc/x86_64-pc-linux-gnu/11.0.0/crtendS.o
/lib/../lib64/crtn.o
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O2' '-gdwarf-5'
'-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'
```

Using the following command, I can inspect the DWARF output.

$ llvm-dwarfdump a.out | less

```
0x000000fd:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name      ("call")
                DW_AT_decl_file
("/data/Workspace/maitrise/analyses/instrumentation-analysis/patches/test/main.c")
                DW_AT_decl_line (11)
                DW_AT_decl_column       (0x20)
                DW_AT_prototyped        (true)
                DW_AT_low_pc    (0x0000000000001190)
                DW_AT_high_pc   (0x00000000000011c6)
                DW_AT_frame_base        (DW_OP_call_frame_cfa)
                DW_AT_sibling   (0x0000014e)

0x0000011b:     DW_TAG_formal_parameter
                  DW_AT_name    ("argc")
                  DW_AT_decl_line       (11)
                  DW_AT_decl_column     (0x29)
                  DW_AT_type    (0x00000054 "int")
                  DW_AT_location        (0x0000006c:
                     [0x0000000000001190, 0x00000000000011a8): DW_OP_reg5 RDI
                     [0x00000000000011a8, 0x00000000000011aa):
DW_OP_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value
                     [0x00000000000011aa, 0x00000000000011b6): DW_OP_reg5 RDI
                     [0x00000000000011b6, 0x00000000000011c6):
DW_OP_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value)
                  DW_AT_unknown_2137    (0x00000064)

0x0000012e:     DW_TAG_formal_parameter
                  DW_AT_name    ("f")
                  DW_AT_decl_file
("/data/Workspace/maitrise/analyses/instrumentation-analysis/patches/test/main.c")
                  DW_AT_decl_line       (11)
                  DW_AT_decl_column     (0x36)
                  DW_AT_type    (0x0000014f "void()*")
                  DW_AT_location        (0x00000098:
                     [0x0000000000001190, 0x00000000000011a9): DW_OP_reg4 RSI
                     [0x00000000000011a9, 0x00000000000011aa):
DW_OP_entry_value(DW_OP_reg4 RSI), DW_OP_stack_value
                     [0x00000000000011aa, 0x00000000000011c5): DW_OP_reg4 RSI
                     [0x00000000000011c5, 0x00000000000011c6):
DW_OP_entry_value(DW_OP_reg4 RSI), DW_OP_stack_value)
                  DW_AT_unknown_2137    (0x00000090)

0x00000140:     DW_TAG_call_site
                  DW_AT_call_return_pc  (0x00000000000011c6)
                  DW_AT_call_tail_call  (true)
                  DW_AT_call_origin     (0x0000018c)

0x0000014d:     NULL
```

We notice that there is only a single `DW_TAG_call_site` while the
function `void call(void)`
clearly makes two function calls (one direct, the other through a
function pointer). It happens
with both GCC-10 and GCC compiled from the git repository.

Using clang, I get the following DWARF information.

$ clang -Wall -O2 -gdwarf-5 main.c
$ readelf --debug-dump=info a.out | less

```
0x0000003d:   DW_TAG_subprogram
                DW_AT_low_pc    (0x0000000000001150)
                DW_AT_high_pc   (0x000000000000118e)
                DW_AT_frame_base        (DW_OP_reg7 RSP)
                DW_AT_call_all_calls    (true)
                DW_AT_name      ("call")
                DW_AT_decl_file
("/data/Workspace/maitrise/analyses/instrumentation-analysis/patches/test/main.c")
                DW_AT_decl_line (11)
                DW_AT_prototyped        (true)
                DW_AT_external  (true)

0x00000048:     DW_TAG_formal_parameter
                  DW_AT_location        (indexed (0x0) loclist = 0x0000001c:
                     [0x0000000000001150, 0x0000000000001185): DW_OP_reg5 RDI)
                  DW_AT_name    ("argc")
                  DW_AT_decl_file
("/data/Workspace/maitrise/analyses/instrumentation-analysis/patches/test/main.c")
                  DW_AT_decl_line       (11)
                  DW_AT_type    (0x000000a2 "int")

0x00000051:     DW_TAG_formal_parameter
                  DW_AT_location        (indexed (0x1) loclist = 0x00000022:
                     [0x0000000000001150, 0x000000000000118e): DW_OP_reg4 RSI)
                  DW_AT_name    ("f")
                  DW_AT_decl_file
("/data/Workspace/maitrise/analyses/instrumentation-analysis/patches/test/main.c")
                  DW_AT_decl_line       (11)
                  DW_AT_type    (0x000000a6 "void()*")

0x0000005a:     DW_TAG_call_site
                  DW_AT_call_origin     (0x00000027)
                  DW_AT_call_tail_call  (true)
                  DW_AT_call_return_pc  (0x000000000000003c)

0x00000067:     DW_TAG_call_site
                  DW_AT_call_target     (DW_OP_reg4 RSI)
                  DW_AT_call_tail_call  (true)
                  DW_AT_call_return_pc  (0x000000000000003e)

0x00000072:     NULL
```

As you can see, there is two `DW_TAG_call_site` as expected. Is GCC
behavior expected? I know DWARF5
support is stil considered experimental, did I miss something in the
DWARF5 standard?

If it is indeed a bug, I will report it into the bug tracker. I'm also
willing to send a patch
if someone could give me some pointers.

Thanks,
Gabriel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-07-06 19:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-06 19:46 Missing DW_TAG_call_site on tail optimized function pointer call Gabriel-Andrew Pollo Guilbert

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).