Hi Bill,

On Mon, Nov 30, 2020 at 07:18:50PM +0000, Bill Messmer via Gcc wrote:
> I am trying to understand something unexpected I am seeing in the relocations 
> placed into a compiled Linux kernel for the .debug_info section.  Those 
> relocations seem to change the names of various entries in the debug info:
> 
>       [65] .debug_info       PROGBITS         0000000000000000  02c284e0
>            000000000c458644  0000000000000000           0     0     1
>       [66] .rela.debug_info  RELA             0000000000000000  16081790
>            000000001288ae68  0000000000000018   I      78    65     8
>       [72] .debug_str        PROGBITS         0000000000000000  10b451e8
>            00000000002bef2e  0000000000000001  MS       0     0     1

Note that you are only seeing relocations against .debug sections
because the kernel and kernel modules are only partially linked (so in
theory they can be relinked again against more/other object files).

The relocations tell where the strings (and some other entities) are
relative to the start of the .debug_ sections, so when other pieces of
.debug sections are merged later the relocations can be used/updated
to show where they are now.

But since we know these relocations are "final" they can actually be
resolved (which means, apply the relications directly to the target
section). For example if you have the elfutils tools installed you can
use eu-strip, which has two different ways to get rid of them (one
while stripping the .debug sections into a separate .debug file, one
to remove the reloations "in-place"):

      --reloc-debug-sections Resolve all trivial relocations between debug
                             sections if the removed sections are placed in a
                             debug file (only relevant for ET_REL files,
                             operation is not reversable, needs -f)
      --reloc-debug-sections-only
                             Similar to --reloc-debug-sections, but resolve all
                             trivial relocations between debug sections in
                             place.  No other stripping is performed (operation
                             is not reversable, incompatible with -f, -g,
                             --remove-comment and --remove-section)

That can save a couple of hunder megabytes of relocations.

