Commit | Line | Data |
---|---|---|
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) | |
26 | static 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 | ||
37 | static __printf(1, 2) libbpf_print_fn_t __pr_warning = __base_pr; | |
38 | static __printf(1, 2) libbpf_print_fn_t __pr_info = __base_pr; | |
39 | static __printf(1, 2) libbpf_print_fn_t __pr_debug; | |
40 | ||
41 | #define __pr(func, fmt, ...) \ | |
42 | do { \ | |
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 | ||
51 | void 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 | ||
80 | struct 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 | ||
94 | static 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 | ||
109 | static 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 | ||
121 | static 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; | |
164 | errout: | |
165 | bpf_object__elf_finish(obj); | |
166 | return err; | |
167 | } | |
168 | ||
169 | static 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; | |
188 | out: | |
189 | bpf_object__close(obj); | |
190 | return NULL; | |
191 | } | |
192 | ||
193 | struct 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 | ||
204 | void 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 | } |