aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/btf.c
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2019-04-09 17:20:14 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-04-09 20:05:47 -0400
commit1713d68b3bf039d029afd74653c9325f5003ccbe (patch)
tree1a075e1e49244968145a450df10005fc73df0282 /tools/lib/bpf/btf.c
parentd859900c4c56dc4f0f8894c92a01dad86917453e (diff)
bpf, libbpf: add support for BTF Var and DataSec
This adds libbpf support for BTF Var and DataSec kinds. Main point here is that libbpf needs to do some preparatory work before the whole BTF object can be loaded into the kernel, that is, fixing up of DataSec size taken from the ELF section size and non-static variable offset which needs to be taken from the ELF's string section. Upstream LLVM doesn't fix these up since at time of BTF emission it is too early in the compilation process thus this information isn't available yet, hence loader needs to take care of it. Note, deduplication handling has not been in the scope of this work and needs to be addressed in a future commit. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://reviews.llvm.org/D59441 Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
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;