> Dumping the DWARF information for one of the CUs in the compiled image (with 
> standard tooling) shows me:
> 
> 0x0000002d: DW_TAG_compile_unit
>               DW_AT_producer    ("GNU C89 8.3.1 20191121 (Red Hat 8.3.1-5) 
> -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -mno-80387 
> -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup 
> -mtune=generic -mno-red-zone -mcmodel=kernel -mindirect-branch=thunk-extern 
> -mindirect-branch-register -mrecord-mcount -mfentry -march=x86-64 -g 
> -gdwarf-4 -O2 -std=gnu90 -fno-strict-aliasing -fno-common -fshort-wchar 
> -fno-PIE -falign-jumps=1 -falign-loops=1 -funit-at-a-time 
> -fno-asynchronous-unwind-tables -fno-jump-tables 
> -fno-delete-null-pointer-checks -fstack-protector-strong 
> -fno-inline-functions-called-once -fno-strict-overflow 
> -fno-merge-all-constants -fmerge-constants -fstack-check=no -fconserve-stack 
> --param allow-store-data-races=0")
>               DW_AT_language    (DW_LANG_C89)
>               DW_AT_name        ("arch/x86/kernel/head64.c")
>               DW_AT_comp_dir    
> ("/usr/src/debug/kernel-4.18.0-193.el8/linux-4.18.0-193.el8.x86_64")
>               DW_AT_ranges      (0x000009d0
>                  [0xffffffff81002000, 0xffffffff81002008)
>                  [0xffffffff82977172, 0xffffffff829771c0)
>                  [0xffffffff829771c0, 0xffffffff8297727a)
>                  [0xffffffff8297727a, 0xffffffff829774f8)
>                  [0xffffffff829774f8, 0xffffffff82977518)
>                  [0xffffffff82977518, 0xffffffff8297759f)
>                  [0xffffffff81000200, 0xffffffff810005b9)
>                  [0xffffffff8297759f, 0xffffffff829775bc))
>               DW_AT_low_pc      (0x0000000000000000)
>               DW_AT_stmt_list   (0x00000126)
> 
>             0x00000d84:   DW_TAG_structure_type [55] *
>                             DW_AT_name [DW_FORM_strp]       ( 
> .debug_str[0x0023ff94] = "task_struct")
>                             DW_AT_byte_size [DW_FORM_data2] (0x2480)
>                             DW_AT_alignment [DW_FORM_data1] (0x40)
>                             DW_AT_decl_file [DW_FORM_data1] 
> ("/usr/src/debug/kernel-4.18.0-193.el8/linux-4.18.0-193.el8.x86_64/./include/linux/sched.h")
>                             DW_AT_decl_line [DW_FORM_data2] (589)
>                             DW_AT_decl_column [DW_FORM_data1]       (0x08)
>                             DW_AT_sibling [DW_FORM_ref4]    (cu + 0x19cc => 
> {0x000019ee})
> 
> As I'd expect, the name of the structure with the DWARF DIE at offset 0xd84 
> is "task_struct".  A hex dump of this part of .debug_info within the compiled 
> image confirms the 0x23ff94 offset into the string table:
> 
>     02c29260  47 0d 00 00 37 **94 ff 23  00** 80 24 40 22 4d 02 08  
> |G...7..#..$@"M..|
> 
>     02c29270  cc 19 00 00 02 28 a5 19  00 22 53 02 16 bb 49 00  
> |.....(..."S...I.|
>     02c29280  00 00 02 77 0a 11 00 22  56 02 12 bd 01 00 00 10  
> |...w..."V.......|
>     02c29290  02 c6 07 15 00 22 5e 02  0b 8b 05 00 00 18 02 26  
> |....."^........&|

I think the tool you are using is showing you the data with the relocations 
already applied.

> And dumping this area of .debug_str shows the name I'd expect (0x23ff94 
> within .debug_str is 0x10d8517c)
> 
>     10d85168  61 73 6b 5f 73 74 72 75  63 74 00 61 72 63 68 5f  
> |ask_struct.arch_|
> 
>     10d85178  64 75 70 5f **74 61 73 6b  5f 73 74 72 75 63 74 00 ** 
> |dup_task_struct.|
> 
>     10d85188  5f 5f 6b 73 79 6d 74 61  62 5f 5f 5f 70 75 74 5f  
> |__ksymtab___put_|
>     10d85198  74 61 73 6b 5f 73 74 72  75 63 74 00 5f 5f 6b 73  
> |task_struct.__ks|
> 
> The relocations within .rela.debug_info, however, change the STRP reference 
> for the "task_struct" DIE to something else:
> 
>     Relocation section '.rela.debug_info' at offset 0x16081790 contains 
> 12956143 entries:
>       Offset          Info           Type           Sym. Value    Sym. Name + 
> Addend
>     000000000d85  002a0000000a R_X86_64_32       0000000000000000 .debug_str 
> + 66d60
> 
> Looking at offset 0x66d60 into .debug_str shows the middle of some other 
> random name (0x66d60 in would be 0x10babf48): 
> "ksymtab_power_supply_get_drvdata" in this case.
> 
>     10babf38  76 5f 67 65 74 5f 64 72  76 64 61 74 61 00 5f 5f  
> |v_get_drvdata.__|
> 
>     10babf48  6b 73 79 6d 74 61 62 5f  70 6f 77 65 72 5f 73 75  
> |ksymtab_power_su|
> 
>     10babf58  70 70 6c 79 5f 67 65 74  5f 64 72 76 64 61 74 61  
> |pply_get_drvdata|
>     10babf68  00 5f 5f 6b 73 74 72 74  61 62 5f 70 6f 77 65 72  
> |.__kstrtab_power|
> 
> Have I misunderstood something fundamental here about the relocation data in 
> .rela.debug_info and its application...?  Or is the relocation data in this 
> .rela.debug_info bad...?

I would be very surprised if the relocations generated by GCC are
bad. I don't know whether the tools you are using to dump the data
apply the relocations already or not. Which could explain why applying
the relocation again might seem wrong.

Cheers,

Mark

Reply via email to