Back to index

glibc  2.9
readelflib.c
Go to the documentation of this file.
00001 /* Copyright (C) 1999, 2000, 2001, 2002, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
00004                 Jakub Jelinek <jakub@redhat.com>, 1999.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 /* This code is a heavily simplified version of the readelf program
00022    that's part of the current binutils development version.  For architectures
00023    which need to handle both 32bit and 64bit ELF libraries,  this file is
00024    included twice for each arch size.  */
00025 
00026 /* check_ptr checks that a pointer is in the mmaped file and doesn't
00027    point outside it.  */
00028 #undef check_ptr
00029 #define check_ptr(ptr)                                         \
00030 do                                                      \
00031   {                                                     \
00032     if ((void *)(ptr) < file_contents                          \
00033        || (void *)(ptr) > (file_contents+file_length))         \
00034       {                                                        \
00035        error (0, 0, _("file %s is truncated\n"), file_name);   \
00036        return 1;                                        \
00037       }                                                        \
00038   }                                                     \
00039  while (0);
00040 
00041 /* Returns 0 if everything is ok, != 0 in case of error.  */
00042 int
00043 process_elf_file (const char *file_name, const char *lib, int *flag,
00044                 unsigned int *osversion, char **soname, void *file_contents,
00045                 size_t file_length)
00046 {
00047   int i;
00048   unsigned int j;
00049   ElfW(Addr) loadaddr;
00050   unsigned int dynamic_addr;
00051   size_t dynamic_size;
00052   char *program_interpreter;
00053 
00054   ElfW(Ehdr) *elf_header;
00055   ElfW(Phdr) *elf_pheader, *segment;
00056   ElfW(Dyn) *dynamic_segment, *dyn_entry;
00057   char *dynamic_strings;
00058 
00059   elf_header = (ElfW(Ehdr) *) file_contents;
00060   *osversion = 0;
00061 
00062   if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
00063     {
00064       if (opt_verbose)
00065        {
00066          if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
00067            error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
00068          else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
00069            error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
00070          else
00071            error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
00072        }
00073       return 1;
00074     }
00075 
00076   if (elf_header->e_type != ET_DYN)
00077     {
00078       error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
00079             elf_header->e_type);
00080       return 1;
00081     }
00082 
00083   /* Get information from elf program header.  */
00084   elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
00085   check_ptr (elf_pheader);
00086 
00087   /* The library is an elf library, now search for soname and
00088      libc5/libc6.  */
00089   *flag = FLAG_ELF;
00090 
00091   loadaddr = -1;
00092   dynamic_addr = 0;
00093   dynamic_size = 0;
00094   program_interpreter = NULL;
00095   for (i = 0, segment = elf_pheader;
00096        i < elf_header->e_phnum; i++, segment++)
00097     {
00098       check_ptr (segment);
00099 
00100       switch (segment->p_type)
00101        {
00102        case PT_LOAD:
00103          if (loadaddr == (ElfW(Addr)) -1)
00104            loadaddr = segment->p_vaddr - segment->p_offset;
00105          break;
00106 
00107        case PT_DYNAMIC:
00108          if (dynamic_addr)
00109            error (0, 0, _("more than one dynamic segment\n"));
00110 
00111          dynamic_addr = segment->p_offset;
00112          dynamic_size = segment->p_filesz;
00113          break;
00114 
00115        case PT_INTERP:
00116          program_interpreter = (char *) (file_contents + segment->p_offset);
00117          check_ptr (program_interpreter);
00118 
00119          /* Check if this is enough to classify the binary.  */
00120          for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
00121               ++j)
00122            if (strcmp (program_interpreter, interpreters[j].soname) == 0)
00123              {
00124               *flag = interpreters[j].flag;
00125               break;
00126              }
00127          break;
00128 
00129        case PT_NOTE:
00130          if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
00131            {
00132              ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents
00133                                                + segment->p_offset);
00134              ElfW(Addr) size = segment->p_filesz;
00135 
00136              while (abi_note [0] != 4 || abi_note [1] != 16
00137                    || abi_note [2] != 1
00138                    || memcmp (abi_note + 3, "GNU", 4) != 0)
00139               {
00140 #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
00141                 ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
00142                                     + ROUND (abi_note[0])
00143                                     + ROUND (abi_note[1]);
00144 
00145                 if (size - 32 < note_size || note_size == 0)
00146                   {
00147                     size = 0;
00148                     break;
00149                   }
00150                 size -= note_size;
00151                 abi_note = (void *) abi_note + note_size;
00152               }
00153 
00154              if (size == 0)
00155               break;
00156 
00157              *osversion = (abi_note [4] << 24) |
00158                         ((abi_note [5] & 0xff) << 16) |
00159                         ((abi_note [6] & 0xff) << 8) |
00160                         (abi_note [7] & 0xff);
00161            }
00162          break;
00163 
00164        default:
00165          break;
00166        }
00167 
00168     }
00169   if (loadaddr == (ElfW(Addr)) -1)
00170     {
00171       /* Very strange. */
00172       loadaddr = 0;
00173     }
00174 
00175   /* Now we can read the dynamic sections.  */
00176   if (dynamic_size == 0)
00177     return 1;
00178 
00179   dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
00180   check_ptr (dynamic_segment);
00181 
00182   /* Find the string table.  */
00183   dynamic_strings = NULL;
00184   for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
00185        ++dyn_entry)
00186     {
00187       check_ptr (dyn_entry);
00188       if (dyn_entry->d_tag == DT_STRTAB)
00189        {
00190          dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
00191          check_ptr (dynamic_strings);
00192          break;
00193        }
00194     }
00195 
00196   if (dynamic_strings == NULL)
00197     return 1;
00198 
00199   /* Now read the DT_NEEDED and DT_SONAME entries.  */
00200   for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
00201        ++dyn_entry)
00202     {
00203       if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
00204        {
00205          char *name = dynamic_strings + dyn_entry->d_un.d_val;
00206          check_ptr (name);
00207 
00208          if (dyn_entry->d_tag == DT_NEEDED)
00209            {
00210 
00211              if (*flag == FLAG_ELF)
00212               {
00213                 /* Check if this is enough to classify the binary.  */
00214                 for (j = 0;
00215                      j < sizeof (known_libs) / sizeof (known_libs [0]);
00216                      ++j)
00217                   if (strcmp (name, known_libs [j].soname) == 0)
00218                     {
00219                      *flag = known_libs [j].flag;
00220                      break;
00221                     }
00222               }
00223            }
00224 
00225          else if (dyn_entry->d_tag == DT_SONAME)
00226            *soname = xstrdup (name);
00227 
00228          /* Do we have everything we need?  */
00229          if (*soname && *flag != FLAG_ELF)
00230            return 0;
00231        }
00232     }
00233 
00234   return 0;
00235 }