LCOV - code coverage report
Current view: top level - vppinfra - elf_clib.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 82 167 49.1 %
Date: 2023-10-26 01:39:38 Functions: 7 14 50.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : #include <vppinfra/elf_clib.h>
      16             : 
      17             : #include <stdlib.h>
      18             : #include <fcntl.h>
      19             : #include <sys/stat.h>
      20             : 
      21             : typedef struct
      22             : {
      23             :   char **path;
      24             : } path_search_t;
      25             : 
      26             : always_inline void
      27           0 : path_search_free (path_search_t * p)
      28             : {
      29             :   uword i;
      30           0 :   for (i = 0; i < vec_len (p->path); i++)
      31           0 :     vec_free (p->path[i]);
      32           0 :   vec_free (p->path);
      33           0 : }
      34             : 
      35             : static char **
      36           0 : split_string (char *string, u8 delimiter)
      37             : {
      38           0 :   char **result = 0;
      39             :   char *p, *start, *s;
      40             : 
      41           0 :   p = string;
      42             :   while (1)
      43             :     {
      44           0 :       start = p;
      45           0 :       while (*p != 0 && *p != delimiter)
      46           0 :         p++;
      47           0 :       s = 0;
      48           0 :       vec_add (s, start, p - start);
      49           0 :       vec_add1 (s, 0);
      50           0 :       vec_add1 (result, s);
      51           0 :       if (*p == 0)
      52           0 :         break;
      53           0 :       p++;
      54             :     }
      55             : 
      56           0 :   return result;
      57             : }
      58             : 
      59             : static int
      60           0 : file_exists_and_is_executable (char *dir, char *file)
      61             : {
      62           0 :   char *path = (char *) format (0, "%s/%s%c", dir, file, 0);
      63             :   struct stat s;
      64             :   uword yes;
      65             : 
      66           0 :   yes = (stat (path, &s) >= 0
      67           0 :          && S_ISREG (s.st_mode)
      68           0 :          && 0 != (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)));
      69             : 
      70           0 :   vec_free (path);
      71             : 
      72           0 :   return yes;
      73             : }
      74             : 
      75             : static char *
      76         575 : path_search (char *file)
      77             : {
      78             :   path_search_t ps;
      79             :   uword i;
      80             :   char *result;
      81             : 
      82             :   /* Relative or absolute path. */
      83         575 :   if (file[0] == '.' || file[0] == '/')
      84         575 :     return file;
      85             : 
      86           0 :   if (getenv ("PATH") == 0)
      87           0 :     return file;
      88             : 
      89           0 :   ps.path = split_string (getenv ("PATH"), ':');
      90             : 
      91           0 :   for (i = 0; i < vec_len (ps.path); i++)
      92           0 :     if (file_exists_and_is_executable (ps.path[i], file))
      93           0 :       break;
      94             : 
      95           0 :   result = 0;
      96           0 :   if (i < vec_len (ps.path))
      97           0 :     result = (char *) format (0, "%s/%s%c", ps.path[i], file, 0);
      98             : 
      99           0 :   path_search_free (&ps);
     100             : 
     101           0 :   return result;
     102             : }
     103             : 
     104             : static clib_error_t *
     105       58111 : clib_elf_parse_file (clib_elf_main_t * cem,
     106             :                      char *file_name, void *link_address)
     107             : {
     108             :   elf_main_t *em;
     109             :   elf_section_t *s;
     110             :   int fd;
     111             :   struct stat fd_stat;
     112       58111 :   uword mmap_length = 0;
     113       58111 :   void *data = 0;
     114       58111 :   clib_error_t *error = 0;
     115             : 
     116       58111 :   vec_add2 (cem->elf_mains, em, 1);
     117             : 
     118       58111 :   fd = open (file_name, 0);
     119       58111 :   if (fd < 0)
     120             :     {
     121         575 :       error = clib_error_return_unix (0, "open `%s'", file_name);
     122         575 :       goto done;
     123             :     }
     124             : 
     125       57536 :   if (fstat (fd, &fd_stat) < 0)
     126             :     {
     127           0 :       error = clib_error_return_unix (0, "fstat `%s'", file_name);
     128           0 :       goto done;
     129             :     }
     130       57536 :   mmap_length = fd_stat.st_size;
     131             : 
     132       57536 :   data = mmap (0, mmap_length, PROT_READ, MAP_SHARED, fd, /* offset */ 0);
     133       57536 :   if (~pointer_to_uword (data) == 0)
     134             :     {
     135           0 :       error = clib_error_return_unix (0, "mmap `%s'", file_name);
     136           0 :       goto done;
     137             :     }
     138             : 
     139       57536 :   error = elf_parse (em, data, mmap_length);
     140       57536 :   if (error)
     141           0 :     goto done;
     142             : 
     143             :   /* Look for CLIB special sections. */
     144             :   {
     145       57536 :     char *section_name_start = CLIB_ELF_SECTION_ADD_PREFIX ();
     146       57536 :     uword section_name_start_len = strlen (section_name_start);
     147             : 
     148     2184660 :     vec_foreach (s, em->sections)
     149             :     {
     150     2127120 :       u8 *name = elf_section_name (em, s);
     151             :       uword *p;
     152             :       clib_elf_section_t *vs;
     153             :       clib_elf_section_bounds_t *b;
     154             : 
     155             :       /* Section name must begin with CLIB_ELF_SECTION key. */
     156     2127120 :       if (strcmp ((char *) name, section_name_start))
     157     2127120 :         continue;
     158             : 
     159           0 :       name += section_name_start_len;
     160           0 :       p = hash_get_mem (cem->section_by_name, name);
     161           0 :       if (p)
     162           0 :         vs = vec_elt_at_index (cem->sections, p[0]);
     163             :       else
     164             :         {
     165           0 :           name = format (0, "%s%c", name, 0);
     166           0 :           if (!cem->section_by_name)
     167           0 :             cem->section_by_name = hash_create_string (0, sizeof (uword));
     168           0 :           hash_set_mem (cem->section_by_name, name, vec_len (cem->sections));
     169           0 :           vec_add2 (cem->sections, vs, 1);
     170           0 :           vs->name = name;
     171             :         }
     172             : 
     173           0 :       vec_add2 (vs->bounds, b, 1);
     174           0 :       b->lo = link_address + s->header.exec_address;
     175           0 :       b->hi = b->lo + s->header.file_size;
     176             :     }
     177             :   }
     178             : 
     179             :   /* Parse symbols for this file. */
     180             :   {
     181             :     elf_symbol_table_t *t;
     182             :     elf64_symbol_t *s;
     183             : 
     184       57536 :     elf_parse_symbols (em);
     185      166854 :     vec_foreach (t, em->symbol_tables)
     186             :     {
     187   293197000 :       vec_foreach (s, t->symbols)
     188             :       {
     189   293088000 :         s->value += pointer_to_uword (link_address);
     190             :       }
     191             :     }
     192             :   }
     193             : 
     194             :   /* No need to keep section contents around. */
     195             :   {
     196             :     elf_section_t *s;
     197     2184660 :     vec_foreach (s, em->sections)
     198             :     {
     199     2127120 :       if (s->header.type != ELF_SECTION_STRING_TABLE)
     200     1960270 :         vec_free (s->contents);
     201             :     }
     202             :   }
     203             : 
     204       57536 : done:
     205       58111 :   if (error)
     206         575 :     elf_main_free (em);
     207       58111 :   if (fd >= 0)
     208       57536 :     close (fd);
     209       58111 :   if (data)
     210       57536 :     munmap (data, mmap_length);
     211       58111 :   return error;
     212             : }
     213             : 
     214             : #define __USE_GNU
     215             : #include <link.h>
     216             : 
     217             : static int
     218       58111 : add_section (struct dl_phdr_info *info, size_t size, void *opaque)
     219             : {
     220       58111 :   clib_elf_main_t *cem = opaque;
     221             :   clib_error_t *error;
     222       58111 :   char *name = (char *) info->dlpi_name;
     223       58111 :   void *addr = (void *) info->dlpi_addr;
     224             :   uword is_main;
     225             : 
     226       58111 :   is_main = strlen (name) == 0;
     227       58111 :   if (is_main)
     228             :     {
     229             :       static int done;
     230             : 
     231             :       /* Only do main program once. */
     232         575 :       if (done++)
     233           0 :         return 0;
     234             : 
     235         575 :       name = path_search (cem->exec_path);
     236         575 :       if (!name)
     237             :         {
     238           0 :           clib_error ("failed to find %s on PATH", cem->exec_path);
     239           0 :           return 0;
     240             :         }
     241         575 :       addr = 0;
     242             :     }
     243             : 
     244       58111 :   error = clib_elf_parse_file (cem, name, addr);
     245       58111 :   if (error)
     246             :     {
     247             :       /* Don't complain about 'linux-vdso.so.1' */
     248         575 :       if (!is_main && name[0] != '/' && error->code == ENOENT)
     249         575 :         clib_error_free (error);
     250             :       else
     251           0 :         clib_error_report (error);
     252             :     }
     253             : 
     254       58111 :   if (is_main && name != cem->exec_path)
     255           0 :     vec_free (name);
     256             : 
     257       58111 :   return 0;
     258             : }
     259             : 
     260             : static clib_elf_main_t clib_elf_main;
     261             : 
     262             : __clib_export void
     263         575 : clib_elf_main_init (char *exec_path)
     264             : {
     265         575 :   clib_elf_main_t *cem = &clib_elf_main;
     266             : 
     267         575 :   cem->exec_path = exec_path;
     268             : 
     269         575 :   dl_iterate_phdr (add_section, cem);
     270         575 : }
     271             : 
     272             : clib_elf_section_bounds_t *
     273           0 : clib_elf_get_section_bounds (char *name)
     274             : {
     275           0 :   clib_elf_main_t *em = &clib_elf_main;
     276           0 :   uword *p = hash_get (em->section_by_name, name);
     277           0 :   return p ? vec_elt_at_index (em->sections, p[0])->bounds : 0;
     278             : }
     279             : 
     280             : static uword
     281          12 : symbol_by_address_or_name (char *by_name,
     282             :                            uword by_address, clib_elf_symbol_t * s)
     283             : {
     284          12 :   clib_elf_main_t *cem = &clib_elf_main;
     285             :   elf_main_t *em;
     286             : 
     287          66 :   vec_foreach (em, cem->elf_mains)
     288             :   {
     289             :     elf_symbol_table_t *t;
     290          66 :     s->elf_main_index = em - cem->elf_mains;
     291         149 :     vec_foreach (t, em->symbol_tables)
     292             :     {
     293          95 :       s->symbol_table_index = t - em->symbol_tables;
     294          95 :       if (by_name)
     295             :         {
     296           0 :           uword *p = hash_get (t->symbol_by_name, by_name);
     297           0 :           if (p)
     298             :             {
     299           0 :               s->symbol = vec_elt (t->symbols, p[0]);
     300           0 :               return 1;
     301             :             }
     302             :         }
     303             :       else
     304             :         {
     305             :           elf64_symbol_t *x;
     306             :           /* FIXME linear search. */
     307     1325090 :           vec_foreach (x, t->symbols)
     308             :           {
     309     1325000 :             if (by_address >= x->value && by_address < x->value + x->size)
     310             :               {
     311          12 :                 s->symbol = x[0];
     312          12 :                 return 1;
     313             :               }
     314             :           }
     315             :         }
     316             :     }
     317             :   }
     318             : 
     319           0 :   return 0;
     320             : }
     321             : 
     322             : __clib_export uword
     323           0 : clib_elf_symbol_by_name (char *by_name, clib_elf_symbol_t *s)
     324             : {
     325           0 :   return symbol_by_address_or_name (by_name, /* by_address */ 0, s);
     326             : }
     327             : 
     328             : __clib_export uword
     329          12 : clib_elf_symbol_by_address (uword by_address, clib_elf_symbol_t *s)
     330             : {
     331          12 :   return symbol_by_address_or_name ( /* by_name */ 0, by_address, s);
     332             : }
     333             : 
     334             : __clib_export const char *
     335           0 : clib_elf_symbol_name (clib_elf_symbol_t *s)
     336             : {
     337           0 :   clib_elf_main_t *cem = &clib_elf_main;
     338             :   elf_main_t *em;
     339             :   elf_symbol_table_t *t;
     340             : 
     341           0 :   em = vec_elt_at_index (cem->elf_mains, s->elf_main_index);
     342           0 :   t = vec_elt_at_index (em->symbol_tables, s->symbol_table_index);
     343             : 
     344           0 :   return (const char *) elf_symbol_name (t, &s->symbol);
     345             : }
     346             : 
     347             : __clib_export u8 *
     348           0 : format_clib_elf_symbol (u8 *s, va_list *args)
     349             : {
     350           0 :   clib_elf_main_t *cem = &clib_elf_main;
     351           0 :   clib_elf_symbol_t *sym = va_arg (*args, clib_elf_symbol_t *);
     352             :   elf_main_t *em;
     353             :   elf_symbol_table_t *t;
     354             : 
     355           0 :   if (!sym)
     356             :     /* Just print table headings. */
     357           0 :     return format (s, "%U", format_elf_symbol, 0, 0, 0);
     358             : 
     359             :   else
     360             :     {
     361           0 :       em = vec_elt_at_index (cem->elf_mains, sym->elf_main_index);
     362           0 :       t = vec_elt_at_index (em->symbol_tables, sym->symbol_table_index);
     363           0 :       return format (s, "%U", format_elf_symbol, em, t, &sym->symbol);
     364             :     }
     365             : }
     366             : 
     367             : __clib_export u8 *
     368          12 : format_clib_elf_symbol_with_address (u8 * s, va_list * args)
     369             : {
     370          12 :   uword address = va_arg (*args, uword);
     371          12 :   clib_elf_main_t *cem = &clib_elf_main;
     372             :   clib_elf_symbol_t sym;
     373             :   elf_main_t *em;
     374             :   elf_symbol_table_t *t;
     375             : 
     376          12 :   if (clib_elf_symbol_by_address (address, &sym))
     377             :     {
     378          12 :       em = vec_elt_at_index (cem->elf_mains, sym.elf_main_index);
     379          12 :       t = vec_elt_at_index (em->symbol_tables, sym.symbol_table_index);
     380          12 :       s = format (s, "%s + 0x%wx",
     381             :                   elf_symbol_name (t, &sym.symbol),
     382          12 :                   address - sym.symbol.value);
     383             :     }
     384             :   else
     385           0 :     s = format (s, "0x%wx", address);
     386             : 
     387          12 :   return s;
     388             : }
     389             : 
     390             : /*
     391             :  * fd.io coding-style-patch-verification: ON
     392             :  *
     393             :  * Local Variables:
     394             :  * eval: (c-set-style "gnu")
     395             :  * End:
     396             :  */

Generated by: LCOV version 1.14