LCOV - code coverage report
Current view: top level - libbpfilter - btf.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 55.7 % 79 44
Test Date: 2025-09-30 16:37:25 Functions: 62.5 % 8 5

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-only
       2              : /*
       3              :  * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "bpfilter/btf.h"
       7              : 
       8              : #include <linux/btf.h>
       9              : 
      10              : #include <bpf/btf.h>
      11              : #include <errno.h>
      12              : #include <limits.h>
      13              : #include <stddef.h>
      14              : #include <stdlib.h>
      15              : 
      16              : #include "bpfilter/helper.h"
      17              : #include "bpfilter/logger.h"
      18              : 
      19              : static struct btf *_bf_btf = NULL;
      20              : 
      21            3 : int bf_btf_setup(void)
      22              : {
      23            3 :     _bf_btf = btf__load_vmlinux_btf();
      24            3 :     if (!_bf_btf)
      25            1 :         return bf_err_r(errno, "failed to load vmlinux BTF");
      26              : 
      27              :     return 0;
      28              : }
      29              : 
      30            2 : void bf_btf_teardown(void)
      31              : {
      32            2 :     btf__free(_bf_btf);
      33            2 :     _bf_btf = NULL;
      34            2 : }
      35              : 
      36            0 : int bf_btf_get_id(const char *name)
      37              : {
      38              :     int id;
      39              : 
      40            0 :     bf_assert(name);
      41              : 
      42            0 :     id = btf__find_by_name(_bf_btf, name);
      43            0 :     if (id < 0)
      44            0 :         return bf_err_r(errno, "failed to find BTF type for \"%s\"", name);
      45              : 
      46              :     return id;
      47              : }
      48              : 
      49            0 : const char *bf_btf_get_name(int id)
      50              : {
      51              :     const struct btf_type *type;
      52              : 
      53            0 :     type = btf__type_by_id(_bf_btf, id);
      54            0 :     if (!type) {
      55            0 :         bf_warn("can't find BTF type ID %d", id);
      56            0 :         return NULL;
      57              :     }
      58              : 
      59            0 :     return btf__name_by_offset(_bf_btf, type->name_off);
      60              : }
      61              : 
      62            0 : int bf_btf_kernel_has_token(void)
      63              : {
      64              :     int bpf_attr_id;
      65              :     const struct btf_type *bpf_attr_type;
      66              :     const struct btf_member *bpf_attr_members;
      67              : 
      68            0 :     bpf_attr_id = btf__find_by_name_kind(_bf_btf, "bpf_attr", BTF_KIND_UNION);
      69            0 :     if (bpf_attr_id < 0) {
      70            0 :         return bf_err_r(bpf_attr_id,
      71              :                         "can't find structure 'bpf_attr' in kernel BTF");
      72              :     }
      73              : 
      74            0 :     bpf_attr_type = btf__type_by_id(_bf_btf, bpf_attr_id);
      75            0 :     if (!bpf_attr_type)
      76            0 :         return bf_err_r(-EINVAL, "failed to request 'bpf_attr' BTF type");
      77              : 
      78              :     bpf_attr_members = btf_members(bpf_attr_type);
      79              :     // Iterate through union members
      80            0 :     for (unsigned short i = 0; i < btf_vlen(bpf_attr_type); i++) {
      81              :         const struct btf_type *member_type =
      82            0 :             btf__type_by_id(_bf_btf, bpf_attr_members[i].type);
      83              :         const struct btf_member *m_members = btf_members(member_type);
      84              : 
      85              :         // We are looking for an anonymous structure
      86            0 :         if (!btf_is_struct(member_type) || bpf_attr_members[i].name_off != 0)
      87            0 :             continue;
      88              : 
      89            0 :         for (int j = 0; j < btf_vlen(member_type); j++) {
      90              :             const char *member_name =
      91            0 :                 btf__name_by_offset(_bf_btf, m_members[j].name_off);
      92              : 
      93            0 :             if (member_name && bf_streq(member_name, "prog_token_fd"))
      94              :                 return 0;
      95              :         }
      96              :     }
      97              : 
      98              :     return -ENOENT;
      99              : }
     100              : 
     101              : #define _bf_btf_type_is_compound(type)                                         \
     102              :     (BTF_INFO_KIND((type)->info) == BTF_KIND_UNION ||                          \
     103              :      BTF_INFO_KIND((type)->info) == BTF_KIND_STRUCT)
     104              : 
     105              : /**
     106              :  * @brief Find the offset of `field_name` in BTF type ID `compound_id`.
     107              :  *
     108              :  * @param compound_id Compound BTF type id.
     109              :  * @param field_name Name of the field to find the offset of. Can't be NULL.
     110              :  * @return Offset (in bits) of `field_name` in `compound_id` BTF type.
     111              :  */
     112            6 : static ssize_t _bf_btf_offset_in_compound(uint32_t compound_id,
     113              :                                           const char *field_name)
     114              : {
     115              :     ssize_t offset;
     116              :     const struct btf_type *compound_type, *member_type;
     117              :     const struct btf_member *member;
     118              : 
     119            6 :     bf_assert(field_name);
     120              : 
     121            6 :     compound_type = btf__type_by_id(_bf_btf, compound_id);
     122            6 :     if (!compound_type)
     123            0 :         return -errno;
     124              : 
     125            6 :     if (!_bf_btf_type_is_compound(compound_type))
     126              :         return -ENOTSUP;
     127              : 
     128            6 :     member = (const struct btf_member *)(compound_type + 1);
     129           28 :     for (size_t i = 0; i < BTF_INFO_VLEN(compound_type->info); ++i, ++member) {
     130           25 :         const char *name = btf__name_by_offset(_bf_btf, member->name_off);
     131              : 
     132           25 :         member_type = btf__type_by_id(_bf_btf, member->type);
     133           25 :         if (!member_type)
     134            0 :             return -errno;
     135              : 
     136              :         // Member is an anonymous compound type? Check its members
     137           25 :         if (*name == '\0' && _bf_btf_type_is_compound(member_type)) {
     138            2 :             offset = _bf_btf_offset_in_compound(member->type, field_name);
     139            2 :             if (offset < 0)
     140            2 :                 continue;
     141              : 
     142            0 :             if (BTF_MEMBER_BIT_OFFSET(member->offset) % 8) {
     143              :                 // Assuming this is not possible, but who knows
     144            0 :                 return bf_err_r(-ENOTSUP,
     145              :                                 "anonymous compound parent is a bitfield");
     146              :             }
     147              : 
     148            0 :             if (BTF_INFO_KFLAG(compound_type->info))
     149            0 :                 offset += BTF_MEMBER_BIT_OFFSET(member->offset);
     150              :             else
     151            0 :                 offset += member->offset;
     152              : 
     153            0 :             return offset;
     154              :         }
     155              : 
     156           23 :         if (!bf_streq(name, field_name))
     157           20 :             continue;
     158              : 
     159            3 :         offset = (ssize_t)member->offset;
     160            3 :         if (BTF_INFO_KFLAG(compound_type->info))
     161            2 :             offset = BTF_MEMBER_BIT_OFFSET(member->offset);
     162              : 
     163              :         return offset;
     164              :     }
     165              : 
     166              :     return -EINVAL;
     167              : }
     168              : 
     169            6 : static int _bf_btf_get_compound_type_id(const char *name)
     170              : {
     171              :     int compound_id;
     172              : 
     173            6 :     compound_id = btf__find_by_name_kind(_bf_btf, name, BTF_KIND_STRUCT);
     174            6 :     if (compound_id < 0 && compound_id != -ENOENT)
     175              :         return compound_id;
     176            6 :     if (compound_id >= 0)
     177              :         return compound_id;
     178              : 
     179            2 :     compound_id = btf__find_by_name_kind(_bf_btf, name, BTF_KIND_UNION);
     180              :     if (compound_id < 0 && compound_id != -ENOENT)
     181              :         return compound_id;
     182              : 
     183              :     return compound_id;
     184              : }
     185              : 
     186            6 : int bf_btf_get_field_off(const char *struct_name, const char *field_name)
     187              : {
     188              :     int id;
     189              :     ssize_t offset;
     190              : 
     191            6 :     bf_assert(struct_name);
     192            6 :     bf_assert(field_name);
     193              : 
     194            6 :     id = _bf_btf_get_compound_type_id(struct_name);
     195            6 :     if (id < 0)
     196            2 :         return bf_err_r(id, "failed to find BTF type ID for '%s'", struct_name);
     197              : 
     198            4 :     offset = _bf_btf_offset_in_compound(id, field_name);
     199            4 :     if (offset < 0) {
     200            1 :         return bf_err_r((int)offset, "failed to find offset of %s.%s",
     201              :                         struct_name, field_name);
     202              :     }
     203            3 :     if (offset % 8) {
     204            0 :         return bf_err_r(-EINVAL, "%s.%s has a bit offset", struct_name,
     205              :                         field_name);
     206              :     }
     207            3 :     if (offset / 8 > INT_MAX) {
     208            0 :         return bf_err_r(-E2BIG, "%s.%s has an offset bigger than %d",
     209              :                         struct_name, field_name, INT_MAX);
     210              :     }
     211              : 
     212            3 :     return (int)(offset / 8);
     213              : }
        

Generated by: LCOV version 2.0-1