aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/btf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib/bpf/btf.c')
-rw-r--r--tools/lib/bpf/btf.c97
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
27static struct btf_type btf_void; 29static struct btf_type btf_void;
28 30
29struct btf { 31struct 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
420static 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
428static 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
483int 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
411int btf__load(struct btf *btf) 506int 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;