Mark, Much appreciate the response.
I'm still a bit confused here. And the reason I ask this is because I open this particular vmlinux image with an OSS ELF/DWARF library... which gives me the *WRONG* names for various DWARF DIEs. I stepped through the library... and the reason the names are wrong is because the library applies all of the relocations in .rela.debug_info to the sections it opens. I thought there might be a bug in the library somewhere, so I started down looking at the DWARF data with standard Linux tools and in hex dumps... and it seemed incorrect to my -- admittedly limited -- understanding... Yes, I am using llvm-dwarfdump to textualize the DWARF data (llvm-dwarfdump-10 --verbose vmlinux) and I would assume(?) this applies the relocations as necessary. And I am using readelf to get the section data (readelf -S vmlinux) and the relocation data (readelf -r vmlinuix); however, the hex data I show is just a flat hexdump of the image (hexdump -C vmlinux -n ... -s ...). The headers via "readelf -S vmlinux": [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 For the DIE I am looking at (0xd84) via "llvm-dwarfdump-10 --verbose vmlinux" vmlinux: file format ELF64-x86-64 Abbrev table for offset: 0x00000012 [1 byte ] [55] DW_TAG_structure_type DW_CHILDREN_yes [4 bytes] DW_AT_name DW_FORM_strp [2 bytes] DW_AT_byte_size DW_FORM_data2 [1 byte ] DW_AT_alignment DW_FORM_data1 [1 byte ] DW_AT_decl_file DW_FORM_data1 [2 bytes] DW_AT_decl_line DW_FORM_data2 [1 byte ] DW_AT_decl_column DW_FORM_data1 [4 bytes] DW_AT_sibling DW_FORM_ref4 [16 bytes] 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}) The **RAW IMAGE DATA** for that DIE via "hexdump -C -n 16 -s 0x2c29264 vmlinux" (0x2c29264 is the section offset for .debug_info 0x2c284e0 + DIE offset of 0xd84): 02c29264 37 94 ff 23 00 80 24 40 22 4d 02 08 cc 19 00 00 |7..#..$@"M......| Breaking that down: 02c29264 (abbrev code) 37 (name STRP) 94 ff 23 00 (byte_size DATA2) 80 24 (align DATA1) 40 (decl_file DATA1) 22 (decl_line DATA2) 4d 02 (decl_column DATA1) 08 (sibling REF4) cc 19 00 00 |7..#..$@"M......| 2c29264: [1 byte] Abbrev Code --> 0x37 == [55] 2c29265: [4 bytes] DW_AT_name (STRP reference) --> 0x0023ff94 2c29269: [2 bytes] DW_AT_byte_size (data2) --> 0x2480 2c2926b: [1 byte] DW_AT_alignment (data1) --> 0x40 2c2926c: [1 byte] DW_AT_decl_file (data1) --> 0x22 2c2926d: [2 bytes] DW_AT_decl_line (data2) --> 0x24d == 589 2c2926f: [1 byte] DW_AT_decl_column (data1) --> 0x08 2c29270: [4 bytes] DW_AT_sibling (data4) --> 0x000019cc == [cu + 0x19cc] The relocations via "readelf -r vmlinux": Relocation section '.rela.debug_info' at offset 0x16081790 contains 12956143 entries: Offset Info Type Sym. Value Sym. Name + Addend <234 entries> 000000000d85 002a0000000a R_X86_64_32 0000000000000000 .debug_str + 66d60 <many entries> 64-bit ELF RELA relocations are 0x18 bytes. .rela.debug_info's section offset is 0x16081790. That puts this relocation at 0x16081790 + 234 * 0x18 == 0x16082d80. That relocation's binary data via "hexdump -C -n 24 -s 0x16082d80 vmlinux": 16082d80 85 0d 00 00 00 00 00 00 0a 00 00 00 2a 00 00 00 |............*...| 16082d90 60 6d 06 00 00 00 00 00 |`m......| Breaking that down: 16082d80 (r_offset) 85 0d 00 00 00 00 00 00 (r_info) 0a 00 00 00 2a 00 00 00 |............*...| 16082d90 (r_addend) 60 6d 06 00 00 00 00 00 |`m......| r_offset == 0xd85 (which points at the DW_AT_name STRP reference in .debug_info) r_info == 0x0000002a0000000a ELF32_R_SYM(r_info) == 0x2a ELF32_R_TYPE(r_info) == 0x0a (for x86-64 is R_X86_64_32) r_addend == 0x066d60 Looking at where that ELF32_R_SYM of 0x2a == 42 points via "readelf -s vmlinux": Symbol table '.symtab' contains 106815 entries: 42: 0000000000000000 0 SECTION LOCAL DEFAULT 72 Section 72 is: [72] .debug_str PROGBITS 0000000000000000 10b451e8 00000000002bef2e 0000000000000001 MS 0 0 1 The relocation does literally say "replace the DWORD 0xd85 bytes into .debug_info with a reference 0x66d60 into .debug_str" and, again, a hex dump of .debug_str (section offset == 0x10b451e8) at this offset (0x66d60) via "hexdump -C -n 128 -s 0x10babf48 vmlinux": 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| 10babf78 5f 73 75 70 70 6c 79 5f 67 65 74 5f 64 72 76 64 |_supply_get_drvd| 10babf88 61 74 61 00 68 69 64 5f 73 65 74 5f 64 72 76 64 |ata.hid_set_drvd| 10babf98 61 74 61 00 74 79 70 65 63 5f 61 6c 74 6d 6f 64 |ata.typec_altmod| 10babfa8 65 5f 73 65 74 5f 64 72 76 64 61 74 61 00 70 63 |e_set_drvdata.pc| 10babfb8 69 5f 73 65 74 5f 64 72 76 64 61 74 61 00 70 6c |i_set_drvdata.pl| And indeed, if I open this image with the OSS library I'm using and do: if (dwarf_offdie_b(dwarf, dieOffset, true, &die, &err) == DW_DLV_OK) { Dwarf_Attribute atName; char *name; if (dwarf_attr(die, DW_AT_name, &atName, &err) == DW_DLV_OK && dwarf_formstring(atName, &name, &err) == DW_DLV_OK) { // // Indeed, I get "ksymtab_power_supply_get_drvdata" as the name here // } } I get the completely wrong "ksymtab_power_supply_get_drvdata" name instead of the "task_struct" name which is expected. Either both that library and my understanding are incorrect, there is something wrong with that relocation data, or it flat isn't supposed to be applied... I also tried what you suggested "eu-strip -- reloc-debug-sections vmlinux -f stripped" and looked at the resulting output: "readelf -S stripped" still shows the reloc sections: [65] .debug_info PROGBITS 0000000000000000 00059e50 000000000c458644 0000000000000000 0 0 1 [66] .rela.debug_info RELA 0000000000000000 0c4b2498 000000001288ae68 0000000000000018 I 78 65 8 And that relocation is still there via "readelf -r stripped": Relocation section '.rela.debug_info' at offset 0xc4b2498 contains 12956143 entries: 000000000d85 002a0000000a R_X86_64_32 0000000000000000 .debug_str + 66d60 Any other thoughts? Sincerely, Bill Messmer -----Original Message----- From: Mark Wielaard <m...@klomp.org> Sent: Monday, November 30, 2020 12:17 PM To: Bill Messmer <wmess...@microsoft.com> Cc: gcc@gcc.gnu.org Subject: [EXTERNAL] Re: DWARF Debug Info Relocations (.debug_str STRP references) 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