bpf tools: Add bpf.c/h for common bpf operations
[deliverable/linux.git] / tools / lib / bpf / libbpf.c
CommitLineData
1b76c13e
WN
1/*
2 * Common eBPF ELF object loading operations.
3 *
4 * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
5 * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
6 * Copyright (C) 2015 Huawei Inc.
7 */
8
9#include <stdlib.h>
b3f59d66
WN
10#include <stdio.h>
11#include <stdarg.h>
34090915 12#include <inttypes.h>
b3f59d66 13#include <string.h>
1b76c13e 14#include <unistd.h>
1a5e3fb1
WN
15#include <fcntl.h>
16#include <errno.h>
1b76c13e 17#include <asm/unistd.h>
cb1e5e96 18#include <linux/kernel.h>
1b76c13e 19#include <linux/bpf.h>
1a5e3fb1
WN
20#include <libelf.h>
21#include <gelf.h>
1b76c13e
WN
22
23#include "libbpf.h"
b3f59d66
WN
24
25#define __printf(a, b) __attribute__((format(printf, a, b)))
26
27__printf(1, 2)
28static int __base_pr(const char *format, ...)
29{
30 va_list args;
31 int err;
32
33 va_start(args, format);
34 err = vfprintf(stderr, format, args);
35 va_end(args);
36 return err;
37}
38
39static __printf(1, 2) libbpf_print_fn_t __pr_warning = __base_pr;
40static __printf(1, 2) libbpf_print_fn_t __pr_info = __base_pr;
41static __printf(1, 2) libbpf_print_fn_t __pr_debug;
42
43#define __pr(func, fmt, ...) \
44do { \
45 if ((func)) \
46 (func)("libbpf: " fmt, ##__VA_ARGS__); \
47} while (0)
48
49#define pr_warning(fmt, ...) __pr(__pr_warning, fmt, ##__VA_ARGS__)
50#define pr_info(fmt, ...) __pr(__pr_info, fmt, ##__VA_ARGS__)
51#define pr_debug(fmt, ...) __pr(__pr_debug, fmt, ##__VA_ARGS__)
52
53void libbpf_set_print(libbpf_print_fn_t warn,
54 libbpf_print_fn_t info,
55 libbpf_print_fn_t debug)
56{
57 __pr_warning = warn;
58 __pr_info = info;
59 __pr_debug = debug;
60}
1a5e3fb1
WN
61
62/* Copied from tools/perf/util/util.h */
63#ifndef zfree
64# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
65#endif
66
67#ifndef zclose
68# define zclose(fd) ({ \
69 int ___err = 0; \
70 if ((fd) >= 0) \
71 ___err = close((fd)); \
72 fd = -1; \
73 ___err; })
74#endif
75
76#ifdef HAVE_LIBELF_MMAP_SUPPORT
77# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ_MMAP
78#else
79# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
80#endif
81
a5b8bd47
WN
82/*
83 * bpf_prog should be a better name but it has been used in
84 * linux/filter.h.
85 */
86struct bpf_program {
87 /* Index in elf obj file, for relocation use. */
88 int idx;
89 char *section_name;
90 struct bpf_insn *insns;
91 size_t insns_cnt;
34090915
WN
92
93 struct {
94 int insn_idx;
95 int map_idx;
96 } *reloc_desc;
97 int nr_reloc;
a5b8bd47
WN
98};
99
1a5e3fb1 100struct bpf_object {
cb1e5e96
WN
101 char license[64];
102 u32 kern_version;
0b3d1efa
WN
103 void *maps_buf;
104 size_t maps_buf_sz;
105
a5b8bd47
WN
106 struct bpf_program *programs;
107 size_t nr_programs;
108
1a5e3fb1
WN
109 /*
110 * Information when doing elf related work. Only valid if fd
111 * is valid.
112 */
113 struct {
114 int fd;
6c956392
WN
115 void *obj_buf;
116 size_t obj_buf_sz;
1a5e3fb1
WN
117 Elf *elf;
118 GElf_Ehdr ehdr;
bec7d68c 119 Elf_Data *symbols;
b62f06e8
WN
120 struct {
121 GElf_Shdr shdr;
122 Elf_Data *data;
123 } *reloc;
124 int nr_reloc;
1a5e3fb1
WN
125 } efile;
126 char path[];
127};
128#define obj_elf_valid(o) ((o)->efile.elf)
129
a5b8bd47
WN
130static void bpf_program__exit(struct bpf_program *prog)
131{
132 if (!prog)
133 return;
134
135 zfree(&prog->section_name);
136 zfree(&prog->insns);
34090915
WN
137 zfree(&prog->reloc_desc);
138
139 prog->nr_reloc = 0;
a5b8bd47
WN
140 prog->insns_cnt = 0;
141 prog->idx = -1;
142}
143
144static int
145bpf_program__init(void *data, size_t size, char *name, int idx,
146 struct bpf_program *prog)
147{
148 if (size < sizeof(struct bpf_insn)) {
149 pr_warning("corrupted section '%s'\n", name);
150 return -EINVAL;
151 }
152
153 bzero(prog, sizeof(*prog));
154
155 prog->section_name = strdup(name);
156 if (!prog->section_name) {
157 pr_warning("failed to alloc name for prog %s\n",
158 name);
159 goto errout;
160 }
161
162 prog->insns = malloc(size);
163 if (!prog->insns) {
164 pr_warning("failed to alloc insns for %s\n", name);
165 goto errout;
166 }
167 prog->insns_cnt = size / sizeof(struct bpf_insn);
168 memcpy(prog->insns, data,
169 prog->insns_cnt * sizeof(struct bpf_insn));
170 prog->idx = idx;
171
172 return 0;
173errout:
174 bpf_program__exit(prog);
175 return -ENOMEM;
176}
177
178static int
179bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
180 char *name, int idx)
181{
182 struct bpf_program prog, *progs;
183 int nr_progs, err;
184
185 err = bpf_program__init(data, size, name, idx, &prog);
186 if (err)
187 return err;
188
189 progs = obj->programs;
190 nr_progs = obj->nr_programs;
191
192 progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1));
193 if (!progs) {
194 /*
195 * In this case the original obj->programs
196 * is still valid, so don't need special treat for
197 * bpf_close_object().
198 */
199 pr_warning("failed to alloc a new program '%s'\n",
200 name);
201 bpf_program__exit(&prog);
202 return -ENOMEM;
203 }
204
205 pr_debug("found program %s\n", prog.section_name);
206 obj->programs = progs;
207 obj->nr_programs = nr_progs + 1;
208 progs[nr_progs] = prog;
209 return 0;
210}
211
6c956392
WN
212static struct bpf_object *bpf_object__new(const char *path,
213 void *obj_buf,
214 size_t obj_buf_sz)
1a5e3fb1
WN
215{
216 struct bpf_object *obj;
217
218 obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1);
219 if (!obj) {
220 pr_warning("alloc memory failed for %s\n", path);
221 return NULL;
222 }
223
224 strcpy(obj->path, path);
225 obj->efile.fd = -1;
6c956392
WN
226
227 /*
228 * Caller of this function should also calls
229 * bpf_object__elf_finish() after data collection to return
230 * obj_buf to user. If not, we should duplicate the buffer to
231 * avoid user freeing them before elf finish.
232 */
233 obj->efile.obj_buf = obj_buf;
234 obj->efile.obj_buf_sz = obj_buf_sz;
235
1a5e3fb1
WN
236 return obj;
237}
238
239static void bpf_object__elf_finish(struct bpf_object *obj)
240{
241 if (!obj_elf_valid(obj))
242 return;
243
244 if (obj->efile.elf) {
245 elf_end(obj->efile.elf);
246 obj->efile.elf = NULL;
247 }
bec7d68c 248 obj->efile.symbols = NULL;
b62f06e8
WN
249
250 zfree(&obj->efile.reloc);
251 obj->efile.nr_reloc = 0;
1a5e3fb1 252 zclose(obj->efile.fd);
6c956392
WN
253 obj->efile.obj_buf = NULL;
254 obj->efile.obj_buf_sz = 0;
1a5e3fb1
WN
255}
256
257static int bpf_object__elf_init(struct bpf_object *obj)
258{
259 int err = 0;
260 GElf_Ehdr *ep;
261
262 if (obj_elf_valid(obj)) {
263 pr_warning("elf init: internal error\n");
264 return -EEXIST;
265 }
266
6c956392
WN
267 if (obj->efile.obj_buf_sz > 0) {
268 /*
269 * obj_buf should have been validated by
270 * bpf_object__open_buffer().
271 */
272 obj->efile.elf = elf_memory(obj->efile.obj_buf,
273 obj->efile.obj_buf_sz);
274 } else {
275 obj->efile.fd = open(obj->path, O_RDONLY);
276 if (obj->efile.fd < 0) {
277 pr_warning("failed to open %s: %s\n", obj->path,
278 strerror(errno));
279 return -errno;
280 }
281
282 obj->efile.elf = elf_begin(obj->efile.fd,
283 LIBBPF_ELF_C_READ_MMAP,
284 NULL);
1a5e3fb1
WN
285 }
286
1a5e3fb1
WN
287 if (!obj->efile.elf) {
288 pr_warning("failed to open %s as ELF file\n",
289 obj->path);
290 err = -EINVAL;
291 goto errout;
292 }
293
294 if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) {
295 pr_warning("failed to get EHDR from %s\n",
296 obj->path);
297 err = -EINVAL;
298 goto errout;
299 }
300 ep = &obj->efile.ehdr;
301
302 if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) {
303 pr_warning("%s is not an eBPF object file\n",
304 obj->path);
305 err = -EINVAL;
306 goto errout;
307 }
308
309 return 0;
310errout:
311 bpf_object__elf_finish(obj);
312 return err;
313}
314
cc4228d5
WN
315static int
316bpf_object__check_endianness(struct bpf_object *obj)
317{
318 static unsigned int const endian = 1;
319
320 switch (obj->efile.ehdr.e_ident[EI_DATA]) {
321 case ELFDATA2LSB:
322 /* We are big endian, BPF obj is little endian. */
323 if (*(unsigned char const *)&endian != 1)
324 goto mismatch;
325 break;
326
327 case ELFDATA2MSB:
328 /* We are little endian, BPF obj is big endian. */
329 if (*(unsigned char const *)&endian != 0)
330 goto mismatch;
331 break;
332 default:
333 return -EINVAL;
334 }
335
336 return 0;
337
338mismatch:
339 pr_warning("Error: endianness mismatch.\n");
340 return -EINVAL;
341}
342
cb1e5e96
WN
343static int
344bpf_object__init_license(struct bpf_object *obj,
345 void *data, size_t size)
346{
347 memcpy(obj->license, data,
348 min(size, sizeof(obj->license) - 1));
349 pr_debug("license of %s is %s\n", obj->path, obj->license);
350 return 0;
351}
352
353static int
354bpf_object__init_kversion(struct bpf_object *obj,
355 void *data, size_t size)
356{
357 u32 kver;
358
359 if (size != sizeof(kver)) {
360 pr_warning("invalid kver section in %s\n", obj->path);
361 return -EINVAL;
362 }
363 memcpy(&kver, data, sizeof(kver));
364 obj->kern_version = kver;
365 pr_debug("kernel version of %s is %x\n", obj->path,
366 obj->kern_version);
367 return 0;
368}
369
0b3d1efa
WN
370static int
371bpf_object__init_maps(struct bpf_object *obj, void *data,
372 size_t size)
373{
374 if (size == 0) {
375 pr_debug("%s doesn't need map definition\n",
376 obj->path);
377 return 0;
378 }
379
380 obj->maps_buf = malloc(size);
381 if (!obj->maps_buf) {
382 pr_warning("malloc maps failed: %s\n", obj->path);
383 return -ENOMEM;
384 }
385
386 obj->maps_buf_sz = size;
387 memcpy(obj->maps_buf, data, size);
388 pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size);
389 return 0;
390}
391
29603665
WN
392static int bpf_object__elf_collect(struct bpf_object *obj)
393{
394 Elf *elf = obj->efile.elf;
395 GElf_Ehdr *ep = &obj->efile.ehdr;
396 Elf_Scn *scn = NULL;
397 int idx = 0, err = 0;
398
399 /* Elf is corrupted/truncated, avoid calling elf_strptr. */
400 if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
401 pr_warning("failed to get e_shstrndx from %s\n",
402 obj->path);
403 return -EINVAL;
404 }
405
406 while ((scn = elf_nextscn(elf, scn)) != NULL) {
407 char *name;
408 GElf_Shdr sh;
409 Elf_Data *data;
410
411 idx++;
412 if (gelf_getshdr(scn, &sh) != &sh) {
413 pr_warning("failed to get section header from %s\n",
414 obj->path);
415 err = -EINVAL;
416 goto out;
417 }
418
419 name = elf_strptr(elf, ep->e_shstrndx, sh.sh_name);
420 if (!name) {
421 pr_warning("failed to get section name from %s\n",
422 obj->path);
423 err = -EINVAL;
424 goto out;
425 }
426
427 data = elf_getdata(scn, 0);
428 if (!data) {
429 pr_warning("failed to get section data from %s(%s)\n",
430 name, obj->path);
431 err = -EINVAL;
432 goto out;
433 }
434 pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n",
435 name, (unsigned long)data->d_size,
436 (int)sh.sh_link, (unsigned long)sh.sh_flags,
437 (int)sh.sh_type);
cb1e5e96
WN
438
439 if (strcmp(name, "license") == 0)
440 err = bpf_object__init_license(obj,
441 data->d_buf,
442 data->d_size);
443 else if (strcmp(name, "version") == 0)
444 err = bpf_object__init_kversion(obj,
445 data->d_buf,
446 data->d_size);
0b3d1efa
WN
447 else if (strcmp(name, "maps") == 0)
448 err = bpf_object__init_maps(obj, data->d_buf,
449 data->d_size);
bec7d68c
WN
450 else if (sh.sh_type == SHT_SYMTAB) {
451 if (obj->efile.symbols) {
452 pr_warning("bpf: multiple SYMTAB in %s\n",
453 obj->path);
454 err = -EEXIST;
455 } else
456 obj->efile.symbols = data;
a5b8bd47
WN
457 } else if ((sh.sh_type == SHT_PROGBITS) &&
458 (sh.sh_flags & SHF_EXECINSTR) &&
459 (data->d_size > 0)) {
460 err = bpf_object__add_program(obj, data->d_buf,
461 data->d_size, name, idx);
462 if (err) {
463 char errmsg[128];
464 strerror_r(-err, errmsg, sizeof(errmsg));
465 pr_warning("failed to alloc program %s (%s): %s",
466 name, obj->path, errmsg);
467 }
b62f06e8
WN
468 } else if (sh.sh_type == SHT_REL) {
469 void *reloc = obj->efile.reloc;
470 int nr_reloc = obj->efile.nr_reloc + 1;
471
472 reloc = realloc(reloc,
473 sizeof(*obj->efile.reloc) * nr_reloc);
474 if (!reloc) {
475 pr_warning("realloc failed\n");
476 err = -ENOMEM;
477 } else {
478 int n = nr_reloc - 1;
479
480 obj->efile.reloc = reloc;
481 obj->efile.nr_reloc = nr_reloc;
482
483 obj->efile.reloc[n].shdr = sh;
484 obj->efile.reloc[n].data = data;
485 }
bec7d68c 486 }
cb1e5e96
WN
487 if (err)
488 goto out;
29603665
WN
489 }
490out:
491 return err;
492}
493
34090915
WN
494static struct bpf_program *
495bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx)
496{
497 struct bpf_program *prog;
498 size_t i;
499
500 for (i = 0; i < obj->nr_programs; i++) {
501 prog = &obj->programs[i];
502 if (prog->idx == idx)
503 return prog;
504 }
505 return NULL;
506}
507
508static int
509bpf_program__collect_reloc(struct bpf_program *prog,
510 size_t nr_maps, GElf_Shdr *shdr,
511 Elf_Data *data, Elf_Data *symbols)
512{
513 int i, nrels;
514
515 pr_debug("collecting relocating info for: '%s'\n",
516 prog->section_name);
517 nrels = shdr->sh_size / shdr->sh_entsize;
518
519 prog->reloc_desc = malloc(sizeof(*prog->reloc_desc) * nrels);
520 if (!prog->reloc_desc) {
521 pr_warning("failed to alloc memory in relocation\n");
522 return -ENOMEM;
523 }
524 prog->nr_reloc = nrels;
525
526 for (i = 0; i < nrels; i++) {
527 GElf_Sym sym;
528 GElf_Rel rel;
529 unsigned int insn_idx;
530 struct bpf_insn *insns = prog->insns;
531 size_t map_idx;
532
533 if (!gelf_getrel(data, i, &rel)) {
534 pr_warning("relocation: failed to get %d reloc\n", i);
535 return -EINVAL;
536 }
537
538 insn_idx = rel.r_offset / sizeof(struct bpf_insn);
539 pr_debug("relocation: insn_idx=%u\n", insn_idx);
540
541 if (!gelf_getsym(symbols,
542 GELF_R_SYM(rel.r_info),
543 &sym)) {
544 pr_warning("relocation: symbol %"PRIx64" not found\n",
545 GELF_R_SYM(rel.r_info));
546 return -EINVAL;
547 }
548
549 if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
550 pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
551 insn_idx, insns[insn_idx].code);
552 return -EINVAL;
553 }
554
555 map_idx = sym.st_value / sizeof(struct bpf_map_def);
556 if (map_idx >= nr_maps) {
557 pr_warning("bpf relocation: map_idx %d large than %d\n",
558 (int)map_idx, (int)nr_maps - 1);
559 return -EINVAL;
560 }
561
562 prog->reloc_desc[i].insn_idx = insn_idx;
563 prog->reloc_desc[i].map_idx = map_idx;
564 }
565 return 0;
566}
567
568static int bpf_object__collect_reloc(struct bpf_object *obj)
569{
570 int i, err;
571
572 if (!obj_elf_valid(obj)) {
573 pr_warning("Internal error: elf object is closed\n");
574 return -EINVAL;
575 }
576
577 for (i = 0; i < obj->efile.nr_reloc; i++) {
578 GElf_Shdr *shdr = &obj->efile.reloc[i].shdr;
579 Elf_Data *data = obj->efile.reloc[i].data;
580 int idx = shdr->sh_info;
581 struct bpf_program *prog;
582 size_t nr_maps = obj->maps_buf_sz /
583 sizeof(struct bpf_map_def);
584
585 if (shdr->sh_type != SHT_REL) {
586 pr_warning("internal error at %d\n", __LINE__);
587 return -EINVAL;
588 }
589
590 prog = bpf_object__find_prog_by_idx(obj, idx);
591 if (!prog) {
592 pr_warning("relocation failed: no %d section\n",
593 idx);
594 return -ENOENT;
595 }
596
597 err = bpf_program__collect_reloc(prog, nr_maps,
598 shdr, data,
599 obj->efile.symbols);
600 if (err)
601 return -EINVAL;
602 }
603 return 0;
604}
605
cb1e5e96
WN
606static int bpf_object__validate(struct bpf_object *obj)
607{
608 if (obj->kern_version == 0) {
609 pr_warning("%s doesn't provide kernel version\n",
610 obj->path);
611 return -EINVAL;
612 }
613 return 0;
614}
615
1a5e3fb1 616static struct bpf_object *
6c956392 617__bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)
1a5e3fb1
WN
618{
619 struct bpf_object *obj;
620
621 if (elf_version(EV_CURRENT) == EV_NONE) {
622 pr_warning("failed to init libelf for %s\n", path);
623 return NULL;
624 }
625
6c956392 626 obj = bpf_object__new(path, obj_buf, obj_buf_sz);
1a5e3fb1
WN
627 if (!obj)
628 return NULL;
629
630 if (bpf_object__elf_init(obj))
631 goto out;
cc4228d5
WN
632 if (bpf_object__check_endianness(obj))
633 goto out;
29603665
WN
634 if (bpf_object__elf_collect(obj))
635 goto out;
34090915
WN
636 if (bpf_object__collect_reloc(obj))
637 goto out;
cb1e5e96
WN
638 if (bpf_object__validate(obj))
639 goto out;
1a5e3fb1
WN
640
641 bpf_object__elf_finish(obj);
642 return obj;
643out:
644 bpf_object__close(obj);
645 return NULL;
646}
647
648struct bpf_object *bpf_object__open(const char *path)
649{
650 /* param validation */
651 if (!path)
652 return NULL;
653
654 pr_debug("loading %s\n", path);
655
6c956392
WN
656 return __bpf_object__open(path, NULL, 0);
657}
658
659struct bpf_object *bpf_object__open_buffer(void *obj_buf,
660 size_t obj_buf_sz)
661{
662 /* param validation */
663 if (!obj_buf || obj_buf_sz <= 0)
664 return NULL;
665
666 pr_debug("loading object from buffer\n");
667
668 return __bpf_object__open("[buffer]", obj_buf, obj_buf_sz);
1a5e3fb1
WN
669}
670
671void bpf_object__close(struct bpf_object *obj)
672{
a5b8bd47
WN
673 size_t i;
674
1a5e3fb1
WN
675 if (!obj)
676 return;
677
678 bpf_object__elf_finish(obj);
679
0b3d1efa 680 zfree(&obj->maps_buf);
a5b8bd47
WN
681
682 if (obj->programs && obj->nr_programs) {
683 for (i = 0; i < obj->nr_programs; i++)
684 bpf_program__exit(&obj->programs[i]);
685 }
686 zfree(&obj->programs);
687
1a5e3fb1
WN
688 free(obj);
689}
This page took 0.095716 seconds and 5 git commands to generate.