bpf tools: Open eBPF object file and do basic validation
[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>
12#include <string.h>
1b76c13e 13#include <unistd.h>
1a5e3fb1
WN
14#include <fcntl.h>
15#include <errno.h>
1b76c13e
WN
16#include <asm/unistd.h>
17#include <linux/bpf.h>
1a5e3fb1
WN
18#include <libelf.h>
19#include <gelf.h>
1b76c13e
WN
20
21#include "libbpf.h"
b3f59d66
WN
22
23#define __printf(a, b) __attribute__((format(printf, a, b)))
24
25__printf(1, 2)
26static int __base_pr(const char *format, ...)
27{
28 va_list args;
29 int err;
30
31 va_start(args, format);
32 err = vfprintf(stderr, format, args);
33 va_end(args);
34 return err;
35}
36
37static __printf(1, 2) libbpf_print_fn_t __pr_warning = __base_pr;
38static __printf(1, 2) libbpf_print_fn_t __pr_info = __base_pr;
39static __printf(1, 2) libbpf_print_fn_t __pr_debug;
40
41#define __pr(func, fmt, ...) \
42do { \
43 if ((func)) \
44 (func)("libbpf: " fmt, ##__VA_ARGS__); \
45} while (0)
46
47#define pr_warning(fmt, ...) __pr(__pr_warning, fmt, ##__VA_ARGS__)
48#define pr_info(fmt, ...) __pr(__pr_info, fmt, ##__VA_ARGS__)
49#define pr_debug(fmt, ...) __pr(__pr_debug, fmt, ##__VA_ARGS__)
50
51void libbpf_set_print(libbpf_print_fn_t warn,
52 libbpf_print_fn_t info,
53 libbpf_print_fn_t debug)
54{
55 __pr_warning = warn;
56 __pr_info = info;
57 __pr_debug = debug;
58}
1a5e3fb1
WN
59
60/* Copied from tools/perf/util/util.h */
61#ifndef zfree
62# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
63#endif
64
65#ifndef zclose
66# define zclose(fd) ({ \
67 int ___err = 0; \
68 if ((fd) >= 0) \
69 ___err = close((fd)); \
70 fd = -1; \
71 ___err; })
72#endif
73
74#ifdef HAVE_LIBELF_MMAP_SUPPORT
75# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ_MMAP
76#else
77# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
78#endif
79
80struct bpf_object {
81 /*
82 * Information when doing elf related work. Only valid if fd
83 * is valid.
84 */
85 struct {
86 int fd;
87 Elf *elf;
88 GElf_Ehdr ehdr;
89 } efile;
90 char path[];
91};
92#define obj_elf_valid(o) ((o)->efile.elf)
93
94static struct bpf_object *bpf_object__new(const char *path)
95{
96 struct bpf_object *obj;
97
98 obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1);
99 if (!obj) {
100 pr_warning("alloc memory failed for %s\n", path);
101 return NULL;
102 }
103
104 strcpy(obj->path, path);
105 obj->efile.fd = -1;
106 return obj;
107}
108
109static void bpf_object__elf_finish(struct bpf_object *obj)
110{
111 if (!obj_elf_valid(obj))
112 return;
113
114 if (obj->efile.elf) {
115 elf_end(obj->efile.elf);
116 obj->efile.elf = NULL;
117 }
118 zclose(obj->efile.fd);
119}
120
121static int bpf_object__elf_init(struct bpf_object *obj)
122{
123 int err = 0;
124 GElf_Ehdr *ep;
125
126 if (obj_elf_valid(obj)) {
127 pr_warning("elf init: internal error\n");
128 return -EEXIST;
129 }
130
131 obj->efile.fd = open(obj->path, O_RDONLY);
132 if (obj->efile.fd < 0) {
133 pr_warning("failed to open %s: %s\n", obj->path,
134 strerror(errno));
135 return -errno;
136 }
137
138 obj->efile.elf = elf_begin(obj->efile.fd,
139 LIBBPF_ELF_C_READ_MMAP,
140 NULL);
141 if (!obj->efile.elf) {
142 pr_warning("failed to open %s as ELF file\n",
143 obj->path);
144 err = -EINVAL;
145 goto errout;
146 }
147
148 if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) {
149 pr_warning("failed to get EHDR from %s\n",
150 obj->path);
151 err = -EINVAL;
152 goto errout;
153 }
154 ep = &obj->efile.ehdr;
155
156 if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) {
157 pr_warning("%s is not an eBPF object file\n",
158 obj->path);
159 err = -EINVAL;
160 goto errout;
161 }
162
163 return 0;
164errout:
165 bpf_object__elf_finish(obj);
166 return err;
167}
168
169static struct bpf_object *
170__bpf_object__open(const char *path)
171{
172 struct bpf_object *obj;
173
174 if (elf_version(EV_CURRENT) == EV_NONE) {
175 pr_warning("failed to init libelf for %s\n", path);
176 return NULL;
177 }
178
179 obj = bpf_object__new(path);
180 if (!obj)
181 return NULL;
182
183 if (bpf_object__elf_init(obj))
184 goto out;
185
186 bpf_object__elf_finish(obj);
187 return obj;
188out:
189 bpf_object__close(obj);
190 return NULL;
191}
192
193struct bpf_object *bpf_object__open(const char *path)
194{
195 /* param validation */
196 if (!path)
197 return NULL;
198
199 pr_debug("loading %s\n", path);
200
201 return __bpf_object__open(path);
202}
203
204void bpf_object__close(struct bpf_object *obj)
205{
206 if (!obj)
207 return;
208
209 bpf_object__elf_finish(obj);
210
211 free(obj);
212}
This page took 0.03339 seconds and 5 git commands to generate.