Back to index

glibc  2.9
check-localplt.c
Go to the documentation of this file.
00001 /* Show local PLT use in DSOs.
00002    Copyright (C) 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contribute by Ulrich Drepper <drepper@redhat.com>. 2006.
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 #include <byteswap.h>
00022 #include <elf.h>
00023 #include <endian.h>
00024 #include <fcntl.h>
00025 #include <stdint.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 
00031 
00032 #ifdef BITS
00033 
00034 # define AB(name) _AB (name, BITS)
00035 # define _AB(name, bits) __AB (name, bits)
00036 # define __AB(name, bits) name##bits
00037 # define E(name) _E (name, BITS)
00038 # define _E(name, bits) __E (name, bits)
00039 # define __E(name, bits) Elf##bits##_##name
00040 # define EE(name) _EE (name, BITS)
00041 # define _EE(name, bits) __EE (name, bits)
00042 # define __EE(name, bits) ELF##bits##_##name
00043 # define SWAP(val) \
00044   ({ __typeof (val) __res;                                           \
00045      if (((ehdr.e_ident[EI_DATA] == ELFDATA2MSB                             \
00046           && BYTE_ORDER == LITTLE_ENDIAN)                            \
00047          || (ehdr.e_ident[EI_DATA] == ELFDATA2LSB                           \
00048              && BYTE_ORDER == BIG_ENDIAN))                                  \
00049         && sizeof (val) != 1)                                               \
00050        {                                                             \
00051         if (sizeof (val) == 2)                                              \
00052           __res = bswap_16 (val);                                    \
00053         else if (sizeof (val) == 4)                                         \
00054           __res = bswap_32 (val);                                    \
00055         else                                                         \
00056           __res = bswap_64 (val);                                    \
00057        }                                                             \
00058      else                                                            \
00059        __res = (val);                                                       \
00060      __res; })
00061 
00062 
00063 static int
00064 AB(handle_file) (const char *fname, int fd)
00065 {
00066   E(Ehdr) ehdr;
00067 
00068   if (pread (fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
00069     {
00070     read_error:
00071       printf ("%s: read error: %m\n", fname);
00072       return 1;
00073     }
00074 
00075   const size_t phnum = SWAP (ehdr.e_phnum);
00076   const size_t phentsize = SWAP (ehdr.e_phentsize);
00077 
00078   /* Read the program header.  */
00079   E(Phdr) *phdr = alloca (phentsize * phnum);
00080   if (pread (fd, phdr, phentsize * phnum, SWAP (ehdr.e_phoff))
00081       != phentsize * phnum)
00082     goto read_error;
00083 
00084   /* Search for the PT_DYNAMIC entry.  */
00085   size_t cnt;
00086   E(Phdr) *dynphdr = NULL;
00087   for (cnt = 0; cnt < phnum; ++cnt)
00088     if (SWAP (phdr[cnt].p_type) == PT_DYNAMIC)
00089       {
00090        dynphdr = &phdr[cnt];
00091        break;
00092       }
00093 
00094   if (dynphdr == NULL)
00095     {
00096       printf ("%s: no DYNAMIC segment found\n", fname);
00097       return 1;
00098     }
00099 
00100   /* Read the dynamic segment.  */
00101   size_t pmemsz = SWAP(dynphdr->p_memsz);
00102   E(Dyn) *dyn = alloca (pmemsz);
00103   if (pread64 (fd, dyn, pmemsz, SWAP(dynphdr->p_offset)) != pmemsz)
00104     goto read_error;
00105 
00106   /* Search for an DT_PLTREL, DT_JMPREL, DT_PLTRELSZ, DT_STRTAB,
00107      DT_STRSZ, and DT_SYMTAB entries.  */
00108   size_t pltrel_idx = SIZE_MAX;
00109   size_t jmprel_idx = SIZE_MAX;
00110   size_t pltrelsz_idx = SIZE_MAX;
00111   size_t strtab_idx = SIZE_MAX;
00112   size_t strsz_idx = SIZE_MAX;
00113   size_t symtab_idx = SIZE_MAX;
00114   for (cnt = 0; (cnt + 1) * sizeof (E(Dyn)) - 1 < pmemsz; ++cnt)
00115     {
00116       unsigned int tag = SWAP (dyn[cnt].d_tag);
00117 
00118       if (tag == DT_NULL)
00119        /* We reached the end.  */
00120        break;
00121 
00122       if (tag == DT_PLTREL)
00123        pltrel_idx = cnt;
00124       else if (tag == DT_JMPREL)
00125        jmprel_idx = cnt;
00126       else if (tag == DT_PLTRELSZ)
00127        pltrelsz_idx = cnt;
00128       else if (tag == DT_STRTAB)
00129        strtab_idx = cnt;
00130       else if (tag == DT_STRSZ)
00131        strsz_idx = cnt;
00132       else if (tag == DT_SYMTAB)
00133        symtab_idx = cnt;
00134     }
00135 
00136   if (pltrel_idx == SIZE_MAX || jmprel_idx == SIZE_MAX
00137       || pltrelsz_idx == SIZE_MAX || strtab_idx == SIZE_MAX
00138       || strsz_idx == SIZE_MAX || symtab_idx == SIZE_MAX)
00139     {
00140       puts ("not all PLT information found");
00141       return 1;
00142     }
00143 
00144   E(Xword) relsz = SWAP (dyn[pltrelsz_idx].d_un.d_val);
00145 
00146   void *relmem = NULL;
00147   char *strtab = NULL;
00148   E(Xword) symtab_offset = 0;
00149 
00150   /* Find the offset of DT_JMPREL and load the data.  */
00151   for (cnt = 0; cnt < phnum; ++cnt)
00152     if (SWAP (phdr[cnt].p_type) == PT_LOAD)
00153       {
00154        E(Addr) vaddr = SWAP (phdr[cnt].p_vaddr);
00155        E(Xword) memsz = SWAP (phdr[cnt].p_memsz);
00156 
00157        if (vaddr <= SWAP (dyn[jmprel_idx].d_un.d_val)
00158            && vaddr + memsz >= SWAP (dyn[jmprel_idx].d_un.d_val) + relsz)
00159          {
00160            relmem = alloca (SWAP (dyn[pltrelsz_idx].d_un.d_val));
00161            if (pread64 (fd, relmem, relsz,
00162                       SWAP (phdr[cnt].p_offset)
00163                       + SWAP (dyn[jmprel_idx].d_un.d_val) - vaddr)
00164               != relsz)
00165              {
00166               puts ("cannot read JMPREL");
00167               return 1;
00168              }
00169          }
00170 
00171        if (vaddr <= SWAP (dyn[symtab_idx].d_un.d_val)
00172            && vaddr + memsz > SWAP (dyn[symtab_idx].d_un.d_val))
00173          symtab_offset = (SWAP (phdr[cnt].p_offset)
00174                         + SWAP (dyn[symtab_idx].d_un.d_val) - vaddr);
00175 
00176        if (vaddr <= SWAP (dyn[strtab_idx].d_un.d_val)
00177            && vaddr + memsz >= (SWAP (dyn[strtab_idx].d_un.d_val)
00178                              + SWAP(dyn[strsz_idx].d_un.d_val)))
00179          {
00180            strtab = alloca (SWAP(dyn[strsz_idx].d_un.d_val));
00181            if (pread64 (fd, strtab, SWAP(dyn[strsz_idx].d_un.d_val),
00182                       SWAP (phdr[cnt].p_offset)
00183                       + SWAP (dyn[strtab_idx].d_un.d_val) - vaddr)
00184               != SWAP(dyn[strsz_idx].d_un.d_val))
00185              {
00186               puts ("cannot read STRTAB");
00187               return 1;
00188              }
00189          }
00190       }
00191 
00192   if (relmem == NULL || strtab == NULL || symtab_offset == 0)
00193     {
00194       puts ("couldn't load PLT data");
00195       return 1;
00196     }
00197 
00198   if (SWAP (dyn[pltrel_idx].d_un.d_val) == DT_RELA)
00199     for (E(Rela) *rela = relmem; (char *) rela - (char *) relmem < relsz;
00200         ++rela)
00201       {
00202        E(Sym) sym;
00203 
00204        if (pread64 (fd, &sym, sizeof (sym),
00205                    symtab_offset
00206                    + EE(R_SYM) (SWAP (rela->r_info)) * sizeof (sym))
00207            != sizeof (sym))
00208          {
00209            puts ("cannot read symbol");
00210            return 1;
00211          }
00212 
00213        if (sym.st_value != 0)
00214          /* This symbol is locally defined.  */
00215          printf ("%s: %s\n", basename (fname), strtab + SWAP (sym.st_name));
00216       }
00217   else
00218     for (E(Rel) *rel = relmem; (char *) rel - (char *) relmem < relsz; ++rel)
00219       {
00220        E(Sym) sym;
00221 
00222        if (pread64 (fd, &sym, sizeof (sym),
00223                    symtab_offset
00224                    + EE(R_SYM) (SWAP (rel->r_info)) * sizeof (sym))
00225            != sizeof (sym))
00226          {
00227            puts ("cannot read symbol");
00228            return 1;
00229          }
00230 
00231        if (sym.st_value != 0)
00232          /* This symbol is locally defined.  */
00233          printf ("%s: %s\n", basename (fname), strtab + SWAP (sym.st_name));
00234       }
00235 
00236   return 0;
00237 }
00238 
00239 # undef BITS
00240 #else
00241 
00242 # define BITS 32
00243 # include "check-localplt.c"
00244 
00245 # define BITS 64
00246 # include "check-localplt.c"
00247 
00248 
00249 static int
00250 handle_file (const char *fname)
00251 {
00252   int fd = open (fname, O_RDONLY);
00253   if (fd == -1)
00254     {
00255       printf ("cannot open %s: %m\n", fname);
00256       return 1;
00257     }
00258 
00259   /* Read was is supposed to be the ELF header.  Read the initial
00260      bytes to determine whether this is a 32 or 64 bit file.  */
00261   char ident[EI_NIDENT];
00262   if (read (fd, ident, EI_NIDENT) != EI_NIDENT)
00263     {
00264       printf ("%s: read error: %m\n", fname);
00265       close (fd);
00266       return 1;
00267     }
00268 
00269   if (memcmp (&ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
00270     {
00271       printf ("%s: not an ELF file\n", fname);
00272       close (fd);
00273       return 1;
00274     }
00275 
00276   int result;
00277   if (ident[EI_CLASS] == ELFCLASS64)
00278     result = handle_file64 (fname, fd);
00279   else
00280     result = handle_file32 (fname, fd);
00281 
00282   close (fd);
00283 
00284   return result;
00285 }
00286 
00287 
00288 int
00289 main (int argc, char *argv[])
00290 {
00291   int cnt;
00292   int result = 0;
00293 
00294   for (cnt = 1; cnt < argc; ++cnt)
00295     result |= handle_file (argv[cnt]);
00296 
00297   return result;
00298 }
00299 #endif