diff options
Diffstat (limited to 'tools/lib/bpf/btf.c')
-rw-r--r-- | tools/lib/bpf/btf.c | 97 |
1 files changed, 96 insertions, 1 deletions
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 87e3020ac1bc..0f9079b9539e 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c | |||
@@ -24,6 +24,8 @@ | |||
24 | ((k) == BTF_KIND_CONST) || \ | 24 | ((k) == BTF_KIND_CONST) || \ |
25 | ((k) == BTF_KIND_RESTRICT)) | 25 | ((k) == BTF_KIND_RESTRICT)) |
26 | 26 | ||
27 | #define IS_VAR(k) ((k) == BTF_KIND_VAR) | ||
28 | |||
27 | static struct btf_type btf_void; | 29 | static struct btf_type btf_void; |
28 | 30 | ||
29 | struct btf { | 31 | struct btf { |
@@ -212,6 +214,10 @@ static int btf_type_size(struct btf_type *t) | |||
212 | return base_size + vlen * sizeof(struct btf_member); | 214 | return base_size + vlen * sizeof(struct btf_member); |
213 | case BTF_KIND_FUNC_PROTO: | 215 | case BTF_KIND_FUNC_PROTO: |
214 | return base_size + vlen * sizeof(struct btf_param); | 216 | return base_size + vlen * sizeof(struct btf_param); |
217 | case BTF_KIND_VAR: | ||
218 | return base_size + sizeof(struct btf_var); | ||
219 | case BTF_KIND_DATASEC: | ||
220 | return base_size + vlen * sizeof(struct btf_var_secinfo); | ||
215 | default: | 221 | default: |
216 | pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info)); | 222 | pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info)); |
217 | return -EINVAL; | 223 | return -EINVAL; |
@@ -283,6 +289,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) | |||
283 | case BTF_KIND_STRUCT: | 289 | case BTF_KIND_STRUCT: |
284 | case BTF_KIND_UNION: | 290 | case BTF_KIND_UNION: |
285 | case BTF_KIND_ENUM: | 291 | case BTF_KIND_ENUM: |
292 | case BTF_KIND_DATASEC: | ||
286 | size = t->size; | 293 | size = t->size; |
287 | goto done; | 294 | goto done; |
288 | case BTF_KIND_PTR: | 295 | case BTF_KIND_PTR: |
@@ -292,6 +299,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) | |||
292 | case BTF_KIND_VOLATILE: | 299 | case BTF_KIND_VOLATILE: |
293 | case BTF_KIND_CONST: | 300 | case BTF_KIND_CONST: |
294 | case BTF_KIND_RESTRICT: | 301 | case BTF_KIND_RESTRICT: |
302 | case BTF_KIND_VAR: | ||
295 | type_id = t->type; | 303 | type_id = t->type; |
296 | break; | 304 | break; |
297 | case BTF_KIND_ARRAY: | 305 | case BTF_KIND_ARRAY: |
@@ -326,7 +334,8 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id) | |||
326 | t = btf__type_by_id(btf, type_id); | 334 | t = btf__type_by_id(btf, type_id); |
327 | while (depth < MAX_RESOLVE_DEPTH && | 335 | while (depth < MAX_RESOLVE_DEPTH && |
328 | !btf_type_is_void_or_null(t) && | 336 | !btf_type_is_void_or_null(t) && |
329 | IS_MODIFIER(BTF_INFO_KIND(t->info))) { | 337 | (IS_MODIFIER(BTF_INFO_KIND(t->info)) || |
338 | IS_VAR(BTF_INFO_KIND(t->info)))) { | ||
330 | type_id = t->type; | 339 | type_id = t->type; |
331 | t = btf__type_by_id(btf, type_id); | 340 | t = btf__type_by_id(btf, type_id); |
332 | depth++; | 341 | depth++; |
@@ -408,6 +417,92 @@ done: | |||
408 | return btf; | 417 | return btf; |
409 | } | 418 | } |
410 | 419 | ||
420 | static int compare_vsi_off(const void *_a, const void *_b) | ||
421 | { | ||
422 | const struct btf_var_secinfo *a = _a; | ||
423 | const struct btf_var_secinfo *b = _b; | ||
424 | |||
425 | return a->offset - b->offset; | ||
426 | } | ||
427 | |||
428 | static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf, | ||
429 | struct btf_type *t) | ||
430 | { | ||
431 | __u32 size = 0, off = 0, i, vars = BTF_INFO_VLEN(t->info); | ||
432 | const char *name = btf__name_by_offset(btf, t->name_off); | ||
433 | const struct btf_type *t_var; | ||
434 | struct btf_var_secinfo *vsi; | ||
435 | struct btf_var *var; | ||
436 | int ret; | ||
437 | |||
438 | if (!name) { | ||
439 | pr_debug("No name found in string section for DATASEC kind.\n"); | ||
440 | return -ENOENT; | ||
441 | } | ||
442 | |||
443 | ret = bpf_object__section_size(obj, name, &size); | ||
444 | if (ret || !size || (t->size && t->size != size)) { | ||
445 | pr_debug("Invalid size for section %s: %u bytes\n", name, size); | ||
446 | return -ENOENT; | ||
447 | } | ||
448 | |||
449 | t->size = size; | ||
450 | |||
451 | for (i = 0, vsi = (struct btf_var_secinfo *)(t + 1); | ||
452 | i < vars; i++, vsi++) { | ||
453 | t_var = btf__type_by_id(btf, vsi->type); | ||
454 | var = (struct btf_var *)(t_var + 1); | ||
455 | |||
456 | if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) { | ||
457 | pr_debug("Non-VAR type seen in section %s\n", name); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | |||
461 | if (var->linkage == BTF_VAR_STATIC) | ||
462 | continue; | ||
463 | |||
464 | name = btf__name_by_offset(btf, t_var->name_off); | ||
465 | if (!name) { | ||
466 | pr_debug("No name found in string section for VAR kind\n"); | ||
467 | return -ENOENT; | ||
468 | } | ||
469 | |||
470 | ret = bpf_object__variable_offset(obj, name, &off); | ||
471 | if (ret) { | ||
472 | pr_debug("No offset found in symbol table for VAR %s\n", name); | ||
473 | return -ENOENT; | ||
474 | } | ||
475 | |||
476 | vsi->offset = off; | ||
477 | } | ||
478 | |||
479 | qsort(t + 1, vars, sizeof(*vsi), compare_vsi_off); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | int btf__finalize_data(struct bpf_object *obj, struct btf *btf) | ||
484 | { | ||
485 | int err = 0; | ||
486 | __u32 i; | ||
487 | |||
488 | for (i = 1; i <= btf->nr_types; i++) { | ||
489 | struct btf_type *t = btf->types[i]; | ||
490 | |||
491 | /* Loader needs to fix up some of the things compiler | ||
492 | * couldn't get its hands on while emitting BTF. This | ||
493 | * is section size and global variable offset. We use | ||
494 | * the info from the ELF itself for this purpose. | ||
495 | */ | ||
496 | if (BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC) { | ||
497 | err = btf_fixup_datasec(obj, btf, t); | ||
498 | if (err) | ||
499 | break; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | return err; | ||
504 | } | ||
505 | |||
411 | int btf__load(struct btf *btf) | 506 | int btf__load(struct btf *btf) |
412 | { | 507 | { |
413 | __u32 log_buf_size = BPF_LOG_BUF_SIZE; | 508 | __u32 log_buf_size = BPF_LOG_BUF_SIZE; |