Back to index

glibc  2.9
dl-addr.c
Go to the documentation of this file.
00001 /* Locate the shared object symbol nearest a given address.
00002    Copyright (C) 1996-2004, 2005, 2006, 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <dlfcn.h>
00021 #include <stddef.h>
00022 #include <ldsodefs.h>
00023 
00024 
00025 static void
00026 __attribute ((always_inline))
00027 determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
00028               struct link_map **mapp, const ElfW(Sym) **symbolp)
00029 {
00030   /* Now we know what object the address lies in.  */
00031   info->dli_fname = match->l_name;
00032   info->dli_fbase = (void *) match->l_map_start;
00033 
00034   /* If this is the main program the information is incomplete.  */
00035   if (__builtin_expect (match->l_name[0], 'a') == '\0'
00036       && match->l_type == lt_executable)
00037     info->dli_fname = _dl_argv[0];
00038 
00039   const ElfW(Sym) *symtab
00040     = (const ElfW(Sym) *) D_PTR (match, l_info[DT_SYMTAB]);
00041   const char *strtab = (const char *) D_PTR (match, l_info[DT_STRTAB]);
00042 
00043   ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
00044 
00045   const ElfW(Sym) *matchsym = NULL;
00046   if (match->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
00047                   + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] != NULL)
00048     {
00049       /* We look at all symbol table entries referenced by the hash
00050         table.  */
00051       for (Elf_Symndx bucket = 0; bucket < match->l_nbuckets; ++bucket)
00052        {
00053          Elf32_Word symndx = match->l_gnu_buckets[bucket];
00054          if (symndx != 0)
00055            {
00056              const Elf32_Word *hasharr = &match->l_gnu_chain_zero[symndx];
00057 
00058              do
00059               {
00060                 /* The hash table never references local symbols so
00061                    we can omit that test here.  */
00062                 if ((symtab[symndx].st_shndx != SHN_UNDEF
00063                      || symtab[symndx].st_value != 0)
00064                     && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS
00065                     && DL_ADDR_SYM_MATCH (match, &symtab[symndx],
00066                                        matchsym, addr)
00067                     && symtab[symndx].st_name < strtabsize)
00068                   matchsym = (ElfW(Sym) *) &symtab[symndx];
00069 
00070                 ++symndx;
00071               }
00072              while ((*hasharr++ & 1u) == 0);
00073            }
00074        }
00075     }
00076   else
00077     {
00078       const ElfW(Sym) *symtabend;
00079       if (match->l_info[DT_HASH] != NULL)
00080        symtabend = (symtab
00081                    + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]);
00082       else
00083        /* There is no direct way to determine the number of symbols in the
00084           dynamic symbol table and no hash table is present.  The ELF
00085           binary is ill-formed but what shall we do?  Use the beginning of
00086           the string table which generally follows the symbol table.  */
00087        symtabend = (const ElfW(Sym) *) strtab;
00088 
00089       for (; (void *) symtab < (void *) symtabend; ++symtab)
00090        if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
00091             || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
00092            && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
00093            && (symtab->st_shndx != SHN_UNDEF
00094               || symtab->st_value != 0)
00095            && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
00096            && symtab->st_name < strtabsize)
00097          matchsym = (ElfW(Sym) *) symtab;
00098     }
00099 
00100   if (mapp)
00101     *mapp = match;
00102   if (symbolp)
00103     *symbolp = matchsym;
00104 
00105   if (matchsym)
00106     {
00107       /* We found a symbol close by.  Fill in its name and exact
00108         address.  */
00109       lookup_t matchl = LOOKUP_VALUE (match);
00110 
00111       info->dli_sname = strtab + matchsym->st_name;
00112       info->dli_saddr = DL_SYMBOL_ADDRESS (matchl, matchsym);
00113     }
00114   else
00115     {
00116       /* No symbol matches.  We return only the containing object.  */
00117       info->dli_sname = NULL;
00118       info->dli_saddr = NULL;
00119     }
00120 }
00121 
00122 
00123 int
00124 internal_function
00125 _dl_addr (const void *address, Dl_info *info,
00126          struct link_map **mapp, const ElfW(Sym) **symbolp)
00127 {
00128   const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address);
00129   int result = 0;
00130 
00131   /* Protect against concurrent loads and unloads.  */
00132   __rtld_lock_lock_recursive (GL(dl_load_lock));
00133 
00134   /* Find the highest-addressed object that ADDRESS is not below.  */
00135   for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
00136     for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l; l = l->l_next)
00137       if (addr >= l->l_map_start && addr < l->l_map_end
00138          && (l->l_contiguous || _dl_addr_inside_object (l, addr)))
00139        {
00140          determine_info (addr, l, info, mapp, symbolp);
00141          result = 1;
00142          goto out;
00143        }
00144 
00145  out:
00146   __rtld_lock_unlock_recursive (GL(dl_load_lock));
00147 
00148   return result;
00149 }
00150 libc_hidden_def (_dl_addr)
00151 
00152 /* Return non-zero if ADDR lies within one of L's segments.  */
00153 int
00154 internal_function
00155 _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
00156 {
00157   int n = l->l_phnum;
00158   const ElfW(Addr) reladdr = addr - l->l_addr;
00159 
00160   while (--n >= 0)
00161     if (l->l_phdr[n].p_type == PT_LOAD
00162        && reladdr - l->l_phdr[n].p_vaddr >= 0
00163        && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
00164       return 1;
00165   return 0;
00166 }