Bug 103525 - wrong function entry with -fpatchable-function-entry
Summary: wrong function entry with -fpatchable-function-entry
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 10.3.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code, wrong-debug
Depends on:
Blocks:
 
Reported: 2021-12-02 03:05 UTC by Will Cohen
Modified: 2022-06-02 14:39 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-12-02 00:00:00


Attachments
Reproducer to show DW_AT_low_pc doesn't always match label for function entry. (162 bytes, text/x-csrc)
2021-12-02 03:05 UTC, Will Cohen
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Will Cohen 2021-12-02 03:05:52 UTC
Created attachment 51914 [details]
Reproducer to show DW_AT_low_pc doesn't always match label for function entry.

When the riscv linux kernel was compiled with CONFIG_DYNAMIC_FTRACE=y the addresses listed in DW_AT_low_pc in the debuginfo and the /proc/kallsyms did not match.  The difference was 0x10 bytes.  The /proc/kallsyms entry would point to the function label and the DW_AT_low_pc in the DIE for the function would point to the first instruction after the 8 nop instructions created by the  -fpatchable-function-entry=8 enable by the CONFIG_DYNAMIC_FTRACE=y.  This seems to be similar to pr99217 for mips.

Can demonstrate the problem with gcc-10.3.1 with the small reproducer u32_test.c:

$ rpm -q gcc
gcc-10.3.1-1.fc33.riscv64
$ gcc -fpatchable-function-entry=8 -g -O2 -save-temps u32_test.c -o u32_test
$ llvm-dwarfdump --name="main" u32_test                                                                                                                           
u32_test:       file format elf64-littleriscv

0x000000cf: DW_TAG_subprogram
              DW_AT_external    (true)
              DW_AT_name        ("main")
              DW_AT_decl_file   ("/home/riscv/u32_test.c")
              DW_AT_decl_line   (8)
              DW_AT_decl_column (0x01)
              DW_AT_prototyped  (true)
              DW_AT_type        (0x00000030 "int")
              DW_AT_low_pc      (0x00000000000103f0)
              DW_AT_high_pc     (0x000000000001040a)
              DW_AT_frame_base  (DW_OP_call_frame_cfa)
              DW_AT_GNU_all_call_sites  (true)
              DW_AT_sibling     (0x0000013c)

$ nm u32_test |grep main                                                                                                                                          
                 U __libc_start_main@@GLIBC_2.27
00000000000103e0 T main

$gcc -g -O2 -save-temps u32_test.c -o u32_test
$  llvm-dwarfdump --name="main" u32_test 
u32_test:	file format elf64-littleriscv

0x000000cf: DW_TAG_subprogram
              DW_AT_external	(true)
              DW_AT_name	("main")
              DW_AT_decl_file	("/home/riscv/u32_test.c")
              DW_AT_decl_line	(8)
              DW_AT_decl_column	(0x01)
              DW_AT_prototyped	(true)
              DW_AT_type	(0x00000030 "int")
              DW_AT_low_pc	(0x00000000000103e0)
              DW_AT_high_pc	(0x00000000000103fa)
              DW_AT_frame_base	(DW_OP_call_frame_cfa)
              DW_AT_GNU_all_call_sites	(true)
              DW_AT_sibling	(0x0000013c)
$ nm u32_test |grep main 
                 U __libc_start_main@@GLIBC_2.27
00000000000103e0 T main
Comment 1 Kito Cheng 2021-12-02 06:44:09 UTC
Confirmed, but I suspect it's binutils bugs, I've forward bug to Nelson Chu (RISC-V binutils maintainer)
Comment 2 Nelson Chu 2021-12-02 10:49:54 UTC
I think this should be hard to fix in binutils, since the debug info looks wrong in the generated assembly code.  I notice that there is a similar pr as follows,
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98776

And here should be one of the solution of x86,
https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=3dcea658c9e2ac84

The patchable area should be placed before both .cfi_startproc and ENDBR. For example,

$ cat tmp.c
void main ()
{}
$ riscv64-unknown-linux-gnu-gcc -fpatchable-function-entry=8,3 -S -g tmp.c

        .text
.Ltext0:
        .cfi_sections   .debug_frame
        .file 0 "/home/nelsonc" "tmp.c"
        .align  1
        .globl  main
        .section        __patchable_function_entries,"awo",@progbits,main
        .align  3
        .8byte  .LPFE1
        .text
.LPFE1:
        nop
        nop
        nop
        .type   main, @function
main:

<------ I think the .LFB0 ~ .cfi_startproc should be moved here ---------

        nop
        nop
        nop
        nop
        nop
.LFB0:
        .file 1 "tmp.c"
        .loc 1 2 1
        .cfi_startproc
        addi    sp,sp,-16

If I move the patchable area forward, then the DW_AT_low_pc looks correct.
Comment 3 Richard Biener 2021-12-02 10:58:56 UTC
it's also wrong-code for unwind info
Comment 4 Marek Polacek 2022-06-02 14:39:33 UTC
Looks like aarch64 has the same issue.