Skip to content

Commit 44ad23d

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
libbpf: Handle BTF pointer sizes more carefully
With libbpf and BTF it is pretty common to have libbpf built for one architecture, while BTF information was generated for a different architecture (typically, but not always, BPF). In such case, the size of a pointer might differ betweem architectures. libbpf previously was always making an assumption that pointer size for BTF is the same as native architecture pointer size, but that breaks for cases where libbpf is built as 32-bit library, while BTF is for 64-bit architecture. To solve this, add heuristic to determine pointer size by searching for `long` or `unsigned long` integer type and using its size as a pointer size. Also, allow to override the pointer size with a new API btf__set_pointer_size(), for cases where application knows which pointer size should be used. User application can check what libbpf "guessed" by looking at the result of btf__pointer_size(). If it's not 0, then libbpf successfully determined a pointer size, otherwise native arch pointer size will be used. For cases where BTF is parsed from ELF file, use ELF's class (32-bit or 64-bit) to determine pointer size. Fixes: 8a138ae ("bpf: btf: Add BTF support to libbpf") Fixes: 351131b ("libbpf: add btf_dump API for BTF-to-C conversion") Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 15728ad commit 44ad23d

File tree

4 files changed

+87
-4
lines changed

4 files changed

+87
-4
lines changed

tools/lib/bpf/btf.c

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ struct btf {
4141
__u32 types_size;
4242
__u32 data_size;
4343
int fd;
44+
int ptr_sz;
4445
};
4546

4647
static inline __u64 ptr_to_u64(const void *ptr)
@@ -221,6 +222,70 @@ const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
221222
return btf->types[type_id];
222223
}
223224

