LCOV - code coverage report
Current view: top level - lib/bpf - bpf_load_elf.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 107 0.0 %
Date: 2025-05-01 17:49:45 Functions: 0 8 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 86 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2018 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <stdarg.h>
       6                 :            : #include <stdio.h>
       7                 :            : #include <string.h>
       8                 :            : #include <errno.h>
       9                 :            : #include <stdint.h>
      10                 :            : #include <unistd.h>
      11                 :            : #include <inttypes.h>
      12                 :            : 
      13                 :            : #include <sys/types.h>
      14                 :            : #include <sys/stat.h>
      15                 :            : #include <sys/queue.h>
      16                 :            : #include <fcntl.h>
      17                 :            : 
      18                 :            : #include <libelf.h>
      19                 :            : 
      20                 :            : #include <eal_export.h>
      21                 :            : #include <rte_common.h>
      22                 :            : #include <rte_log.h>
      23                 :            : #include <rte_debug.h>
      24                 :            : #include <rte_memory.h>
      25                 :            : #include <rte_eal.h>
      26                 :            : #include <rte_byteorder.h>
      27                 :            : #include <rte_errno.h>
      28                 :            : 
      29                 :            : #include "bpf_impl.h"
      30                 :            : 
      31                 :            : /* To overcome compatibility issue */
      32                 :            : #ifndef EM_BPF
      33                 :            : #define EM_BPF  247
      34                 :            : #endif
      35                 :            : 
      36                 :            : static uint32_t
      37                 :          0 : bpf_find_xsym(const char *sn, enum rte_bpf_xtype type,
      38                 :            :         const struct rte_bpf_xsym fp[], uint32_t fn)
      39                 :            : {
      40                 :            :         uint32_t i;
      41                 :            : 
      42         [ #  # ]:          0 :         if (sn == NULL || fp == NULL)
      43                 :            :                 return UINT32_MAX;
      44                 :            : 
      45         [ #  # ]:          0 :         for (i = 0; i != fn; i++) {
      46   [ #  #  #  # ]:          0 :                 if (fp[i].type == type && strcmp(sn, fp[i].name) == 0)
      47                 :            :                         break;
      48                 :            :         }
      49                 :            : 
      50         [ #  # ]:          0 :         return (i != fn) ? i : UINT32_MAX;
      51                 :            : }
      52                 :            : 
      53                 :            : /*
      54                 :            :  * update BPF code at offset *ofs* with a proper address(index) for external
      55                 :            :  * symbol *sn*
      56                 :            :  */
      57                 :            : static int
      58                 :          0 : resolve_xsym(const char *sn, size_t ofs, struct ebpf_insn *ins, size_t ins_sz,
      59                 :            :         const struct rte_bpf_prm *prm)
      60                 :            : {
      61                 :            :         uint32_t idx, fidx;
      62                 :            :         enum rte_bpf_xtype type;
      63                 :            : 
      64   [ #  #  #  # ]:          0 :         if (ofs % sizeof(ins[0]) != 0 || ofs >= ins_sz)
      65                 :            :                 return -EINVAL;
      66                 :            : 
      67                 :          0 :         idx = ofs / sizeof(ins[0]);
      68         [ #  # ]:          0 :         if (ins[idx].code == (BPF_JMP | EBPF_CALL))
      69                 :            :                 type = RTE_BPF_XTYPE_FUNC;
      70         [ #  # ]:          0 :         else if (ins[idx].code == (BPF_LD | BPF_IMM | EBPF_DW) &&
      71         [ #  # ]:          0 :                         ofs < ins_sz - sizeof(ins[idx]))
      72                 :            :                 type = RTE_BPF_XTYPE_VAR;
      73                 :            :         else
      74                 :            :                 return -EINVAL;
      75                 :            : 
      76                 :          0 :         fidx = bpf_find_xsym(sn, type, prm->xsym, prm->nb_xsym);
      77         [ #  # ]:          0 :         if (fidx == UINT32_MAX)
      78                 :            :                 return -ENOENT;
      79                 :            : 
      80                 :            :         /* for function we just need an index in our xsym table */
      81         [ #  # ]:          0 :         if (type == RTE_BPF_XTYPE_FUNC) {
      82                 :            : 
      83                 :            :                 /* we don't support multiple functions per BPF module,
      84                 :            :                  * so treat EBPF_PSEUDO_CALL to external function
      85                 :            :                  * as an ordinary EBPF_CALL.
      86                 :            :                  */
      87         [ #  # ]:          0 :                 if (ins[idx].src_reg == EBPF_PSEUDO_CALL) {
      88                 :          0 :                         RTE_BPF_LOG_LINE(INFO, "%s(%u): "
      89                 :            :                                 "EBPF_PSEUDO_CALL to external function: %s",
      90                 :            :                                 __func__, idx, sn);
      91                 :          0 :                         ins[idx].src_reg = EBPF_REG_0;
      92                 :            :                 }
      93                 :          0 :                 ins[idx].imm = fidx;
      94                 :            :         /* for variable we need to store its absolute address */
      95                 :            :         } else {
      96                 :          0 :                 ins[idx].imm = (uintptr_t)prm->xsym[fidx].var.val;
      97                 :          0 :                 ins[idx + 1].imm =
      98                 :          0 :                         (uint64_t)(uintptr_t)prm->xsym[fidx].var.val >> 32;
      99                 :            :         }
     100                 :            : 
     101                 :            :         return 0;
     102                 :            : }
     103                 :            : 
     104                 :            : static int
     105                 :          0 : check_elf_header(const Elf64_Ehdr *eh)
     106                 :            : {
     107                 :            :         const char *err;
     108                 :            : 
     109                 :            :         err = NULL;
     110                 :            : 
     111                 :            : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
     112         [ #  # ]:          0 :         if (eh->e_ident[EI_DATA] != ELFDATA2LSB)
     113                 :            : #else
     114                 :            :         if (eh->e_ident[EI_DATA] != ELFDATA2MSB)
     115                 :            : #endif
     116                 :            :                 err = "not native byte order";
     117         [ #  # ]:          0 :         else if (eh->e_ident[EI_OSABI] != ELFOSABI_NONE)
     118                 :            :                 err = "unexpected OS ABI";
     119         [ #  # ]:          0 :         else if (eh->e_type != ET_REL)
     120                 :            :                 err = "unexpected ELF type";
     121         [ #  # ]:          0 :         else if (eh->e_machine != EM_NONE && eh->e_machine != EM_BPF)
     122                 :            :                 err = "unexpected machine type";
     123                 :            : 
     124                 :            :         if (err != NULL) {
     125                 :          0 :                 RTE_BPF_LOG_LINE(ERR, "%s(): %s", __func__, err);
     126                 :          0 :                 return -EINVAL;
     127                 :            :         }
     128                 :            : 
     129                 :            :         return 0;
     130                 :            : }
     131                 :            : 
     132                 :            : /*
     133                 :            :  * helper function, find executable section by name.
     134                 :            :  */
     135                 :            : static int
     136                 :          0 : find_elf_code(Elf *elf, const char *section, Elf_Data **psd, size_t *pidx)
     137                 :            : {
     138                 :            :         Elf_Scn *sc;
     139                 :            :         const Elf64_Ehdr *eh;
     140                 :            :         const Elf64_Shdr *sh;
     141                 :            :         Elf_Data *sd;
     142                 :            :         const char *sn;
     143                 :            :         int32_t rc;
     144                 :            : 
     145                 :          0 :         eh = elf64_getehdr(elf);
     146         [ #  # ]:          0 :         if (eh == NULL) {
     147                 :          0 :                 rc = elf_errno();
     148                 :          0 :                 RTE_BPF_LOG_LINE(ERR, "%s(%p, %s) error code: %d(%s)",
     149                 :            :                         __func__, elf, section, rc, elf_errmsg(rc));
     150                 :          0 :                 return -EINVAL;
     151                 :            :         }
     152                 :            : 
     153         [ #  # ]:          0 :         if (check_elf_header(eh) != 0)
     154                 :            :                 return -EINVAL;
     155                 :            : 
     156                 :            :         /* find given section by name */
     157         [ #  # ]:          0 :         for (sc = elf_nextscn(elf, NULL); sc != NULL;
     158                 :          0 :                         sc = elf_nextscn(elf, sc)) {
     159                 :          0 :                 sh = elf64_getshdr(sc);
     160                 :          0 :                 sn = elf_strptr(elf, eh->e_shstrndx, sh->sh_name);
     161   [ #  #  #  # ]:          0 :                 if (sn != NULL && strcmp(section, sn) == 0 &&
     162         [ #  # ]:          0 :                                 sh->sh_type == SHT_PROGBITS &&
     163         [ #  # ]:          0 :                                 sh->sh_flags == (SHF_ALLOC | SHF_EXECINSTR))
     164                 :            :                         break;
     165                 :            :         }
     166                 :            : 
     167                 :          0 :         sd = elf_getdata(sc, NULL);
     168   [ #  #  #  # ]:          0 :         if (sd == NULL || sd->d_size == 0 ||
     169         [ #  # ]:          0 :                         sd->d_size % sizeof(struct ebpf_insn) != 0) {
     170                 :          0 :                 rc = elf_errno();
     171                 :          0 :                 RTE_BPF_LOG_LINE(ERR, "%s(%p, %s) error code: %d(%s)",
     172                 :            :                         __func__, elf, section, rc, elf_errmsg(rc));
     173                 :          0 :                 return -EINVAL;
     174                 :            :         }
     175                 :            : 
     176                 :          0 :         *psd = sd;
     177                 :          0 :         *pidx = elf_ndxscn(sc);
     178                 :          0 :         return 0;
     179                 :            : }
     180                 :            : 
     181                 :            : /*
     182                 :            :  * helper function to process data from relocation table.
     183                 :            :  */
     184                 :            : static int
     185                 :          0 : process_reloc(Elf *elf, size_t sym_idx, Elf64_Rel *re, size_t re_sz,
     186                 :            :         struct ebpf_insn *ins, size_t ins_sz, const struct rte_bpf_prm *prm)
     187                 :            : {
     188                 :            :         int32_t rc;
     189                 :            :         uint32_t i, n;
     190                 :            :         size_t ofs, sym;
     191                 :            :         const char *sn;
     192                 :            :         const Elf64_Ehdr *eh;
     193                 :            :         Elf_Scn *sc;
     194                 :            :         const Elf_Data *sd;
     195                 :            :         Elf64_Sym *sm;
     196                 :            : 
     197                 :          0 :         eh = elf64_getehdr(elf);
     198                 :            : 
     199                 :            :         /* get symtable by section index */
     200                 :          0 :         sc = elf_getscn(elf, sym_idx);
     201                 :          0 :         sd = elf_getdata(sc, NULL);
     202         [ #  # ]:          0 :         if (sd == NULL)
     203                 :            :                 return -EINVAL;
     204                 :          0 :         sm = sd->d_buf;
     205                 :            : 
     206                 :          0 :         n = re_sz / sizeof(re[0]);
     207         [ #  # ]:          0 :         for (i = 0; i != n; i++) {
     208                 :            : 
     209                 :          0 :                 ofs = re[i].r_offset;
     210                 :            : 
     211                 :            :                 /* retrieve index in the symtable */
     212                 :          0 :                 sym = ELF64_R_SYM(re[i].r_info);
     213         [ #  # ]:          0 :                 if (sym * sizeof(sm[0]) >= sd->d_size)
     214                 :            :                         return -EINVAL;
     215                 :            : 
     216                 :          0 :                 sn = elf_strptr(elf, eh->e_shstrndx, sm[sym].st_name);
     217                 :            : 
     218                 :          0 :                 rc = resolve_xsym(sn, ofs, ins, ins_sz, prm);
     219         [ #  # ]:          0 :                 if (rc != 0) {
     220                 :          0 :                         RTE_BPF_LOG_LINE(ERR,
     221                 :            :                                 "resolve_xsym(%s, %zu) error code: %d",
     222                 :            :                                 sn, ofs, rc);
     223                 :          0 :                         return rc;
     224                 :            :                 }
     225                 :            :         }
     226                 :            : 
     227                 :            :         return 0;
     228                 :            : }
     229                 :            : 
     230                 :            : /*
     231                 :            :  * helper function, find relocation information (if any)
     232                 :            :  * and update bpf code.
     233                 :            :  */
     234                 :            : static int
     235                 :          0 : elf_reloc_code(Elf *elf, Elf_Data *ed, size_t sidx,
     236                 :            :         const struct rte_bpf_prm *prm)
     237                 :            : {
     238                 :            :         Elf64_Rel *re;
     239                 :            :         Elf_Scn *sc;
     240                 :            :         const Elf64_Shdr *sh;
     241                 :            :         const Elf_Data *sd;
     242                 :            :         int32_t rc;
     243                 :            : 
     244                 :            :         rc = 0;
     245                 :            : 
     246                 :            :         /* walk through all sections */
     247         [ #  # ]:          0 :         for (sc = elf_nextscn(elf, NULL); sc != NULL && rc == 0;
     248                 :          0 :                         sc = elf_nextscn(elf, sc)) {
     249                 :            : 
     250                 :          0 :                 sh = elf64_getshdr(sc);
     251                 :            : 
     252                 :            :                 /* relocation data for our code section */
     253   [ #  #  #  # ]:          0 :                 if (sh->sh_type == SHT_REL && sh->sh_info == sidx) {
     254                 :          0 :                         sd = elf_getdata(sc, NULL);
     255   [ #  #  #  # ]:          0 :                         if (sd == NULL || sd->d_size == 0 ||
     256         [ #  # ]:          0 :                                         sd->d_size % sizeof(re[0]) != 0)
     257                 :            :                                 return -EINVAL;
     258                 :          0 :                         rc = process_reloc(elf, sh->sh_link,
     259                 :          0 :                                 sd->d_buf, sd->d_size, ed->d_buf, ed->d_size,
     260                 :            :                                 prm);
     261                 :            :                 }
     262                 :            :         }
     263                 :            : 
     264                 :            :         return rc;
     265                 :            : }
     266                 :            : 
     267                 :            : static struct rte_bpf *
     268                 :          0 : bpf_load_elf(const struct rte_bpf_prm *prm, int32_t fd, const char *section)
     269                 :            : {
     270                 :            :         Elf *elf;
     271                 :            :         Elf_Data *sd;
     272                 :            :         size_t sidx;
     273                 :            :         int32_t rc;
     274                 :            :         struct rte_bpf *bpf;
     275                 :            :         struct rte_bpf_prm np;
     276                 :            : 
     277                 :          0 :         elf_version(EV_CURRENT);
     278                 :          0 :         elf = elf_begin(fd, ELF_C_READ, NULL);
     279                 :            : 
     280                 :          0 :         rc = find_elf_code(elf, section, &sd, &sidx);
     281         [ #  # ]:          0 :         if (rc == 0)
     282                 :          0 :                 rc = elf_reloc_code(elf, sd, sidx, prm);
     283                 :            : 
     284         [ #  # ]:          0 :         if (rc == 0) {
     285                 :          0 :                 np = prm[0];
     286                 :          0 :                 np.ins = sd->d_buf;
     287                 :          0 :                 np.nb_ins = sd->d_size / sizeof(struct ebpf_insn);
     288                 :          0 :                 bpf = rte_bpf_load(&np);
     289                 :            :         } else {
     290                 :            :                 bpf = NULL;
     291                 :          0 :                 rte_errno = -rc;
     292                 :            :         }
     293                 :            : 
     294                 :          0 :         elf_end(elf);
     295                 :          0 :         return bpf;
     296                 :            : }
     297                 :            : 
     298                 :            : RTE_EXPORT_SYMBOL(rte_bpf_elf_load)
     299                 :            : struct rte_bpf *
     300                 :          0 : rte_bpf_elf_load(const struct rte_bpf_prm *prm, const char *fname,
     301                 :            :         const char *sname)
     302                 :            : {
     303                 :            :         int32_t fd, rc;
     304                 :            :         struct rte_bpf *bpf;
     305                 :            : 
     306   [ #  #  #  # ]:          0 :         if (prm == NULL || fname == NULL || sname == NULL) {
     307                 :          0 :                 rte_errno = EINVAL;
     308                 :          0 :                 return NULL;
     309                 :            :         }
     310                 :            : 
     311                 :            :         fd = open(fname, O_RDONLY);
     312         [ #  # ]:          0 :         if (fd < 0) {
     313                 :          0 :                 rc = errno;
     314                 :          0 :                 RTE_BPF_LOG_LINE(ERR, "%s(%s) error code: %d(%s)",
     315                 :            :                         __func__, fname, rc, strerror(rc));
     316                 :          0 :                 rte_errno = EINVAL;
     317                 :          0 :                 return NULL;
     318                 :            :         }
     319                 :            : 
     320                 :          0 :         bpf = bpf_load_elf(prm, fd, sname);
     321                 :          0 :         close(fd);
     322                 :            : 
     323         [ #  # ]:          0 :         if (bpf == NULL) {
     324                 :          0 :                 RTE_BPF_LOG_LINE(ERR,
     325                 :            :                         "%s(fname=\"%s\", sname=\"%s\") failed, "
     326                 :            :                         "error code: %d",
     327                 :            :                         __func__, fname, sname, rte_errno);
     328                 :          0 :                 return NULL;
     329                 :            :         }
     330                 :            : 
     331                 :          0 :         RTE_BPF_LOG_LINE(INFO, "%s(fname=\"%s\", sname=\"%s\") "
     332                 :            :                 "successfully creates %p(jit={.func=%p,.sz=%zu});",
     333                 :            :                 __func__, fname, sname, bpf, bpf->jit.func, bpf->jit.sz);
     334                 :          0 :         return bpf;
     335                 :            : }

Generated by: LCOV version 1.14