Home | History | Annotate | Line # | Download | only in gdb.base
      1  1.11  christos /* Copyright 2013-2024 Free Software Foundation, Inc.
      2   1.1  christos    This program is free software; you can redistribute it and/or modify
      3   1.1  christos    it under the terms of the GNU General Public License as published by
      4   1.1  christos    the Free Software Foundation; either version 3 of the License, or
      5   1.1  christos    (at your option) any later version.
      6   1.1  christos 
      7   1.1  christos    This program is distributed in the hope that it will be useful,
      8   1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
      9   1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10   1.1  christos    GNU General Public License for more details.
     11   1.1  christos 
     12   1.1  christos    You should have received a copy of the GNU General Public License
     13   1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     14   1.1  christos */
     15   1.1  christos 
     16   1.1  christos #include <unistd.h>
     17   1.1  christos #include <fcntl.h>
     18   1.3  christos #include <limits.h>
     19   1.1  christos #include <stdio.h>
     20   1.1  christos #include <stdlib.h>
     21   1.1  christos #include <string.h>
     22   1.1  christos #include <sys/mman.h>
     23   1.9  christos #include <assert.h>
     24   1.1  christos 
     25   1.1  christos #include "sym-file-loader.h"
     26   1.1  christos 
     27   1.3  christos #include <inttypes.h>
     28   1.3  christos #include <ansidecl.h>
     29   1.3  christos #include <elf/common.h>
     30   1.3  christos #include <elf/external.h>
     31   1.3  christos 
     32   1.3  christos #ifdef TARGET_LP64
     33   1.3  christos 
     34   1.3  christos typedef Elf64_External_Phdr Elf_External_Phdr;
     35   1.3  christos typedef Elf64_External_Ehdr Elf_External_Ehdr;
     36   1.3  christos typedef Elf64_External_Shdr Elf_External_Shdr;
     37   1.3  christos typedef Elf64_External_Sym Elf_External_Sym;
     38   1.3  christos typedef uint64_t Elf_Addr;
     39   1.3  christos 
     40   1.3  christos #elif defined TARGET_ILP32
     41   1.3  christos 
     42   1.3  christos typedef Elf32_External_Phdr Elf_External_Phdr;
     43   1.3  christos typedef Elf32_External_Ehdr Elf_External_Ehdr;
     44   1.3  christos typedef Elf32_External_Shdr Elf_External_Shdr;
     45   1.3  christos typedef Elf32_External_Sym Elf_External_Sym;
     46   1.3  christos typedef uint32_t Elf_Addr;
     47   1.3  christos 
     48   1.3  christos #endif
     49   1.3  christos 
     50   1.3  christos #define GET(hdr, field) (\
     51   1.3  christos sizeof ((hdr)->field) == 1 ? (uint64_t) (hdr)->field[0] : \
     52   1.3  christos sizeof ((hdr)->field) == 2 ? (uint64_t) *(uint16_t *) (hdr)->field : \
     53   1.3  christos sizeof ((hdr)->field) == 4 ? (uint64_t) *(uint32_t *) (hdr)->field : \
     54   1.3  christos sizeof ((hdr)->field) == 8 ? *(uint64_t *) (hdr)->field : \
     55   1.3  christos *(uint64_t *) NULL)
     56   1.3  christos 
     57   1.3  christos #define GETADDR(hdr, field) (\
     58   1.3  christos sizeof ((hdr)->field) == sizeof (Elf_Addr) ? *(Elf_Addr *) (hdr)->field : \
     59   1.3  christos *(Elf_Addr *) NULL)
     60   1.3  christos 
     61   1.3  christos struct segment
     62   1.3  christos {
     63   1.3  christos   uint8_t *mapped_addr;
     64   1.3  christos   size_t mapped_size;
     65   1.3  christos   Elf_External_Phdr *phdr;
     66   1.3  christos   struct segment *next;
     67   1.3  christos };
     68   1.3  christos 
     69   1.3  christos struct library
     70   1.3  christos {
     71   1.3  christos   int fd;
     72   1.3  christos   Elf_External_Ehdr *ehdr;
     73   1.3  christos   struct segment *segments;
     74   1.3  christos };
     75   1.3  christos 
     76   1.3  christos static Elf_External_Shdr *find_shdr (Elf_External_Ehdr *ehdr,
     77   1.3  christos 				     const char *section);
     78   1.3  christos static int translate_offset (uint64_t file_offset, struct segment *seg,
     79   1.3  christos 			     void **addr);
     80   1.3  christos 
     81   1.1  christos #ifdef TARGET_LP64
     82   1.1  christos 
     83   1.1  christos uint8_t
     84   1.1  christos elf_st_type (uint8_t st_info)
     85   1.1  christos {
     86   1.1  christos   return ELF64_ST_TYPE (st_info);
     87   1.1  christos }
     88   1.1  christos 
     89   1.1  christos #elif defined TARGET_ILP32
     90   1.1  christos 
     91   1.1  christos uint8_t
     92   1.1  christos elf_st_type (uint8_t st_info)
     93   1.1  christos {
     94   1.1  christos   return ELF32_ST_TYPE (st_info);
     95   1.1  christos }
     96   1.1  christos 
     97   1.1  christos #endif
     98   1.1  christos 
     99   1.1  christos /* Load a program segment.  */
    100   1.1  christos 
    101   1.1  christos static struct segment *
    102   1.1  christos load (uint8_t *addr, Elf_External_Phdr *phdr, struct segment *tail_seg)
    103   1.1  christos {
    104   1.1  christos   struct segment *seg = NULL;
    105   1.1  christos   uint8_t *mapped_addr = NULL;
    106   1.3  christos   size_t mapped_size = 0;
    107   1.1  christos   void *from = NULL;
    108   1.1  christos   void *to = NULL;
    109   1.1  christos 
    110   1.1  christos   /* For the sake of simplicity all operations are permitted.  */
    111   1.1  christos   unsigned perm = PROT_READ | PROT_WRITE | PROT_EXEC;
    112   1.1  christos 
    113   1.1  christos   mapped_addr = (uint8_t *) mmap ((void *) GETADDR (phdr, p_vaddr),
    114   1.1  christos 				  GET (phdr, p_memsz), perm,
    115   1.1  christos 				  MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    116   1.9  christos   assert (mapped_addr != MAP_FAILED);
    117   1.9  christos 
    118   1.3  christos   mapped_size = GET (phdr, p_memsz);
    119   1.1  christos 
    120   1.1  christos   from = (void *) (addr + GET (phdr, p_offset));
    121   1.1  christos   to = (void *) mapped_addr;
    122   1.1  christos 
    123   1.1  christos   memcpy (to, from, GET (phdr, p_filesz));
    124   1.1  christos 
    125   1.1  christos   seg = (struct segment *) malloc (sizeof (struct segment));
    126   1.1  christos 
    127   1.1  christos   if (seg == 0)
    128   1.1  christos     return 0;
    129   1.1  christos 
    130   1.1  christos   seg->mapped_addr = mapped_addr;
    131   1.3  christos   seg->mapped_size = mapped_size;
    132   1.1  christos   seg->phdr = phdr;
    133   1.1  christos   seg->next = 0;
    134   1.1  christos 
    135   1.1  christos   if (tail_seg != 0)
    136   1.1  christos     tail_seg->next = seg;
    137   1.1  christos 
    138   1.1  christos   return seg;
    139   1.1  christos }
    140   1.1  christos 
    141   1.3  christos #ifdef __linux__
    142   1.3  christos # define SELF_LINK "/proc/self/exe"
    143   1.3  christos #elif defined NETBSD
    144   1.3  christos # define SELF_LINK "/proc/curproc/exe"
    145   1.3  christos #elif defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
    146   1.3  christos # define SELF_LINK "/proc/curproc/file"
    147   1.3  christos #elif defined SunOS
    148   1.3  christos # define SELF_LINK "/proc/self/path/a.out"
    149   1.3  christos #endif
    150   1.3  christos 
    151   1.3  christos /* Like RPATH=$ORIGIN, return the dirname of the current
    152   1.3  christos    executable.  */
    153   1.3  christos 
    154   1.3  christos static const char *
    155   1.3  christos get_origin (void)
    156   1.3  christos {
    157   1.3  christos   static char self_path[PATH_MAX];
    158   1.3  christos   static ssize_t self_path_len;
    159   1.3  christos 
    160   1.3  christos   if (self_path_len == 0)
    161   1.3  christos     {
    162   1.3  christos #ifdef SELF_LINK
    163   1.3  christos       self_path_len = readlink (SELF_LINK, self_path, PATH_MAX - 1);
    164   1.3  christos       if (self_path_len != -1)
    165   1.3  christos 	{
    166   1.3  christos 	  char *dirsep;
    167   1.3  christos 
    168   1.3  christos 	  self_path[self_path_len] = '\0';
    169   1.3  christos 	  dirsep = strrchr (self_path, '/');
    170   1.3  christos 	  *dirsep = '\0';
    171   1.3  christos 	}
    172   1.3  christos #else
    173   1.3  christos       self_path_len = -1;
    174   1.3  christos #endif
    175   1.3  christos     }
    176   1.3  christos 
    177   1.3  christos   if (self_path_len == -1)
    178   1.3  christos     return NULL;
    179   1.3  christos   else
    180   1.3  christos     return self_path;
    181   1.3  christos }
    182   1.3  christos 
    183   1.3  christos /* Unload/unmap a segment.  */
    184   1.3  christos 
    185   1.3  christos static void
    186   1.3  christos unload (struct segment *seg)
    187   1.3  christos {
    188   1.3  christos   munmap (seg->mapped_addr, seg->mapped_size);
    189   1.3  christos   free (seg);
    190   1.3  christos }
    191   1.3  christos 
    192   1.3  christos void
    193   1.3  christos unload_shlib (struct library *lib)
    194   1.3  christos {
    195   1.3  christos   struct segment *seg, *next_seg;
    196   1.3  christos 
    197   1.3  christos   for (seg = lib->segments; seg != NULL; seg = next_seg)
    198   1.3  christos     {
    199   1.3  christos       next_seg = seg->next;
    200   1.3  christos       unload (seg);
    201   1.3  christos     }
    202   1.3  christos 
    203   1.3  christos   close (lib->fd);
    204   1.3  christos   free (lib);
    205   1.3  christos }
    206   1.3  christos 
    207   1.1  christos /* Mini shared library loader.  No reallocation
    208   1.1  christos    is performed for the sake of simplicity.  */
    209   1.1  christos 
    210   1.3  christos struct library *
    211   1.3  christos load_shlib (const char *file)
    212   1.1  christos {
    213   1.3  christos   struct library *lib;
    214   1.1  christos   uint64_t i;
    215   1.3  christos   int fd = -1;
    216   1.1  christos   off_t fsize;
    217   1.1  christos   uint8_t *addr;
    218   1.1  christos   Elf_External_Ehdr *ehdr;
    219   1.1  christos   Elf_External_Phdr *phdr;
    220   1.1  christos   struct segment *head_seg = NULL;
    221   1.1  christos   struct segment *tail_seg = NULL;
    222   1.3  christos   const char *origin;
    223   1.3  christos   char *path;
    224   1.3  christos 
    225   1.3  christos   /* Map the lib in memory for reading.
    226   1.3  christos 
    227   1.3  christos      If the file name is relative, try looking it up relative to the
    228   1.3  christos      main executable's path.  I.e., emulate RPATH=$ORIGIN.  */
    229   1.3  christos   if (file[0] != '/')
    230   1.3  christos     {
    231   1.3  christos       origin = get_origin ();
    232   1.3  christos       if (origin == NULL)
    233   1.3  christos 	{
    234   1.3  christos 	  fprintf (stderr, "get_origin not implemented.");
    235   1.3  christos 	  return NULL;
    236   1.3  christos 	}
    237   1.3  christos 
    238   1.3  christos       path = alloca (strlen (origin) + 1 + strlen (file) + 1);
    239   1.3  christos       sprintf (path, "%s/%s", origin, file);
    240   1.3  christos       fd = open (path, O_RDONLY);
    241   1.3  christos     }
    242   1.3  christos 
    243   1.3  christos   if (fd < 0)
    244   1.3  christos     fd = open (file, O_RDONLY);
    245   1.1  christos 
    246   1.1  christos   if (fd < 0)
    247   1.1  christos     {
    248   1.1  christos       perror ("fopen failed.");
    249   1.3  christos       return NULL;
    250   1.1  christos     }
    251   1.1  christos 
    252   1.1  christos   fsize = lseek (fd, 0, SEEK_END);
    253   1.1  christos 
    254   1.1  christos   if (fsize < 0)
    255   1.1  christos     {
    256   1.1  christos       perror ("lseek failed.");
    257   1.3  christos       return NULL;
    258   1.1  christos     }
    259   1.1  christos 
    260   1.1  christos   addr = (uint8_t *) mmap (NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
    261   1.9  christos   if (addr == MAP_FAILED)
    262   1.1  christos     {
    263   1.1  christos       perror ("mmap failed.");
    264   1.3  christos       return NULL;
    265   1.1  christos     }
    266   1.1  christos 
    267   1.1  christos   /* Check if the lib is an ELF file.  */
    268   1.1  christos   ehdr = (Elf_External_Ehdr *) addr;
    269   1.1  christos   if (ehdr->e_ident[EI_MAG0] != ELFMAG0
    270   1.1  christos       || ehdr->e_ident[EI_MAG1] != ELFMAG1
    271   1.1  christos       || ehdr->e_ident[EI_MAG2] != ELFMAG2
    272   1.1  christos       || ehdr->e_ident[EI_MAG3] != ELFMAG3)
    273   1.1  christos     {
    274   1.1  christos       printf ("Not an ELF file: %x\n", ehdr->e_ident[EI_MAG0]);
    275   1.3  christos       return NULL;
    276   1.1  christos     }
    277   1.1  christos 
    278   1.1  christos   if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
    279   1.1  christos     {
    280   1.1  christos       if (sizeof (void *) != 4)
    281   1.1  christos 	{
    282   1.1  christos 	  printf ("Architecture mismatch.");
    283   1.3  christos 	  return NULL;
    284   1.1  christos 	}
    285   1.1  christos     }
    286   1.1  christos   else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
    287   1.1  christos     {
    288   1.1  christos       if (sizeof (void *) != 8)
    289   1.1  christos 	{
    290   1.1  christos 	  printf ("Architecture mismatch.");
    291   1.3  christos 	  return NULL;
    292   1.1  christos 	}
    293   1.1  christos     }
    294   1.1  christos 
    295   1.3  christos   lib = malloc (sizeof (struct library));
    296   1.3  christos   if (lib == NULL)
    297   1.3  christos     {
    298   1.3  christos       printf ("malloc failed.");
    299   1.3  christos       return NULL;
    300   1.3  christos     }
    301   1.3  christos 
    302   1.3  christos   lib->fd = fd;
    303   1.3  christos 
    304   1.1  christos   /* Load the program segments.  For the sake of simplicity
    305   1.1  christos      assume that no reallocation is needed.  */
    306   1.1  christos   phdr = (Elf_External_Phdr *) (addr + GET (ehdr, e_phoff));
    307   1.1  christos   for (i = 0; i < GET (ehdr, e_phnum); i++, phdr++)
    308   1.1  christos     {
    309   1.1  christos       if (GET (phdr, p_type) == PT_LOAD)
    310   1.1  christos 	{
    311   1.1  christos 	  struct segment *next_seg = load (addr, phdr, tail_seg);
    312   1.1  christos 	  if (next_seg == 0)
    313   1.1  christos 	    continue;
    314   1.1  christos 	  tail_seg = next_seg;
    315   1.1  christos 	  if (head_seg == 0)
    316   1.1  christos 	    head_seg = next_seg;
    317   1.1  christos 	}
    318   1.1  christos     }
    319   1.3  christos   lib->ehdr = ehdr;
    320   1.3  christos   lib->segments = head_seg;
    321   1.3  christos   return lib;
    322   1.3  christos }
    323   1.3  christos 
    324   1.3  christos int
    325   1.3  christos get_text_addr (struct library *lib, void **text_addr)
    326   1.3  christos {
    327   1.3  christos   Elf_External_Shdr *text;
    328   1.3  christos 
    329   1.3  christos   /* Get the text section.  */
    330   1.3  christos   text = find_shdr (lib->ehdr, ".text");
    331   1.3  christos   if (text == NULL)
    332   1.3  christos     return -1;
    333   1.3  christos 
    334   1.3  christos   if (translate_offset (GET (text, sh_offset), lib->segments, text_addr)
    335   1.3  christos       != 0)
    336   1.3  christos     return -1;
    337   1.3  christos 
    338   1.1  christos   return 0;
    339   1.1  christos }
    340   1.1  christos 
    341   1.1  christos /* Return the section-header table.  */
    342   1.1  christos 
    343   1.1  christos Elf_External_Shdr *
    344   1.1  christos find_shdrtab (Elf_External_Ehdr *ehdr)
    345   1.1  christos {
    346   1.1  christos   return (Elf_External_Shdr *) (((uint8_t *) ehdr) + GET (ehdr, e_shoff));
    347   1.1  christos }
    348   1.1  christos 
    349   1.1  christos /* Return the string table of the section headers.  */
    350   1.1  christos 
    351   1.1  christos const char *
    352   1.1  christos find_shstrtab (Elf_External_Ehdr *ehdr, uint64_t *size)
    353   1.1  christos {
    354   1.1  christos   const Elf_External_Shdr *shdr;
    355   1.1  christos   const Elf_External_Shdr *shstr;
    356   1.1  christos 
    357   1.1  christos   if (GET (ehdr, e_shnum) <= GET (ehdr, e_shstrndx))
    358   1.1  christos     {
    359   1.1  christos       printf ("The index of the string table is corrupt.");
    360   1.1  christos       return NULL;
    361   1.1  christos     }
    362   1.1  christos 
    363   1.1  christos   shdr = find_shdrtab (ehdr);
    364   1.1  christos 
    365   1.1  christos   shstr = &shdr[GET (ehdr, e_shstrndx)];
    366   1.1  christos   *size = GET (shstr, sh_size);
    367   1.1  christos   return ((const char *) ehdr) + GET (shstr, sh_offset);
    368   1.1  christos }
    369   1.1  christos 
    370   1.1  christos /* Return the string table named SECTION.  */
    371   1.1  christos 
    372   1.1  christos const char *
    373   1.1  christos find_strtab (Elf_External_Ehdr *ehdr,
    374   1.1  christos 	     const char *section, uint64_t *strtab_size)
    375   1.1  christos {
    376   1.1  christos   uint64_t shstrtab_size = 0;
    377   1.1  christos   const char *shstrtab;
    378   1.1  christos   uint64_t i;
    379   1.1  christos   const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
    380   1.1  christos 
    381   1.1  christos   /* Get the string table of the section headers.  */
    382   1.1  christos   shstrtab = find_shstrtab (ehdr, &shstrtab_size);
    383   1.1  christos   if (shstrtab == NULL)
    384   1.1  christos     return NULL;
    385   1.1  christos 
    386   1.1  christos   for (i = 0; i < GET (ehdr, e_shnum); i++)
    387   1.1  christos     {
    388   1.1  christos       uint64_t name = GET (shdr + i, sh_name);
    389   1.1  christos       if (GET (shdr + i, sh_type) == SHT_STRTAB && name <= shstrtab_size
    390   1.1  christos 	  && strcmp ((const char *) &shstrtab[name], section) == 0)
    391   1.1  christos 	{
    392   1.1  christos 	  *strtab_size = GET (shdr + i, sh_size);
    393   1.1  christos 	  return ((const char *) ehdr) + GET (shdr + i, sh_offset);
    394   1.1  christos 	}
    395   1.1  christos 
    396   1.1  christos     }
    397   1.1  christos   return NULL;
    398   1.1  christos }
    399   1.1  christos 
    400   1.1  christos /* Return the section header named SECTION.  */
    401   1.1  christos 
    402   1.3  christos static Elf_External_Shdr *
    403   1.1  christos find_shdr (Elf_External_Ehdr *ehdr, const char *section)
    404   1.1  christos {
    405   1.1  christos   uint64_t shstrtab_size = 0;
    406   1.1  christos   const char *shstrtab;
    407   1.1  christos   uint64_t i;
    408   1.1  christos 
    409   1.1  christos   /* Get the string table of the section headers.  */
    410   1.1  christos   shstrtab = find_shstrtab (ehdr, &shstrtab_size);
    411   1.1  christos   if (shstrtab == NULL)
    412   1.1  christos     return NULL;
    413   1.1  christos 
    414   1.1  christos   Elf_External_Shdr *shdr = find_shdrtab (ehdr);
    415   1.1  christos   for (i = 0; i < GET (ehdr, e_shnum); i++)
    416   1.1  christos     {
    417   1.1  christos       uint64_t name = GET (shdr + i, sh_name);
    418   1.1  christos       if (name <= shstrtab_size)
    419   1.1  christos 	{
    420   1.1  christos 	  if (strcmp ((const char *) &shstrtab[name], section) == 0)
    421   1.1  christos 	    return &shdr[i];
    422   1.1  christos 	}
    423   1.1  christos 
    424   1.1  christos     }
    425   1.1  christos   return NULL;
    426   1.1  christos }
    427   1.1  christos 
    428   1.1  christos /* Return the symbol table.  */
    429   1.1  christos 
    430   1.3  christos static Elf_External_Sym *
    431   1.1  christos find_symtab (Elf_External_Ehdr *ehdr, uint64_t *symtab_size)
    432   1.1  christos {
    433   1.1  christos   uint64_t i;
    434   1.1  christos   const Elf_External_Shdr *shdr = find_shdrtab (ehdr);
    435   1.1  christos 
    436   1.1  christos   for (i = 0; i < GET (ehdr, e_shnum); i++)
    437   1.1  christos     {
    438   1.1  christos       if (GET (shdr + i, sh_type) == SHT_SYMTAB)
    439   1.1  christos 	{
    440   1.1  christos 	  *symtab_size = GET (shdr + i, sh_size) / sizeof (Elf_External_Sym);
    441   1.1  christos 	  return (Elf_External_Sym *) (((const char *) ehdr) +
    442   1.1  christos 				       GET (shdr + i, sh_offset));
    443   1.1  christos 	}
    444   1.1  christos     }
    445   1.1  christos   return NULL;
    446   1.1  christos }
    447   1.1  christos 
    448   1.1  christos /* Translate a file offset to an address in a loaded segment.   */
    449   1.1  christos 
    450   1.3  christos static int
    451   1.1  christos translate_offset (uint64_t file_offset, struct segment *seg, void **addr)
    452   1.1  christos {
    453   1.1  christos   while (seg)
    454   1.1  christos     {
    455   1.1  christos       uint64_t p_from, p_to;
    456   1.1  christos 
    457   1.1  christos       Elf_External_Phdr *phdr = seg->phdr;
    458   1.1  christos 
    459   1.1  christos       if (phdr == NULL)
    460   1.1  christos 	{
    461   1.1  christos 	  seg = seg->next;
    462   1.1  christos 	  continue;
    463   1.1  christos 	}
    464   1.1  christos 
    465   1.1  christos       p_from = GET (phdr, p_offset);
    466   1.1  christos       p_to = p_from + GET (phdr, p_filesz);
    467   1.1  christos 
    468   1.1  christos       if (p_from <= file_offset && file_offset < p_to)
    469   1.1  christos 	{
    470   1.1  christos 	  *addr = (void *) (seg->mapped_addr + (file_offset - p_from));
    471   1.1  christos 	  return 0;
    472   1.1  christos 	}
    473   1.1  christos       seg = seg->next;
    474   1.1  christos     }
    475   1.1  christos 
    476   1.1  christos   return -1;
    477   1.1  christos }
    478   1.1  christos 
    479   1.1  christos /* Lookup the address of FUNC.  */
    480   1.1  christos 
    481   1.1  christos int
    482   1.3  christos lookup_function (struct library *lib, const char *func, void **addr)
    483   1.1  christos {
    484   1.1  christos   const char *strtab;
    485   1.1  christos   uint64_t strtab_size = 0;
    486   1.1  christos   Elf_External_Sym *symtab;
    487   1.1  christos   uint64_t symtab_size = 0;
    488   1.1  christos   uint64_t i;
    489   1.3  christos   Elf_External_Ehdr *ehdr = lib->ehdr;
    490   1.3  christos   struct segment *seg = lib->segments;
    491   1.1  christos 
    492   1.1  christos   /* Get the string table for the symbols.  */
    493   1.1  christos   strtab = find_strtab (ehdr, ".strtab", &strtab_size);
    494   1.1  christos   if (strtab == NULL)
    495   1.1  christos     {
    496   1.1  christos       printf (".strtab not found.");
    497   1.1  christos       return -1;
    498   1.1  christos     }
    499   1.1  christos 
    500   1.1  christos   /* Get the symbol table.  */
    501   1.1  christos   symtab = find_symtab (ehdr, &symtab_size);
    502   1.1  christos   if (symtab == NULL)
    503   1.1  christos     {
    504   1.1  christos       printf ("symbol table not found.");
    505   1.1  christos       return -1;
    506   1.1  christos     }
    507   1.1  christos 
    508   1.1  christos   for (i = 0; i < symtab_size; i++)
    509   1.1  christos     {
    510   1.1  christos       Elf_External_Sym *sym = &symtab[i];
    511   1.1  christos 
    512   1.1  christos       if (elf_st_type (GET (sym, st_info)) != STT_FUNC)
    513   1.1  christos 	continue;
    514   1.1  christos 
    515   1.1  christos       if (GET (sym, st_name) < strtab_size)
    516   1.1  christos 	{
    517   1.1  christos 	  const char *name = &strtab[GET (sym, st_name)];
    518   1.1  christos 	  if (strcmp (name, func) == 0)
    519   1.1  christos 	    {
    520   1.1  christos 
    521   1.1  christos 	      uint64_t offset = GET (sym, st_value);
    522   1.1  christos 	      return translate_offset (offset, seg, addr);
    523   1.1  christos 	    }
    524   1.1  christos 	}
    525   1.1  christos     }
    526   1.1  christos 
    527   1.1  christos   return -1;
    528   1.1  christos }
    529