Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: Handle GCC noreturn-turned-volatile quirk

Handle a GCC quirk of emitting extra volatile modifier in DWARF (and
subsequently preserved in BTF by pahole) for function pointers marked as
__attribute__((noreturn)). This was the way to mark such functions before GCC
2.5 added noreturn attribute. Drop such func_proto modifiers, similarly to how
it's done for array (also to handle GCC quirk/bug).

Such volatile attribute is emitted by GCC only, so existing selftests can't
express such test. Simple repro is like this (compiled with GCC + BTF
generated by pahole):

struct my_struct {
void __attribute__((noreturn)) (*fn)(int);
};
struct my_struct a;

Without this fix, output will be:

struct my_struct {
voidvolatile (*fn)(int);
};

With the fix:

struct my_struct {
void (*fn)(int);
};

Fixes: 351131b51c7a ("libbpf: add btf_dump API for BTF-to-C conversion")
Reported-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Tested-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Link: https://lore.kernel.org/bpf/20200610052335.2862559-1-andriin@fb.com

authored by

Andrii Nakryiko and committed by
Daniel Borkmann
32022fd9 8ca8d4a8

+24 -9
+24 -9
tools/lib/bpf/btf_dump.c
··· 1137 1137 } 1138 1138 } 1139 1139 1140 + static void btf_dump_drop_mods(struct btf_dump *d, struct id_stack *decl_stack) 1141 + { 1142 + const struct btf_type *t; 1143 + __u32 id; 1144 + 1145 + while (decl_stack->cnt) { 1146 + id = decl_stack->ids[decl_stack->cnt - 1]; 1147 + t = btf__type_by_id(d->btf, id); 1148 + if (!btf_is_mod(t)) 1149 + return; 1150 + decl_stack->cnt--; 1151 + } 1152 + } 1153 + 1140 1154 static void btf_dump_emit_name(const struct btf_dump *d, 1141 1155 const char *name, bool last_was_ptr) 1142 1156 { ··· 1249 1235 * a const/volatile modifier for array, so we are 1250 1236 * going to silently skip them here. 1251 1237 */ 1252 - while (decls->cnt) { 1253 - next_id = decls->ids[decls->cnt - 1]; 1254 - next_t = btf__type_by_id(d->btf, next_id); 1255 - if (btf_is_mod(next_t)) 1256 - decls->cnt--; 1257 - else 1258 - break; 1259 - } 1238 + btf_dump_drop_mods(d, decls); 1260 1239 1261 1240 if (decls->cnt == 0) { 1262 1241 btf_dump_emit_name(d, fname, last_was_ptr); ··· 1277 1270 __u16 vlen = btf_vlen(t); 1278 1271 int i; 1279 1272 1280 - btf_dump_emit_mods(d, decls); 1273 + /* 1274 + * GCC emits extra volatile qualifier for 1275 + * __attribute__((noreturn)) function pointers. Clang 1276 + * doesn't do it. It's a GCC quirk for backwards 1277 + * compatibility with code written for GCC <2.5. So, 1278 + * similarly to extra qualifiers for array, just drop 1279 + * them, instead of handling them. 1280 + */ 1281 + btf_dump_drop_mods(d, decls); 1281 1282 if (decls->cnt) { 1282 1283 btf_dump_printf(d, " ("); 1283 1284 btf_dump_emit_type_chain(d, decls, fname, lvl);