On 1/26/24 10:10 AM, Yonghong Song wrote:
On 1/25/24 2:56 PM, David Faust wrote:
This morning in the BPF office hours we discussed BTF, starting from
some specific cases where gcc and clang differ, and ending up at the
broader question of what precisely should or should not be present
in generated BTF info and in what cases.
Below is a summary/notes on the discussion so far. Apologies if I've
forgotten anything.
Motivation: there are some cases where gcc emits more BTF information
than clang, in particular (not necessarily exhaustive):
+ clang does not emit BTF for unused static vars
+ clang does not emit BTF for variables which have been optimized
away entirely
+ clang does not emit BTF for types which are only used by one
of the above
(See a couple of concrete examples at the bottom.)
that is correct.
[...]
- This also comes with some drawbacks, in some cases BTF will not
be emitted when it is desired. There is a BTF_TYPE_EMIT macro to
work around that. It isn't a perfect solution.
This is due to dwarf. The type most likely not in dwarf,
I will take a look.
In yesterday's bpf office hour meeting, Alexei mentioned that struct
bpf_timer needs "BTF_TYPE_EMIT(struct bpf_timer)" to force dwarf
generating an entry although there are usages of "struct bpf_timer"
in the kernel.
I checked and found the only usage of "struct bpf_timer" is
sizeof(...) and __alignof__(...).
e.g.,
helpers.c: BUILD_BUG_ON(sizeof(struct bpf_timer_kern) > sizeof(struct bpf_timer));
helpers.c: BUILD_BUG_ON(__alignof__(struct bpf_timer_kern) != __alignof__(struct bpf_timer));
and unfortunately dwarf is not generated for such cases. The frontend
resolves the above sizeof(...) and __alignof__(...) as the constant before
generating debug info inside the compiler.
For example,
$ cat t2.c
struct bpf_timer {
int a;
int b;
};
int foo() {
int v1, v2;
v1 = sizeof(struct bpf_timer);
v2 = __alignof__(struct bpf_timer);
return v1 + v2;
}
$ clang -O2 -g -c t2.c
$ llvm-dwarfdump t2.o
t2.o: file format elf64-x86-64
.debug_info contents:
0x00000000: Compile Unit: length = 0x00000046, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, a
ddr_size = 0x08 (next unit at 0x0000004a)
0x0000000c: DW_TAG_compile_unit
DW_AT_producer ("clang version 19.0.0git (https://github.com/llvm/llvm-project.git 6d0080b5de26d8a8682ec6169851af3d0
4e30ccb)")
DW_AT_language (DW_LANG_C11)
DW_AT_name ("t2.c")
DW_AT_str_offsets_base (0x00000008)
DW_AT_stmt_list (0x00000000)
DW_AT_comp_dir ("/home/yhs/tmp10/btf")
DW_AT_low_pc (0x0000000000000000)
DW_AT_high_pc (0x0000000000000006)
DW_AT_addr_base (0x00000008)
0x00000023: DW_TAG_subprogram
DW_AT_low_pc (0x0000000000000000)
DW_AT_high_pc (0x0000000000000006)
DW_AT_frame_base (DW_OP_reg7 RSP)
DW_AT_call_all_calls (true)
DW_AT_name ("foo")
DW_AT_decl_file ("/home/yhs/tmp10/btf/t2.c")
DW_AT_decl_line (6)
DW_AT_type (0x00000045 "int")
DW_AT_external (true)
0x00000032: DW_TAG_variable
DW_AT_const_value (8)
DW_AT_name ("v1")
DW_AT_decl_file ("/home/yhs/tmp10/btf/t2.c")
DW_AT_decl_line (7)
DW_AT_type (0x00000045 "int")
0x0000003b: DW_TAG_variable
DW_AT_const_value (4)
DW_AT_name ("v2")
DW_AT_decl_file ("/home/yhs/tmp10/btf/t2.c")
DW_AT_decl_line (7)
DW_AT_type (0x00000045 "int")
0x00000044: NULL
0x00000045: DW_TAG_base_type
DW_AT_name ("int")
DW_AT_encoding (DW_ATE_signed)
DW_AT_byte_size (0x04)
0x00000049: NULL
So, the question is twofold:
1. What ought to be represented in BTF for a BPF program?
2. Is that/should that be followed for non-BPF program cases, such
as generating BTF for vmlinux?
[...]