Skip to content

Commit 3aa3fd5

Browse files
yonghong-songacmel
authored andcommitted
btf: add func_proto support
Two new btf kinds, BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO, have been added in kernel since https://patchwork.ozlabs.org/cover/1000176/ to support better func introspection. Currently, for a DW_TAG_subroutine_type dwarf type, a simple "void *" is generated instead of real subroutine type. This patch teaches pahole to generate BTF_KIND_FUNC_PROTO properly. After this patch, pahole should have complete type coverage for C frontend with types a bpf program cares. For example, $ cat t1.c typedef int __int32; struct t1 { int a1; int (*f1)(char p1, __int32 p2); } g1; $ cat t2.c typedef int __int32; struct t2 { int a2; int (*f2)(char q1, __int32 q2, ...); int (*f3)(); } g2; int main() { return 0; } $ gcc -O2 -o t1 -g t1.c t2.c $ pahole -JV t1 File t1: [1] TYPEDEF __int32 type_id=2 [2] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [3] STRUCT t1 kind_flag=0 size=16 vlen=2 a1 type_id=2 bits_offset=0 f1 type_id=6 bits_offset=64 [4] FUNC_PROTO (anon) return=2 args=(5 (anon), 1 (anon)) [5] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [6] PTR (anon) type_id=4 [7] TYPEDEF __int32 type_id=8 [8] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED [9] STRUCT t2 kind_flag=0 size=24 vlen=3 a2 type_id=8 bits_offset=0 f2 type_id=12 bits_offset=64 f3 type_id=14 bits_offset=128 [10] FUNC_PROTO (anon) return=8 args=(11 (anon), 7 (anon), vararg) [11] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) [12] PTR (anon) type_id=10 [13] FUNC_PROTO (anon) return=8 args=(vararg) [14] PTR (anon) type_id=13 $ In the above example, type [4], [10] and [13] represent the func_proto types. BTF_KIND_FUNC, which represents a real subprogram, is not generated in this patch and will be considered later. Signed-off-by: Yonghong Song <yhs@fb.com> Acked-by: Martin KaFai Lau <kafai@fb.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@fb.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 8630ce4 commit 3aa3fd5

4 files changed

Lines changed: 128 additions & 20 deletions

File tree

