LCOV - code coverage report
Current view: top level - libpkg - pkg_elf.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 136 445 30.6 %
Date: 2015-08-15 Functions: 7 13 53.8 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
       4             :  * All rights reserved.
       5             :  * 
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  * 1. Redistributions of source code must retain the above copyright
      10             :  *    notice, this list of conditions and the following disclaimer
      11             :  *    in this position and unchanged.
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  * 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      17             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      20             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : 
      28             : #ifdef HAVE_CONFIG_H
      29             : #include "pkg_config.h"
      30             : #endif
      31             : 
      32             : #ifdef HAVE_SYS_ENDIAN_H
      33             : #include <sys/endian.h>
      34             : #elif HAVE_ENDIAN_H
      35             : #include <endian.h>
      36             : #elif HAVE_MACHINE_ENDIAN_H
      37             : #include <machine/endian.h>
      38             : #endif
      39             : #include <sys/types.h>
      40             : #if defined(HAVE_SYS_ELF_COMMON_H) && !defined(__DragonFly__)
      41             : #include <sys/elf_common.h>
      42             : #endif
      43             : #include <sys/stat.h>
      44             : 
      45             : #include <assert.h>
      46             : #include <ctype.h>
      47             : #include <dlfcn.h>
      48             : #include <fcntl.h>
      49             : #include <gelf.h>
      50             : #include <libgen.h>
      51             : #if defined(HAVE_LINK_H) && !defined(__DragonFly__) && defined(HAVE_LIBELF)
      52             : #include <link.h>
      53             : #endif
      54             : #include <paths.h>
      55             : #include <stdbool.h>
      56             : #include <string.h>
      57             : #include <unistd.h>
      58             : #ifdef HAVE_LIBELF
      59             : #include <libelf.h>
      60             : #endif
      61             : 
      62             : #include <bsd_compat.h>
      63             : 
      64             : #include "pkg.h"
      65             : #include "private/pkg.h"
      66             : #include "private/event.h"
      67             : #include "private/elf_tables.h"
      68             : #include "private/ldconfig.h"
      69             : 
      70             : #ifndef NT_ABI_TAG
      71             : #define NT_ABI_TAG 1
      72             : #endif
      73             : 
      74             : /* FFR: when we support installing a 32bit package on a 64bit host */
      75             : #define _PATH_ELF32_HINTS       "/var/run/ld-elf32.so.hints"
      76             : 
      77             : #ifndef roundup2
      78             : #define roundup2(x, y)  (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
      79             : #endif
      80             : 
      81             : static const char * elf_corres_to_string(const struct _elf_corres* m, int e);
      82             : static int elf_string_to_corres(const struct _elf_corres* m, const char *s);
      83             : 
      84             : static int
      85           0 : filter_system_shlibs(const char *name, char *path, size_t pathlen)
      86             : {
      87             :         const char *shlib_path;
      88             : 
      89           0 :         shlib_path = shlib_list_find_by_name(name);
      90           0 :         if (shlib_path == NULL) {
      91             :                 /* dynamic linker could not resolve */
      92           0 :                 return (EPKG_FATAL);
      93             :         }
      94             : 
      95             :         /* match /lib, /lib32, /usr/lib and /usr/lib32 */
      96           0 :         if (strncmp(shlib_path, "/lib", 4) == 0 ||
      97           0 :             strncmp(shlib_path, "/usr/lib", 8) == 0)
      98           0 :                 return (EPKG_END); /* ignore libs from base */
      99             : 
     100           0 :         if (path != NULL)
     101           0 :                 strncpy(path, shlib_path, pathlen);
     102             : 
     103           0 :         return (EPKG_OK);
     104             : } 
     105             : 
     106             : /* ARGSUSED */
     107             : static int
     108           0 : add_shlibs_to_pkg(struct pkg *pkg, const char *fpath, const char *name,
     109             :     bool is_shlib)
     110             : {
     111           0 :         struct pkg_file *file = NULL;
     112             :         const char *filepath;
     113             : 
     114           0 :         switch(filter_system_shlibs(name, NULL, 0)) {
     115             :         case EPKG_OK:           /* A non-system library */
     116           0 :                 pkg_addshlib_required(pkg, name);
     117           0 :                 return (EPKG_OK);
     118             :         case EPKG_END:          /* A system library */
     119           0 :                 return (EPKG_OK);
     120             :         default:
     121             :                 /* Ignore link resolution errors if we're analysing a
     122             :                    shared library. */
     123           0 :                 if (is_shlib)
     124           0 :                         return (EPKG_OK);
     125             : 
     126           0 :                 while (pkg_files(pkg, &file) == EPKG_OK) {
     127           0 :                         filepath = file->path;
     128           0 :                         if (strcmp(&filepath[strlen(filepath) - strlen(name)], name) == 0) {
     129           0 :                                 pkg_addshlib_required(pkg, name);
     130           0 :                                 return (EPKG_OK);
     131             :                         }
     132             :                 }
     133             : 
     134           0 :                 pkg_emit_notice("(%s-%s) %s - required shared library %s not "
     135             :                     "found", pkg->name, pkg->version, fpath, name);
     136             : 
     137           0 :                 return (EPKG_FATAL);
     138             :         }
     139             : }
     140             : 
     141             : static bool
     142           0 : shlib_valid_abi(const char *fpath, GElf_Ehdr *hdr, const char *abi)
     143             : {
     144             :         int semicolon;
     145             :         const char *p, *t;
     146             :         char arch[64], wordsize[64];
     147             :         int wclass;
     148             :         const char *shlib_arch;
     149             : 
     150             :         /*
     151             :          * ABI string is in format:
     152             :          * <osname>:<osversion>:<arch>:<wordsize>[.other]
     153             :          * We need here arch and wordsize only
     154             :          */
     155           0 :         arch[0] = '\0';
     156           0 :         wordsize[0] = '\0';
     157           0 :         p = abi;
     158           0 :         for(semicolon = 0; semicolon < 3 && p != NULL; semicolon ++, p ++) {
     159           0 :                 p = strchr(p, ':');
     160           0 :                 if (p != NULL) {
     161           0 :                         switch(semicolon) {
     162             :                         case 1:
     163             :                                 /* We have arch here */
     164           0 :                                 t = strchr(p + 1, ':');
     165             :                                 /* Abi line is likely invalid */
     166           0 :                                 if (t == NULL)
     167           0 :                                         return (true);
     168           0 :                                 strlcpy(arch, p + 1, MIN((long)sizeof(arch), t - p));
     169           0 :                                 break;
     170             :                         case 2:
     171           0 :                                 t = strchr(p + 1, ':');
     172           0 :                                 if (t == NULL)
     173           0 :                                         strlcpy(wordsize, p + 1, sizeof(wordsize));
     174             :                                 else
     175           0 :                                         strlcpy(wordsize, p + 1, MIN((long)sizeof(wordsize), t - p));
     176           0 :                                 break;
     177             :                         }
     178             :                 }
     179             :         }
     180             :         /* Invalid ABI line */
     181           0 :         if (arch[0] == '\0' || wordsize[0] == '\0')
     182           0 :                 return (true);
     183             : 
     184           0 :         shlib_arch = elf_corres_to_string(mach_corres, (int)hdr->e_machine);
     185           0 :         if (shlib_arch == NULL)
     186           0 :                 return (true);
     187             : 
     188           0 :         wclass = elf_string_to_corres(wordsize_corres, wordsize);
     189           0 :         if (wclass == -1)
     190           0 :                 return (true);
     191             : 
     192             : 
     193             :         /*
     194             :          * Compare wordsize first as the arch for amd64/i386 is an abmiguous
     195             :          * 'x86'
     196             :          */
     197           0 :         if ((int)hdr->e_ident[EI_CLASS] != wclass) {
     198           0 :                 pkg_debug(1, "not valid elf class for shlib: %s: %s",
     199             :                     elf_corres_to_string(wordsize_corres,
     200           0 :                     (int)hdr->e_ident[EI_CLASS]),
     201             :                     fpath);
     202           0 :                 return (false);
     203             :         }
     204             : 
     205           0 :         if (strcmp(shlib_arch, arch) != 0) {
     206           0 :                 pkg_debug(1, "not valid abi for shlib: %s: %s", shlib_arch,
     207             :                     fpath);
     208           0 :                 return (false);
     209             :         }
     210             : 
     211           0 :         return (true);
     212             : }
     213             : 
     214             : static int
     215          64 : analyse_elf(struct pkg *pkg, const char *fpath)
     216             : {
     217          64 :         Elf *e = NULL;
     218             :         GElf_Ehdr elfhdr;
     219          64 :         Elf_Scn *scn = NULL;
     220          64 :         Elf_Scn *note = NULL;
     221          64 :         Elf_Scn *dynamic = NULL;
     222             :         GElf_Shdr shdr;
     223             :         Elf_Data *data;
     224             :         GElf_Dyn *dyn, dyn_mem;
     225             :         struct stat sb;
     226          64 :         int ret = EPKG_OK;
     227             : 
     228          64 :         size_t numdyn = 0;
     229          64 :         size_t sh_link = 0;
     230             :         size_t dynidx;
     231             :         const char *osname;
     232             :         const char *myarch;
     233             :         const char *shlib;
     234             : 
     235          64 :         bool is_shlib = false;
     236             : 
     237          64 :         myarch = pkg_object_string(pkg_config_get("ABI"));
     238             : 
     239             :         int fd;
     240             : 
     241          64 :         if (lstat(fpath, &sb) != 0)
     242           0 :                 pkg_emit_errno("fstat() failed for", fpath);
     243             :         /* ignore empty files and non regular files */
     244          64 :         if (sb.st_size == 0 || !S_ISREG(sb.st_mode))
     245          62 :                 return (EPKG_END); /* Empty file or sym-link: no results */
     246             : 
     247           2 :         if ((fd = open(fpath, O_RDONLY, 0)) < 0) {
     248           0 :                 return (EPKG_FATAL);
     249             :         }
     250             : 
     251           2 :         if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
     252           0 :                 ret = EPKG_FATAL;
     253           0 :                 pkg_emit_error("elf_begin() for %s failed: %s", fpath,
     254             :                     elf_errmsg(-1));
     255           0 :                 goto cleanup;
     256             :         }
     257             : 
     258           2 :         if (elf_kind(e) != ELF_K_ELF) {
     259             :                 /* Not an elf file: no results */
     260           2 :                 ret = EPKG_END;
     261           2 :                 goto cleanup;
     262             :         }
     263             : 
     264           0 :         if (developer_mode)
     265           0 :                 pkg->flags |= PKG_CONTAINS_ELF_OBJECTS;
     266             : 
     267           0 :         if (gelf_getehdr(e, &elfhdr) == NULL) {
     268           0 :                 ret = EPKG_FATAL;
     269           0 :                 pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
     270           0 :                 goto cleanup;
     271             :         }
     272             : 
     273           0 :         if (elfhdr.e_type != ET_DYN && elfhdr.e_type != ET_EXEC &&
     274           0 :             elfhdr.e_type != ET_REL) {
     275           0 :                 ret = EPKG_END;
     276           0 :                 goto cleanup;
     277             :         }
     278             : 
     279             :         /* Elf file has sections header */
     280           0 :         while ((scn = elf_nextscn(e, scn)) != NULL) {
     281           0 :                 if (gelf_getshdr(scn, &shdr) != &shdr) {
     282           0 :                         ret = EPKG_FATAL;
     283           0 :                         pkg_emit_error("getshdr() for %s failed: %s", fpath,
     284             :                                         elf_errmsg(-1));
     285           0 :                         goto cleanup;
     286             :                 }
     287           0 :                 switch (shdr.sh_type) {
     288             :                 case SHT_NOTE:
     289           0 :                         if ((data = elf_getdata(scn, NULL)) == NULL) {
     290           0 :                                 ret = EPKG_END; /* Some error occurred, ignore this file */
     291           0 :                                 goto cleanup;
     292             :                         }
     293           0 :                         else if (data->d_buf != NULL) {
     294           0 :                                 Elf_Note *en = (Elf_Note *)data->d_buf;
     295           0 :                                 if (en->n_type == NT_ABI_TAG)
     296           0 :                                         note = scn;
     297             :                         }
     298           0 :                         break;
     299             :                 case SHT_DYNAMIC:
     300           0 :                         dynamic = scn;
     301           0 :                         sh_link = shdr.sh_link;
     302           0 :                         numdyn = shdr.sh_size / shdr.sh_entsize;
     303           0 :                         break;
     304             :                 }
     305             : 
     306           0 :                 if (note != NULL && dynamic != NULL)
     307           0 :                         break;
     308             :         }
     309             : 
     310             :         /*
     311             :          * note == NULL usually means a shared object for use with dlopen(3)
     312             :          * dynamic == NULL means not a dynamically linked elf
     313             :          */
     314           0 :         if (dynamic == NULL) {
     315           0 :                 ret = EPKG_END;
     316           0 :                 goto cleanup; /* not a dynamically linked elf: no results */
     317             :         }
     318             : 
     319           0 :         if (!shlib_valid_abi(fpath, &elfhdr, myarch)) {
     320           0 :                 ret = EPKG_END;
     321           0 :                 goto cleanup; /* Invalid ABI */
     322             :         }
     323             : 
     324           0 :         if (note != NULL) {
     325           0 :                 if ((data = elf_getdata(note, NULL)) == NULL) {
     326           0 :                         ret = EPKG_END; /* Some error occurred, ignore this file */
     327           0 :                         goto cleanup;
     328             :                 }
     329           0 :                 if (data->d_buf == NULL) {
     330           0 :                         ret = EPKG_END; /* No osname available */
     331           0 :                         goto cleanup;
     332             :                 }
     333           0 :                 osname = (const char *) data->d_buf + sizeof(Elf_Note);
     334           0 :                 if (strncasecmp(osname, "freebsd", sizeof("freebsd")) != 0 &&
     335           0 :                     strncasecmp(osname, "dragonfly", sizeof("dragonfly")) != 0) {
     336           0 :                         ret = EPKG_END; /* Foreign (probably linux) ELF object */
     337           0 :                         goto cleanup;
     338             :                 }
     339             :         } else {
     340           0 :                 if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD) {
     341           0 :                         ret = EPKG_END;
     342           0 :                         goto cleanup;
     343             :                 }
     344             :         }
     345             : 
     346           0 :         if ((data = elf_getdata(dynamic, NULL)) == NULL) {
     347           0 :                 ret = EPKG_END; /* Some error occurred, ignore this file */
     348           0 :                 goto cleanup;
     349             :         }
     350             : 
     351             :         /* First, scan through the data from the .dynamic section to
     352             :            find any RPATH or RUNPATH settings.  These are colon
     353             :            separated paths to prepend to the ld.so search paths from
     354             :            the ELF hints file.  These always seem to come right after
     355             :            the NEEDED shared library entries.
     356             : 
     357             :            NEEDED entries should resolve to a filename for installed
     358             :            executables, but need not resolve for installed shared
     359             :            libraries -- additional info from the apps that link
     360             :            against them would be required.  Shared libraries are
     361             :            distinguished by a DT_SONAME tag */
     362             : 
     363           0 :         rpath_list_init();
     364           0 :         for (dynidx = 0; dynidx < numdyn; dynidx++) {
     365           0 :                 if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
     366           0 :                         ret = EPKG_FATAL;
     367           0 :                         pkg_emit_error("getdyn() failed for %s: %s", fpath,
     368             :                             elf_errmsg(-1));
     369           0 :                         goto cleanup;
     370             :                 }
     371             : 
     372           0 :                 if (dyn->d_tag == DT_SONAME) {
     373           0 :                         is_shlib = true;
     374             : 
     375             :                         /* The file being scanned is a shared library
     376             :                            *provided* by the package. Record this if
     377             :                            appropriate */
     378             : 
     379           0 :                         pkg_addshlib_provided(pkg, elf_strptr(e, sh_link, dyn->d_un.d_val));
     380             :                 }
     381             : 
     382           0 :                 if (dyn->d_tag != DT_RPATH && dyn->d_tag != DT_RUNPATH)
     383           0 :                         continue;
     384             :                 
     385           0 :                 shlib_list_from_rpath(elf_strptr(e, sh_link, dyn->d_un.d_val),
     386           0 :                                       bsd_dirname(fpath));
     387           0 :                 break;
     388             :         }
     389             : 
     390             :         /* Now find all of the NEEDED shared libraries. */
     391             : 
     392           0 :         for (dynidx = 0; dynidx < numdyn; dynidx++) {
     393           0 :                 if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
     394           0 :                         ret = EPKG_FATAL;
     395           0 :                         pkg_emit_error("getdyn() failed for %s: %s", fpath,
     396             :                             elf_errmsg(-1));
     397           0 :                         goto cleanup;
     398             :                 }
     399             : 
     400           0 :                 if (dyn->d_tag != DT_NEEDED)
     401           0 :                         continue;
     402             : 
     403           0 :                 shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
     404             : 
     405           0 :                 add_shlibs_to_pkg(pkg, fpath, shlib, is_shlib);
     406             :         }
     407             : 
     408             : cleanup:
     409           2 :         rpath_list_free();
     410             : 
     411           2 :         if (e != NULL)
     412           2 :                 elf_end(e);
     413           2 :         close(fd);
     414             : 
     415           2 :         return (ret);
     416             : }
     417             : 
     418             : static int
     419           0 : analyse_fpath(struct pkg *pkg, const char *fpath)
     420             : {
     421             :         const char *dot;
     422             : 
     423           0 :         dot = strrchr(fpath, '.');
     424             : 
     425           0 :         if (dot == NULL)        /* No extension */
     426           0 :                 return (EPKG_OK);
     427             : 
     428           0 :         if (dot[1] == 'a' && dot[2] == '\0')
     429           0 :                 pkg->flags |= PKG_CONTAINS_STATIC_LIBS;
     430             : 
     431           0 :         if ((dot[1] == 'l' && dot[2] == 'a' && dot[3] == '\0') ||
     432           0 :             (dot[1] == 'h' && dot[2] == '\0'))
     433           0 :                 pkg->flags |= PKG_CONTAINS_H_OR_LA;
     434             : 
     435           0 :         return (EPKG_OK);
     436             : }
     437             : 
     438             : int
     439          71 : pkg_analyse_files(struct pkgdb *db, struct pkg *pkg, const char *stage)
     440             : {
     441          71 :         struct pkg_file *file = NULL;
     442             :         char *sh;
     443             :         khint_t k;
     444          71 :         int ret = EPKG_OK;
     445             :         char fpath[MAXPATHLEN];
     446             :         const char *lib;
     447          71 :         bool failures = false;
     448             : 
     449          71 :         if (kh_count(pkg->shlibs_required) != 0)
     450           0 :                 pkg_list_free(pkg, PKG_SHLIBS_REQUIRED);
     451          71 :         if (kh_count(pkg->shlibs_provided) != 0)
     452           2 :                 pkg_list_free(pkg, PKG_SHLIBS_PROVIDED);
     453             : 
     454          71 :         if (elf_version(EV_CURRENT) == EV_NONE)
     455           0 :                 return (EPKG_FATAL);
     456             : 
     457          71 :         shlib_list_init();
     458             : 
     459          71 :         ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS);
     460          71 :         if (ret != EPKG_OK)
     461           0 :                 goto cleanup;
     462             : 
     463             :         /* Assume no architecture dependence, for contradiction */
     464          71 :         if (developer_mode)
     465           3 :                 pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS |
     466             :                                 PKG_CONTAINS_STATIC_LIBS |
     467             :                                 PKG_CONTAINS_H_OR_LA);
     468             : 
     469         206 :         while (pkg_files(pkg, &file) == EPKG_OK) {
     470          64 :                 if (stage != NULL)
     471          14 :                         snprintf(fpath, sizeof(fpath), "%s/%s", stage, file->path);
     472             :                 else
     473          50 :                         strlcpy(fpath, file->path, sizeof(fpath));
     474             : 
     475          64 :                 ret = analyse_elf(pkg, fpath);
     476          64 :                 if (developer_mode) {
     477           0 :                         if (ret != EPKG_OK && ret != EPKG_END) {
     478           0 :                                 failures = true;
     479           0 :                                 continue;
     480             :                         }
     481           0 :                         analyse_fpath(pkg, fpath);
     482             :                 }
     483             :         }
     484             : 
     485             :         /*
     486             :          * Do not depend on libraries that a package provides itself
     487             :          */
     488          71 :         kh_each_value(pkg->shlibs_required, sh, {
     489             :                 if (kh_contains(strings, pkg->shlibs_provided, sh)) {
     490             :                         pkg_debug(2, "remove %s from required shlibs as the "
     491             :                             "package %s provides this library itself",
     492             :                             sh, pkg->name);
     493             :                         k = kh_get_strings(pkg->shlibs_required, sh);
     494             :                         kh_del_strings(pkg->shlibs_required, k);
     495             :                         continue;
     496             :                 }
     497             :                 file = NULL;
     498             :                 while (pkg_files(pkg, &file) == EPKG_OK) {
     499             :                         if ((lib = strstr(file->path, sh)) != NULL &&
     500             :                             strlen(lib) == strlen(sh) && lib[-1] == '/') {
     501             :                                 pkg_debug(2, "remove %s from required shlibs as "
     502             :                                     "the package %s provides this library itself",
     503             :                                     sh, pkg->name);
     504             :                                 k = kh_get_strings(pkg->shlibs_required, sh);
     505             :                                 kh_del_strings(pkg->shlibs_required, k);
     506             :                                 break;
     507             :                         }
     508             :                 }
     509             :         });
     510             : 
     511             :         /*
     512             :          * if the package is not supposed to provide share libraries then
     513             :          * drop the provided one
     514             :          */
     515          71 :         if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL)
     516           0 :                 kh_free(strings, pkg->shlibs_provided, char, free);
     517             : 
     518          71 :         if (failures)
     519           0 :                 goto cleanup;
     520             : 
     521          71 :         ret = EPKG_OK;
     522             : 
     523             : cleanup:
     524          71 :         shlib_list_free();
     525             : 
     526          71 :         return (ret);
     527             : }
     528             : 
     529             : static const char *
     530         876 : elf_corres_to_string(const struct _elf_corres* m, int e)
     531             : {
     532         876 :         int i = 0;
     533             : 
     534        1752 :         for (i = 0; m[i].string != NULL; i++)
     535        1752 :                 if (m[i].elf_nb == e)
     536         876 :                         return (m[i].string);
     537             : 
     538           0 :         return ("unknown");
     539             : }
     540             : 
     541             : static int
     542           0 : elf_string_to_corres(const struct _elf_corres* m, const char *s)
     543             : {
     544           0 :         int i = 0;
     545             : 
     546           0 :         for (i = 0; m[i].string != NULL; i++)
     547           0 :                 if (strcmp(m[i].string, s) == 0)
     548           0 :                         return (m[i].elf_nb);
     549             : 
     550           0 :         return (-1);
     551             : }
     552             : 
     553             : static const char *
     554           0 : aeabi_parse_arm_attributes(void *data, size_t length)
     555             : {
     556             :         uint32_t sect_len;
     557           0 :         uint8_t *section = data;
     558             : 
     559             : #define MOVE(len) do {          \
     560             :         assert(length >= (len)); \
     561             :         section += (len);       \
     562             :         length -= (len);        \
     563             : } while (0)
     564             : 
     565           0 :         if (length == 0 || *section != 'A')
     566           0 :                 return (NULL);
     567           0 :         MOVE(1);
     568             : 
     569             :         /* Read the section length */
     570           0 :         if (length < sizeof(sect_len))
     571           0 :                 return (NULL);
     572           0 :         memcpy(&sect_len, section, sizeof(sect_len));
     573             : 
     574             :         /*
     575             :          * The section length should be no longer than the section it is within
     576             :          */
     577           0 :         if (sect_len > length)
     578           0 :                 return (NULL);
     579             : 
     580           0 :         MOVE(sizeof(sect_len));
     581             : 
     582             :         /* Skip the vendor name */
     583           0 :         while (length != 0) {
     584           0 :                 if (*section == '\0')
     585           0 :                         break;
     586           0 :                 MOVE(1);
     587             :         }
     588           0 :         if (length == 0)
     589           0 :                 return (NULL);
     590           0 :         MOVE(1);
     591             : 
     592           0 :         while (length != 0) {
     593             :                 uint32_t tag_length;
     594             : 
     595           0 :                 switch(*section) {
     596             :                 case 1: /* Tag_File */
     597           0 :                         MOVE(1);
     598           0 :                         if (length < sizeof(tag_length))
     599           0 :                                 return (NULL);
     600           0 :                         memcpy(&tag_length, section, sizeof(tag_length));
     601           0 :                         break;
     602             :                 case 2: /* Tag_Section */
     603             :                 case 3: /* Tag_Symbol */
     604             :                 default:
     605           0 :                         return (NULL);
     606             :                 }
     607             :                 /* At least space for the tag and size */
     608           0 :                 if (tag_length <= 5)
     609           0 :                         return (NULL);
     610           0 :                 tag_length--;
     611             :                 /* Check the tag fits */
     612           0 :                 if (tag_length > length)
     613           0 :                         return (NULL);
     614             : 
     615             : #define MOVE_TAG(len) do {              \
     616             :         assert(tag_length >= (len)); \
     617             :         MOVE(len);                      \
     618             :         tag_length -= (len);            \
     619             : } while(0)
     620             : 
     621           0 :                 MOVE(sizeof(tag_length));
     622           0 :                 tag_length -= sizeof(tag_length);
     623             : 
     624           0 :                 while (tag_length != 0) {
     625             :                         uint8_t tag;
     626             : 
     627           0 :                         assert(tag_length >= length);
     628             : 
     629           0 :                         tag = *section;
     630           0 :                         MOVE_TAG(1);
     631             : 
     632             :                         /*
     633             :                          * These tag values come from:
     634             :                          * 
     635             :                          * Addenda to, and Errata in, the ABI for the
     636             :                          * ARM Architecture. Release 2.08, section 2.3.
     637             :                          */
     638           0 :                         if (tag == 6) { /* == Tag_CPU_arch */
     639             :                                 uint8_t val;
     640             : 
     641           0 :                                 val = *section;
     642             :                                 /*
     643             :                                  * We don't support values that require
     644             :                                  * more than one byte.
     645             :                                  */
     646           0 :                                 if (val & (1 << 7))
     647           0 :                                         return (NULL);
     648             : 
     649             :                                 /* We have an ARMv4 or ARMv5 */
     650           0 :                                 if (val <= 5)
     651           0 :                                         return ("arm");
     652             :                                 else /* We have an ARMv6+ */
     653           0 :                                         return ("armv6");
     654           0 :                         } else if (tag == 4 || tag == 5 || tag == 32 ||
     655           0 :                             tag == 65 || tag == 67) {
     656           0 :                                 while (*section != '\0' && length != 0)
     657           0 :                                         MOVE_TAG(1);
     658           0 :                                 if (tag_length == 0)
     659           0 :                                         return (NULL);
     660             :                                 /* Skip the last byte */
     661           0 :                                 MOVE_TAG(1);
     662           0 :                         } else if ((tag >= 7 && tag <= 31) || tag == 34 ||
     663           0 :                             tag == 36 || tag == 38 || tag == 42 || tag == 44 ||
     664           0 :                             tag == 64 || tag == 66 || tag == 68 || tag == 70) { 
     665             :                                 /* Skip the uleb128 data */
     666           0 :                                 while (*section & (1 << 7) && length != 0)
     667           0 :                                         MOVE_TAG(1);
     668           0 :                                 if (tag_length == 0)
     669           0 :                                         return (NULL);
     670             :                                 /* Skip the last byte */
     671           0 :                                 MOVE_TAG(1);
     672             :                         } else
     673           0 :                                 return (NULL);
     674             : #undef MOVE_TAG
     675             :                 }
     676             : 
     677           0 :                 break;
     678             :         }
     679           0 :         return (NULL);
     680             : #undef MOVE
     681             : }
     682             : 
     683             : static int
     684         438 : pkg_get_myarch_elfparse(char *dest, size_t sz)
     685             : {
     686         438 :         Elf *elf = NULL;
     687             :         GElf_Ehdr elfhdr;
     688             :         GElf_Shdr shdr;
     689             :         Elf_Data *data;
     690             :         Elf_Note note;
     691         438 :         Elf_Scn *scn = NULL;
     692             :         int fd;
     693         438 :         char *src = NULL;
     694             :         char *osname;
     695         438 :         uint32_t version = 0;
     696         438 :         int ret = EPKG_OK;
     697             :         const char *arch, *abi, *endian_corres_str, *wordsize_corres_str, *fpu;
     698             :         const char *path;
     699             : 
     700         438 :         path = getenv("ABI_FILE");
     701         438 :         if (path == NULL)
     702         438 :                 path = _PATH_BSHELL;
     703             : 
     704         438 :         if (elf_version(EV_CURRENT) == EV_NONE) {
     705           0 :                 pkg_emit_error("ELF library initialization failed: %s",
     706             :                     elf_errmsg(-1));
     707           0 :                 return (EPKG_FATAL);
     708             :         }
     709             : 
     710         438 :         if ((fd = open(path, O_RDONLY)) < 0) {
     711           0 :                 pkg_emit_errno("open", _PATH_BSHELL);
     712           0 :                 snprintf(dest, sz, "%s", "unknown");
     713           0 :                 return (EPKG_FATAL);
     714             :         }
     715             : 
     716         438 :         if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
     717           0 :                 ret = EPKG_FATAL;
     718           0 :                 pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1));
     719           0 :                 goto cleanup;
     720             :         }
     721             : 
     722         438 :         if (gelf_getehdr(elf, &elfhdr) == NULL) {
     723           0 :                 ret = EPKG_FATAL;
     724           0 :                 pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
     725           0 :                 goto cleanup;
     726             :         }
     727             : 
     728             : 
     729        1314 :         while ((scn = elf_nextscn(elf, scn)) != NULL) {
     730         876 :                 if (gelf_getshdr(scn, &shdr) != &shdr) {
     731           0 :                         ret = EPKG_FATAL;
     732           0 :                         pkg_emit_error("getshdr() failed: %s.", elf_errmsg(-1));
     733           0 :                         goto cleanup;
     734             :                 }
     735             : 
     736         876 :                 if (shdr.sh_type == SHT_NOTE)
     737         438 :                         break;
     738             :         }
     739             : 
     740         438 :         if (scn == NULL) {
     741           0 :                 ret = EPKG_FATAL;
     742           0 :                 pkg_emit_error("failed to get the note section");
     743           0 :                 goto cleanup;
     744             :         }
     745             : 
     746         438 :         data = elf_getdata(scn, NULL);
     747         438 :         src = data->d_buf;
     748         876 :         while ((uintptr_t)src < ((uintptr_t)data->d_buf + data->d_size)) {
     749         438 :                 memcpy(&note, src, sizeof(Elf_Note));
     750         438 :                 src += sizeof(Elf_Note);
     751         438 :                 if (note.n_type == NT_VERSION)
     752         438 :                         break;
     753           0 :                 src += roundup2(note.n_namesz + note.n_descsz, 4);
     754             :         }
     755         438 :         if ((uintptr_t)src >= ((uintptr_t)data->d_buf + data->d_size)) {
     756           0 :                 ret = EPKG_FATAL;
     757           0 :                 pkg_emit_error("failed to find the version elf note");
     758           0 :                 goto cleanup;
     759             :         }
     760         438 :         osname = src;
     761         438 :         src += roundup2(note.n_namesz, 4);
     762         438 :         if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
     763           0 :                 version = be32dec(src);
     764             :         else
     765         438 :                 version = le32dec(src);
     766             : 
     767         438 :         wordsize_corres_str = elf_corres_to_string(wordsize_corres,
     768         438 :             (int)elfhdr.e_ident[EI_CLASS]);
     769             : 
     770         438 :         arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine);
     771             : #if defined(__DragonFly__)
     772             :         snprintf(dest, sz, "%s:%d.%d",
     773             :             osname, version / 100000, (((version / 100 % 1000)+1)/2)*2);
     774             : #else
     775         438 :         snprintf(dest, sz, "%s:%d", osname, version / 100000);
     776             : #endif
     777             : 
     778         438 :         switch (elfhdr.e_machine) {
     779             :         case EM_ARM:
     780           0 :                 endian_corres_str = elf_corres_to_string(endian_corres,
     781           0 :                     (int)elfhdr.e_ident[EI_DATA]);
     782             : 
     783             :                 /* FreeBSD doesn't support the hard-float ABI yet */
     784           0 :                 fpu = "softfp";
     785           0 :                 if ((elfhdr.e_flags & 0xFF000000) != 0) {
     786           0 :                         const char *sh_name = NULL;
     787             :                         size_t shstrndx;
     788             : 
     789             :                         /* This is an EABI file, the conformance level is set */
     790           0 :                         abi = "eabi";
     791             : 
     792             :                         /* Find which TARGET_ARCH we are building for. */
     793           0 :                         elf_getshdrstrndx(elf, &shstrndx);
     794           0 :                         while ((scn = elf_nextscn(elf, scn)) != NULL) {
     795           0 :                                 sh_name = NULL;
     796           0 :                                 if (gelf_getshdr(scn, &shdr) != &shdr) {
     797           0 :                                         scn = NULL;
     798           0 :                                         break;
     799             :                                 }
     800             : 
     801           0 :                                 sh_name = elf_strptr(elf, shstrndx,
     802           0 :                                     shdr.sh_name);
     803           0 :                                 if (sh_name == NULL)
     804           0 :                                         continue;
     805           0 :                                 if (strcmp(".ARM.attributes", sh_name) == 0)
     806           0 :                                         break;
     807             :                         }
     808           0 :                         if (scn != NULL && sh_name != NULL) {
     809           0 :                                 data = elf_getdata(scn, NULL);
     810             :                                 /*
     811             :                                  * Prior to FreeBSD 10.0 libelf would return
     812             :                                  * NULL from elf_getdata on the .ARM.attributes
     813             :                                  * section. As this was the first release to
     814             :                                  * get armv6 support assume a NULL value means
     815             :                                  * arm.
     816             :                                  *
     817             :                                  * This assumption can be removed when 9.x
     818             :                                  * is unsupported.
     819             :                                  */
     820           0 :                                 if (data != NULL) {
     821           0 :                                         arch = aeabi_parse_arm_attributes(
     822             :                                             data->d_buf, data->d_size);
     823           0 :                                         if (arch == NULL) {
     824           0 :                                                 ret = EPKG_FATAL;
     825           0 :                                                 pkg_emit_error(
     826             :                                                     "unknown ARM ARCH");
     827           0 :                                                 goto cleanup;
     828             :                                         }
     829             :                                 }
     830             :                         } else {
     831           0 :                                 ret = EPKG_FATAL;
     832           0 :                                 pkg_emit_error("Unable to find the "
     833             :                                     ".ARM.attributes section");
     834           0 :                                 goto cleanup;
     835             :                         }
     836             : 
     837           0 :                 } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) {
     838             :                         /*
     839             :                          * EABI executables all have this field set to
     840             :                          * ELFOSABI_NONE, therefore it must be an oabi file.
     841             :                          */
     842           0 :                         abi = "oabi";
     843             :                 } else {
     844             :                         /*
     845             :                          * We may have failed to positively detect the ABI,
     846             :                          * set the ABI to unknown. If we end up here one of
     847             :                          * the above cases should be fixed for the binary.
     848             :                          */
     849           0 :                         ret = EPKG_FATAL;
     850           0 :                         pkg_emit_error("unknown ARM ABI");
     851           0 :                         goto cleanup;
     852             :                 }
     853           0 :                 snprintf(dest + strlen(dest), sz - strlen(dest),
     854             :                     ":%s:%s:%s:%s:%s", arch, wordsize_corres_str,
     855             :                     endian_corres_str, abi, fpu);
     856           0 :                 break;
     857             :         case EM_MIPS:
     858             :                 /*
     859             :                  * this is taken from binutils sources:
     860             :                  * include/elf/mips.h
     861             :                  * mapping is figured out from binutils:
     862             :                  * gas/config/tc-mips.c
     863             :                  */
     864           0 :                 switch (elfhdr.e_flags & EF_MIPS_ABI) {
     865             :                         case E_MIPS_ABI_O32:
     866           0 :                                 abi = "o32";
     867           0 :                                 break;
     868             :                         case E_MIPS_ABI_N32:
     869           0 :                                 abi = "n32";
     870           0 :                                 break;
     871             :                         default:
     872           0 :                                 if (elfhdr.e_ident[EI_DATA] == ELFCLASS32)
     873           0 :                                         abi = "o32";
     874           0 :                                 else if (elfhdr.e_ident[EI_DATA] == ELFCLASS64)
     875           0 :                                         abi = "n64";
     876             :                                 else
     877           0 :                                         abi = "unknown";
     878           0 :                                 break;
     879             :                 }
     880           0 :                 endian_corres_str = elf_corres_to_string(endian_corres,
     881           0 :                     (int)elfhdr.e_ident[EI_DATA]);
     882             : 
     883           0 :                 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s",
     884             :                     arch, wordsize_corres_str, endian_corres_str, abi);
     885           0 :                 break;
     886             :         default:
     887         438 :                 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s",
     888             :                     arch, wordsize_corres_str);
     889         438 :                 break;
     890             :         }
     891             : 
     892             : cleanup:
     893         438 :         if (elf != NULL)
     894         438 :                 elf_end(elf);
     895             : 
     896         438 :         close(fd);
     897         438 :         return (ret);
     898             : }
     899             : 
     900             : int
     901         305 : pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
     902             : {
     903         305 :         int i = 0;
     904             :         struct arch_trans *arch_trans;
     905             : 
     906         305 :         bzero(dest, sz);
     907             :         /* Lower case the OS */
     908        2211 :         while (arch[i] != ':' && arch[i] != '\0') {
     909        1601 :                 dest[i] = tolower(arch[i]);
     910        1601 :                 i++;
     911             :         }
     912         305 :         if (arch[i] == '\0')
     913          89 :                 return (0);
     914             : 
     915         216 :         dest[i++] = ':';
     916             : 
     917             :         /* Copy the version */
     918         864 :         while (arch[i] != ':' && arch[i] != '\0') {
     919         432 :                 dest[i] = arch[i];
     920         432 :                 i++;
     921             :         }
     922         216 :         if (arch[i] == '\0')
     923           0 :                 return (0);
     924             : 
     925         216 :         dest[i++] = ':';
     926             : 
     927         648 :         for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
     928         216 :             arch_trans++) {
     929         432 :                 if (strcmp(arch + i, arch_trans->archid) == 0) {
     930         216 :                         strlcpy(dest + i, arch_trans->elftype,
     931         216 :                             sz - (arch + i - dest));
     932         216 :                         return (0);
     933             :                 }
     934             :         }
     935           0 :         strlcpy(dest + i, arch + i, sz - (arch + i  - dest));
     936             : 
     937           0 :         return (0);
     938             : }
     939             : 
     940             : int
     941         200 : pkg_get_myarch_legacy(char *dest, size_t sz)
     942             : {
     943             :         int i, err;
     944             : 
     945         200 :         err = pkg_get_myarch_elfparse(dest, sz);
     946         200 :         if (err)
     947           0 :                 return (err);
     948             : 
     949        3600 :         for (i = 0; i < strlen(dest); i++)
     950        3400 :                 dest[i] = tolower(dest[i]);
     951             : 
     952         200 :         return (0);
     953             : }
     954             : 
     955             : #ifndef __DragonFly__
     956             : int
     957         238 : pkg_get_myarch(char *dest, size_t sz)
     958             : {
     959             :         struct arch_trans *arch_trans;
     960             :         char *arch_tweak;
     961             : 
     962             :         int err;
     963         238 :         err = pkg_get_myarch_elfparse(dest, sz);
     964         238 :         if (err)
     965           0 :                 return (err);
     966             : 
     967             :         /* Translate architecture string back to regular OS one */
     968         238 :         arch_tweak = strchr(dest, ':');
     969         238 :         if (arch_tweak == NULL)
     970           0 :                 return (0);
     971         238 :         arch_tweak++;
     972         238 :         arch_tweak = strchr(arch_tweak, ':');
     973         238 :         if (arch_tweak == NULL)
     974           0 :                 return (0);
     975         238 :         arch_tweak++;
     976         714 :         for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
     977         238 :             arch_trans++) {
     978         476 :                 if (strcmp(arch_tweak, arch_trans->elftype) == 0) {
     979         238 :                         strlcpy(arch_tweak, arch_trans->archid,
     980         238 :                             sz - (arch_tweak - dest));
     981         238 :                         break;
     982             :                 }
     983             :         }
     984             : 
     985         238 :         return (0);
     986             : }
     987             : #endif
     988             : 

Generated by: LCOV version 1.10