Simplify gen_btf logic to make it work with llvm-objcopy. The existing 'file format' and 'architecture' parsing logic is brittle and does not work with llvm-objcopy/llvm-objdump. 'file format' output of llvm-objdump>=11 will match GNU objdump, but 'architecture' (bfdarch) may not. .BTF in .tmp_vmlinux.btf is non-SHF_ALLOC. Add the SHF_ALLOC flag because it is part of vmlinux image used for introspection. C code can reference the section via linker script defined __start_BTF and __stop_BTF. This fixes a small problem that previous .BTF had the SHF_WRITE flag (objcopy -I binary -O elf* synthesized .data). Additionally, `objcopy -I binary` synthesized symbols _binary__btf_vmlinux_bin_start and _binary__btf_vmlinux_bin_stop (not used elsewhere) are replaced with more commonplace __start_BTF and __stop_BTF. Add 2>/dev/null because GNU objcopy (but not llvm-objcopy) warns "empty loadable segment detected at vaddr=0xffffffff81000000, is this intentional?" We use a dd command to change the e_type field in the ELF header from ET_EXEC to ET_REL so that lld will accept .btf.vmlinux.bin.o. Accepting ET_EXEC as an input file is an extremely rare GNU ld feature that lld does not intend to support, because this is error-prone. The output section description .BTF in include/asm-generic/vmlinux.lds.h avoids potential subtle orphan section placement issues and suppresses --orphan-handling=warn warnings.
Unified · Split
| @@ -303,12 +303,6 @@ SECTIONS · 302 unmodified lines | |||
| 303 | *(.branch_lt) | 303 | *(.branch_lt) |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | #ifdef CONFIG_DEBUG_INFO_BTF | ||
| 307 | .BTF : AT(ADDR(.BTF) - LOAD_OFFSET) { | ||
| 308 | *(.BTF) | ||
| 309 | } | ||
| 310 | #endif | ||
| 311 | |||
| 312 | .opd : AT(ADDR(.opd) - LOAD_OFFSET) { | 306 | .opd : AT(ADDR(.opd) - LOAD_OFFSET) { |
| 313 | __start_opd = .; | 307 | __start_opd = .; |
| 314 | KEEP(*(.opd)) | 308 | KEEP(*(.opd)) |
| @@ -535,6 +535,7 @@ · 534 unmodified lines | |||
| 535 | \ | 535 | \ |
| 536 | RO_EXCEPTION_TABLE \ | 536 | RO_EXCEPTION_TABLE \ |
| 537 | NOTES \ | 537 | NOTES \ |
| 538 | BTF \ | ||
| 538 | \ | 539 | \ |
| 539 | . = ALIGN((align)); \ | 540 | . = ALIGN((align)); \ |
| 540 | __end_rodata = .; | 541 | __end_rodata = .; |
| @@ -621,6 +622,20 @@ · 80 unmodified lines | |||
| 621 | __stop___ex_table = .; \ | 622 | __stop___ex_table = .; \ |
| 622 | } | 623 | } |
| 623 | 624 | ||
| 625 | /* | ||
| 626 | * .BTF | ||
| 627 | */ | ||
| 628 | #ifdef CONFIG_DEBUG_INFO_BTF | ||
| 629 | #define BTF \ | ||
| 630 | .BTF : AT(ADDR(.BTF) - LOAD_OFFSET) { \ | ||
| 631 | __start_BTF = .; \ | ||
| 632 | *(.BTF) \ | ||
| 633 | __stop_BTF = .; \ | ||
| 634 | } | ||
| 635 | #else | ||
| 636 | #define BTF | ||
| 637 | #endif | ||
| 638 | |||
| 624 | /* | 639 | /* |
| 625 | * Init task | 640 | * Init task |
| 626 | */ | 641 | */ |
| @@ -3477,8 +3477,8 @@ errout: · 3476 unmodified lines | |||
| 3477 | return ERR_PTR(err); | 3477 | return ERR_PTR(err); |
| 3478 | } | 3478 | } |
| 3479 | 3479 | ||
| 3480 | extern char __weak _binary__btf_vmlinux_bin_start[]; | 3480 | extern char __weak __start_BTF[]; |
| 3481 | extern char __weak _binary__btf_vmlinux_bin_end[]; | 3481 | extern char __weak __stop_BTF[]; |
| 3482 | extern struct btf *btf_vmlinux; | 3482 | extern struct btf *btf_vmlinux; |
| 3483 | 3483 | ||
| 3484 | #define BPF_MAP_TYPE(_id, _ops) | 3484 | #define BPF_MAP_TYPE(_id, _ops) |
| @@ -3605,9 +3605,8 @@ struct btf *btf_parse_vmlinux(void) · 120 unmodified lines | |||
| 3605 | } | 3605 | } |
| 3606 | env->btf = btf; | 3606 | env->btf = btf; |
| 3607 | 3607 | ||
| 3608 | btf->data = _binary__btf_vmlinux_bin_start; | 3608 | btf->data = __start_BTF; |
| 3609 | btf->data_size = _binary__btf_vmlinux_bin_end - | 3609 | btf->data_size = __stop_BTF - __start_BTF; |
| 3610 | _binary__btf_vmlinux_bin_start; | ||
| 3611 | 3610 | ||
| 3612 | err = btf_parse_hdr(env); | 3611 | err = btf_parse_hdr(env); |
| 3613 | if (err) | 3612 | if (err) |
| @@ -9,15 +9,15 @@ · 8 unmodified lines | |||
| 9 | #include <linux/sysfs.h> | 9 | #include <linux/sysfs.h> |
| 10 | 10 | ||
| 11 | /* See scripts/link-vmlinux.sh, gen_btf() func for details */ | 11 | /* See scripts/link-vmlinux.sh, gen_btf() func for details */ |
| 12 | extern char __weak _binary__btf_vmlinux_bin_start[]; | 12 | extern char __weak __start_BTF[]; |
| 13 | extern char __weak _binary__btf_vmlinux_bin_end[]; | 13 | extern char __weak __stop_BTF[]; |
| 14 | 14 | ||
| 15 | static ssize_t | 15 | static ssize_t |
| 16 | btf_vmlinux_read(struct file *file, struct kobject *kobj, | 16 | btf_vmlinux_read(struct file *file, struct kobject *kobj, |
| 17 | struct bin_attribute *bin_attr, | 17 | struct bin_attribute *bin_attr, |
| 18 | char *buf, loff_t off, size_t len) | 18 | char *buf, loff_t off, size_t len) |
| 19 | { | 19 | { |
| 20 | memcpy(buf, _binary__btf_vmlinux_bin_start + off, len); | 20 | memcpy(buf, __start_BTF + off, len); |
| 21 | return len; | 21 | return len; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| @@ -30,15 +30,14 @@ static struct kobject *btf_kobj; · 6 unmodified lines | |||
| 30 | 30 | ||
| 31 | static int __init btf_vmlinux_init(void) | 31 | static int __init btf_vmlinux_init(void) |
| 32 | { | 32 | { |
| 33 | if (!_binary__btf_vmlinux_bin_start) | 33 | if (!__start_BTF) |
| 34 | return 0; | 34 | return 0; |
| 35 | 35 | ||
| 36 | btf_kobj = kobject_create_and_add("btf", kernel_kobj); | 36 | btf_kobj = kobject_create_and_add("btf", kernel_kobj); |
| 37 | if (!btf_kobj) | 37 | if (!btf_kobj) |
| 38 | return -ENOMEM; | 38 | return -ENOMEM; |
| 39 | 39 | ||
| 40 | bin_attr_btf_vmlinux.size = _binary__btf_vmlinux_bin_end - | 40 | bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF; |
| 41 | _binary__btf_vmlinux_bin_start; | ||
| 42 | 41 | ||
| 43 | return sysfs_create_bin_file(btf_kobj, &bin_attr_btf_vmlinux); | 42 | return sysfs_create_bin_file(btf_kobj, &bin_attr_btf_vmlinux); |
| 44 | } | 43 | } |
| @@ -113,9 +113,6 @@ vmlinux_link() · 112 unmodified lines | |||
| 113 | gen_btf() | 113 | gen_btf() |
| 114 | { | 114 | { |
| 115 | local pahole_ver | 115 | local pahole_ver |
| 116 | local bin_arch | ||
| 117 | local bin_format | ||
| 118 | local bin_file | ||
| 119 | 116 | ||
| 120 | if ! [ -x "$(command -v ${PAHOLE})" ]; then | 117 | if ! [ -x "$(command -v ${PAHOLE})" ]; then |
| 121 | echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available" | 118 | echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available" |
| @@ -133,17 +130,16 @@ gen_btf() · 11 unmodified lines | |||
| 133 | info "BTF" ${2} | 130 | info "BTF" ${2} |
| 134 | LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1} | 131 | LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1} |
| 135 | 132 | ||
| 136 | # dump .BTF section into raw binary file to link with final vmlinux | 133 | # Create ${2} which contains just .BTF section but no symbols. Add |
| 137 | bin_arch=$(LANG=C ${OBJDUMP} -f ${1} | grep architecture | \ | 134 | # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all |
| 138 | cut -d, -f1 | cut -d' ' -f2) | 135 | # deletes all symbols including __start_BTF and __stop_BTF, which will |
| 139 | bin_format=$(LANG=C ${OBJDUMP} -f ${1} | grep 'file format' | \ | 136 | # be redefined in the linker script. Add 2>/dev/null to suppress GNU |
| 140 | awk '{print $4}') | 137 | # objcopy warnings: "empty loadable segment detected at ..." |
| 141 | bin_file=.btf.vmlinux.bin | 138 | ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \ |
| 142 | ${OBJCOPY} --change-section-address .BTF=0 \ | 139 | --strip-all ${1} ${2} 2>/dev/null |
| 143 | --set-section-flags .BTF=alloc -O binary \ | 140 | # Change e_type to ET_REL so that it can be used to link final vmlinux. |
| 144 | --only-section=.BTF ${1} $bin_file | 141 | # Unlike GNU ld, lld does not allow an ET_EXEC input. |
| 145 | ${OBJCOPY} -I binary -O ${bin_format} -B ${bin_arch} \ | 142 | printf '\1' | dd of=${2} conv=notrunc bs=1 seek=16 status=none |
| 146 | --rename-section .data=.BTF $bin_file ${2} | ||
| 147 | } | 143 | } |
| 148 | 144 | ||
| 149 | # Create ${2} .o file with all symbols from the ${1} object file | 145 | # Create ${2} .o file with all symbols from the ${1} object file |