btf.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ struct btf_type {
6767
#define BTF_KIND_VOLATILE 9 /* Volatile */
6868
#define BTF_KIND_CONST 10 /* Const */
6969
#define BTF_KIND_RESTRICT 11 /* Restrict */
70-
#define BTF_KIND_MAX 11
71-
#define NR_BTF_KINDS 12
70+
#define BTF_KIND_FUNC 12 /* Function */
71+
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
72+
#define BTF_KIND_MAX 13
73+
#define NR_BTF_KINDS 14
7274

7375
/* For some specific BTF_KIND, "struct btf_type" is immediately
7476
* followed by extra data.
@@ -126,4 +128,13 @@ struct btf_member {
126128
#define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
127129
#define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
128130

131+
/* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
132+
* The exact number of btf_param is stored in the vlen (of the
133+
* info in "struct btf_type").
134+
*/
135+
struct btf_param {
136+
__u32 name_off;
137+
__u32 type;
138+
};
139+
129140
#endif /* _UAPI__LINUX_BTF_H__ */

btf_encoder.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,7 @@ static int tag__encode_btf(struct tag *tag, uint32_t core_id, struct btf *btf,
170170
case DW_TAG_enumeration_type:
171171
return enumeration_type__encode(btf, tag);
172172
case DW_TAG_subroutine_type:
173-
/* A dummy void * to avoid a shift in btf->type_index */
174-
btf_verbose_log("Filling unsupported DW_TAG_%s(0x%x) with void *\n",
175-
dwarf_tag_name(tag->tag), tag->tag);
176-
return btf__add_ref_type(btf, BTF_KIND_PTR, 0, 0, false);
173+
return btf__add_func_proto(btf, tag__ftype(tag), type_id_off);
177174
default:
178175
fprintf(stderr, "Unsupported DW_TAG_%s(0x%x)\n",
179176
dwarf_tag_name(tag->tag), tag->tag);

libbtf.c

Lines changed: 111 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
142142
[BTF_KIND_VOLATILE] = "VOLATILE",
143143
[BTF_KIND_CONST] = "CONST",
144144
[BTF_KIND_RESTRICT] = "RESTRICT",
145+
[BTF_KIND_FUNC] = "FUNC",
146+
[BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
145147
};
146148

147149
static const char *btf__name_in_gobuf(const struct btf *btf,
@@ -167,9 +169,9 @@ static const char * btf__int_encoding_str(uint8_t encoding)
167169
return "UNKN";
168170
}
169171

170-
__attribute ((format (printf, 4, 5)))
172+
__attribute ((format (printf, 5, 6)))
171173
static void btf__log_type(const struct btf *btf, const struct btf_type *t,
172-
bool err, const char *fmt, ...)
174+
bool err, bool output_cr, const char *fmt, ...)
173175
{
174176
uint8_t kind;
175177
FILE *out;
@@ -193,7 +195,8 @@ static void btf__log_type(const struct btf *btf, const struct btf_type *t,
193195
va_end(ap);
194196
}
195197

196-
fprintf(out, "\n");
198+
if (output_cr)
199+
fprintf(out, "\n");
197200
}
198201

199202
__attribute ((format (printf, 5, 6)))
@@ -232,6 +235,36 @@ static void btf_log_member(const struct btf *btf,
232235
fprintf(out, "\n");
233236
}
234237

238+
__attribute ((format (printf, 6, 7)))
239+
static void btf_log_func_param(const struct btf *btf,
240+
uint32_t name_off, uint32_t type,
241+
bool err, bool is_last_param,
242+
const char *fmt, ...)
243+
{
244+
FILE *out;
245+
246+
if (!btf_verbose && !err)
247+
return;
248+
249+
out = err ? stderr : stdout;
250+
251+
if (is_last_param && !type)
252+
fprintf(out, "vararg)\n");
253+
else
254+
fprintf(out, "%u %s%s", type,
255+
btf__name_in_gobuf(btf, name_off),
256+
is_last_param ? ")\n" : ", ");
257+
258+
if (fmt && *fmt) {
259+
va_list ap;
260+
261+
fprintf(out, " ");
262+
va_start(ap, fmt);
263+
vfprintf(out, fmt, ap);
264+
va_end(ap);
265+
}
266+
}
267+
235268
int32_t btf__add_base_type(struct btf *btf, const struct base_type *bt)
236269
{
237270
struct btf_int_type int_type;
@@ -253,14 +286,14 @@ int32_t btf__add_base_type(struct btf *btf, const struct base_type *bt)
253286

254287
++btf->type_index;
255288
if (gobuffer__add(&btf->types, &int_type, sizeof(int_type)) >= 0) {
256-
btf__log_type(btf, t, false,
289+
btf__log_type(btf, t, false, true,
257290
"size=%u bit_offset=%u nr_bits=%u encoding=%s",
258291
t->size, BTF_INT_OFFSET(int_type.data),
259292
BTF_INT_BITS(int_type.data),
260293
btf__int_encoding_str(BTF_INT_ENCODING(int_type.data)));
261294
return btf->type_index;
262295
} else {
263-
btf__log_type(btf, t, true,
296+
btf__log_type(btf, t, true, true,
264297
"size=%u bit_offset=%u nr_bits=%u encoding=%s Error in adding gobuffer",
265298
t->size, BTF_INT_OFFSET(int_type.data),
266299
BTF_INT_BITS(int_type.data),
@@ -281,13 +314,13 @@ int32_t btf__add_ref_type(struct btf *btf, uint16_t kind, uint32_t type,
281314
++btf->type_index;
282315
if (gobuffer__add(&btf->types, &t, sizeof(t)) >= 0) {
283316
if (kind == BTF_KIND_FWD)
284-
btf__log_type(btf, &t, false, "%s",
317+
btf__log_type(btf, &t, false, true, "%s",
285318
kind_flag ? "union" : "struct");
286319
else
287-
btf__log_type(btf, &t, false, "type_id=%u", t.type);
320+
btf__log_type(btf, &t, false, true, "type_id=%u", t.type);
288321
return btf->type_index;
289322
} else {
290-
btf__log_type(btf, &t, true,
323+
btf__log_type(btf, &t, true, true,
291324
"kind_flag=%d type_id=%u Error in adding gobuffer",
292325
kind_flag, t.type);
293326
return -1;
@@ -311,12 +344,12 @@ int32_t btf__add_array(struct btf *btf, uint32_t type, uint32_t index_type,
311344

312345
++btf->type_index;
313346
if (gobuffer__add(&btf->types, &array_type, sizeof(array_type)) >= 0) {
314-
btf__log_type(btf, t, false,
347+
btf__log_type(btf, t, false, true,
315348
"type_id=%u index_type_id=%u nr_elems=%u",
316349
array->type, array->index_type, array->nelems);
317350
return btf->type_index;
318351
} else {
319-
btf__log_type(btf, t, true,
352+
btf__log_type(btf, t, true, true,
320353
"type_id=%u index_type_id=%u nr_elems=%u Error in adding gobuffer",
321354
array->type, array->index_type, array->nelems);
322355
return -1;
@@ -352,11 +385,11 @@ int32_t btf__add_struct(struct btf *btf, uint8_t kind, uint32_t name,
352385

353386
++btf->type_index;
354387
if (gobuffer__add(&btf->types, &t, sizeof(t)) >= 0) {
355-
btf__log_type(btf, &t, false, "kind_flag=%d size=%u vlen=%u",
388+
btf__log_type(btf, &t, false, true, "kind_flag=%d size=%u vlen=%u",
356389
kind_flag, t.size, BTF_INFO_VLEN(t.info));
357390
return btf->type_index;
358391
} else {
359-
btf__log_type(btf, &t, true,
392+
btf__log_type(btf, &t, true, true,
360393
"kind_flag=%d size=%u vlen=%u Error in adding gobuffer",
361394
kind_flag, t.size, BTF_INFO_VLEN(t.info));
362395
return -1;
@@ -374,11 +407,11 @@ int32_t btf__add_enum(struct btf *btf, uint32_t name, uint32_t bit_size,
374407

375408
++btf->type_index;
376409
if (gobuffer__add(&btf->types, &t, sizeof(t)) >= 0) {
377-
btf__log_type(btf, &t, false, "size=%u vlen=%u",
410+
btf__log_type(btf, &t, false, true, "size=%u vlen=%u",
378411
t.size, BTF_INFO_VLEN(t.info));
379412
return btf->type_index;
380413
} else {
381-
btf__log_type(btf, &t, true,
414+
btf__log_type(btf, &t, true, true,
382415
"size=%u vlen=%u Error in adding gobuffer",
383416
t.size, BTF_INFO_VLEN(t.info));
384417
return -1;
@@ -403,6 +436,70 @@ int btf__add_enum_val(struct btf *btf, uint32_t name, int32_t value)
403436
return 0;
404437
}
405438

439+
static int32_t btf__add_func_proto_param(struct btf *btf, uint32_t name,
440+
uint32_t type, bool is_last_param)
441+
{
442+
struct btf_param param;
443+
444+
param.name_off = name;
445+
param.type = type;
446+
447+
if (gobuffer__add(&btf->types, &param, sizeof(param)) >= 0) {
448+
btf_log_func_param(btf, name, type, false, is_last_param, NULL);
449+
return 0;
450+
} else {
451+
btf_log_func_param(btf, name, type, true, is_last_param,
452+
"Error in adding gobuffer");
453+
return -1;
454+
}
455+
}
456+
457+
int32_t btf__add_func_proto(struct btf *btf, struct ftype *ftype,
458+
uint32_t type_id_off)
459+
{
460+
uint16_t nr_params, param_idx;
461+
struct parameter *param;
462+
struct btf_type t;
463+
int32_t type_id;
464+
465+
/* add btf_type for func_proto */
466+
nr_params = ftype->nr_parms + (ftype->unspec_parms ? 1 : 0);
467+
468+
t.name_off = 0;
469+
t.info = BTF_INFO_ENCODE(BTF_KIND_FUNC_PROTO, 0, nr_params);
470+
t.type = type_id_off + ftype->tag.type;
471+
472+
++btf->type_index;
473+
if (gobuffer__add(&btf->types, &t, sizeof(t)) >= 0) {
474+
btf__log_type(btf, &t, false, false, "return=%u args=(%s",
475+
t.type, !nr_params ? "void)\n" : "");
476+
type_id = btf->type_index;
477+
} else {
478+
btf__log_type(btf, &t, true, true,
479+
"return=%u vlen=%u Error in adding gobuffer",
480+
t.type, BTF_INFO_VLEN(t.info));
481+
return -1;
482+
}
483+
484+
/* add parameters */
485+
param_idx = 0;
486+
ftype__for_each_parameter(ftype, param) {
487+
++param_idx;
488+
if (btf__add_func_proto_param(btf, param->name,
489+
type_id_off + param->tag.type,
490+
param_idx == nr_params))
491+
return -1;
492+
}
493+
494+
++param_idx;
495+
if (ftype->unspec_parms)
496+
if (btf__add_func_proto_param(btf, 0, 0,
497+
param_idx == nr_params))
498+
return -1;
499+
500+
return type_id;
501+
}
502+
406503
static int btf__write_elf(struct btf *btf)
407504
{
408505
GElf_Shdr shdr_mem, *shdr;

libbtf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern uint8_t btf_verbose;
2929
#define btf_verbose_log(fmt, ...) { if (btf_verbose) printf(fmt, __VA_ARGS__); }
3030

3131
struct base_type;
32+
struct ftype;
3233

3334
struct btf *btf__new(const char *filename, Elf *elf);
3435
void btf__free(struct btf *btf);
@@ -45,6 +46,8 @@ int32_t btf__add_array(struct btf *btf, uint32_t type, uint32_t index_type,
4546
int32_t btf__add_enum(struct btf *btf, uint32_t name, uint32_t size,
4647
uint16_t nr_entries);
4748
int btf__add_enum_val(struct btf *btf, uint32_t name, int32_t value);
49+
int32_t btf__add_func_proto(struct btf *btf, struct ftype *ftype,
50+
uint32_t type_id_off);
4851
void btf__set_strings(struct btf *btf, struct gobuffer *strings);
4952
int btf__encode(struct btf *btf, uint8_t flags);
5053

0 commit comments

Comments
 (0)