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
Confirmed, but I suspect it's binutils bugs, I've forward bug to Nelson Chu (RISC-V binutils maintainer)
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.
it's also wrong-code for unwind info
Looks like aarch64 has the same issue.