225+
static int determine_ptr_size(const struct btf *btf)
226+
{
227+
const struct btf_type *t;
228+
const char *name;
229+
int i;
230+
231+
for (i = 1; i <= btf->nr_types; i++) {
232+
t = btf__type_by_id(btf, i);
233+
if (!btf_is_int(t))
234+
continue;
235+
236+
name = btf__name_by_offset(btf, t->name_off);
237+
if (!name)
238+
continue;
239+
240+
if (strcmp(name, "long int") == 0 ||
241+
strcmp(name, "long unsigned int") == 0) {
242+
if (t->size != 4 && t->size != 8)
243+
continue;
244+
return t->size;
245+
}
246+
}
247+
248+
return -1;
249+
}
250+
251+
static size_t btf_ptr_sz(const struct btf *btf)
252+
{
253+
if (!btf->ptr_sz)
254+
((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
255+
return btf->ptr_sz < 0 ? sizeof(void *) : btf->ptr_sz;
256+
}
257+
258+
/* Return pointer size this BTF instance assumes. The size is heuristically
259+
* determined by looking for 'long' or 'unsigned long' integer type and
260+
* recording its size in bytes. If BTF type information doesn't have any such
261+
* type, this function returns 0. In the latter case, native architecture's
262+
* pointer size is assumed, so will be either 4 or 8, depending on
263+
* architecture that libbpf was compiled for. It's possible to override
264+
* guessed value by using btf__set_pointer_size() API.
265+
*/
266+
size_t btf__pointer_size(const struct btf *btf)
267+
{
268+
if (!btf->ptr_sz)
269+
((struct btf *)btf)->ptr_sz = determine_ptr_size(btf);
270+
271+
if (btf->ptr_sz < 0)
272+
/* not enough BTF type info to guess */
273+
return 0;
274+
275+
return btf->ptr_sz;
276+
}
277+
278+
/* Override or set pointer size in bytes. Only values of 4 and 8 are
279+
* supported.
280+
*/
281+
int btf__set_pointer_size(struct btf *btf, size_t ptr_sz)
282+
{
283+
if (ptr_sz != 4 && ptr_sz != 8)
284+
return -EINVAL;
285+
btf->ptr_sz = ptr_sz;
286+
return 0;
287+
}
288+
224289
static bool btf_type_is_void(const struct btf_type *t)
225290
{
226291
return t == &btf_void || btf_is_fwd(t);
@@ -253,7 +318,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
253318
size = t->size;
254319
goto done;
255320
case BTF_KIND_PTR:
256-
size = sizeof(void *);
321+
size = btf_ptr_sz(btf);
257322
goto done;
258323
case BTF_KIND_TYPEDEF:
259324
case BTF_KIND_VOLATILE:
@@ -293,9 +358,9 @@ int btf__align_of(const struct btf *btf, __u32 id)
293358
switch (kind) {
294359
case BTF_KIND_INT:
295360
case BTF_KIND_ENUM:
296-
return min(sizeof(void *), (size_t)t->size);
361+
return min(btf_ptr_sz(btf), (size_t)t->size);
297362
case BTF_KIND_PTR:
298-
return sizeof(void *);
363+
return btf_ptr_sz(btf);
299364
case BTF_KIND_TYPEDEF:
300365
case BTF_KIND_VOLATILE:
301366
case BTF_KIND_CONST:
@@ -533,6 +598,18 @@ struct btf *btf__parse_elf(const char *path, struct btf_ext **btf_ext)
533598
if (IS_ERR(btf))
534599
goto done;
535600

601+
switch (gelf_getclass(elf)) {
602+
case ELFCLASS32:
603+
btf__set_pointer_size(btf, 4);
604+
break;
605+
case ELFCLASS64:
606+
btf__set_pointer_size(btf, 8);
607+
break;
608+
default:
609+
pr_warn("failed to get ELF class (bitness) for %s\n", path);
610+
break;
611+
}
612+
536613
if (btf_ext && btf_ext_data) {
537614
*btf_ext = btf_ext__new(btf_ext_data->d_buf,
538615
btf_ext_data->d_size);

tools/lib/bpf/btf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ LIBBPF_API __s32 btf__find_by_name_kind(const struct btf *btf,
7676
LIBBPF_API __u32 btf__get_nr_types(const struct btf *btf);
7777
LIBBPF_API const struct btf_type *btf__type_by_id(const struct btf *btf,
7878
__u32 id);
79+
LIBBPF_API size_t btf__pointer_size(const struct btf *btf);
80+
LIBBPF_API int btf__set_pointer_size(struct btf *btf, size_t ptr_sz);
7981
LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
8082
LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
8183
LIBBPF_API int btf__align_of(const struct btf *btf, __u32 id);

tools/lib/bpf/btf_dump.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct btf_dump {
6161
const struct btf_ext *btf_ext;
6262
btf_dump_printf_fn_t printf_fn;
6363
struct btf_dump_opts opts;
64+
int ptr_sz;
6465
bool strip_mods;
6566

6667
/* per-type auxiliary state */
@@ -139,6 +140,7 @@ struct btf_dump *btf_dump__new(const struct btf *btf,
139140
d->btf_ext = btf_ext;
140141
d->printf_fn = printf_fn;
141142
d->opts.ctx = opts ? opts->ctx : NULL;
143+
d->ptr_sz = btf__pointer_size(btf) ? : sizeof(void *);
142144

143145
d->type_names = hashmap__new(str_hash_fn, str_equal_fn, NULL);
144146
if (IS_ERR(d->type_names)) {
@@ -804,7 +806,7 @@ static void btf_dump_emit_bit_padding(const struct btf_dump *d,
804806
int align, int lvl)
805807
{
806808
int off_diff = m_off - cur_off;
807-
int ptr_bits = sizeof(void *) * 8;
809+
int ptr_bits = d->ptr_sz * 8;
808810

809811
if (off_diff <= 0)
810812
/* no gap */

tools/lib/bpf/libbpf.map

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,5 +295,7 @@ LIBBPF_0.1.0 {
295295
bpf_program__set_sk_lookup;
296296
btf__parse;
297297
btf__parse_raw;
298+
btf__pointer_size;
298299
btf__set_fd;
300+
btf__set_pointer_size;
299301
} LIBBPF_0.0.9;

0 commit comments

Comments
 (0)