(root)/
glibc-2.38/
elf/
dl-addr.c
       1  /* Locate the shared object symbol nearest a given address.
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <dlfcn.h>
      20  #include <stddef.h>
      21  #include <ldsodefs.h>
      22  
      23  
      24  static inline void
      25  __attribute ((always_inline))
      26  determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
      27  		struct link_map **mapp, const ElfW(Sym) **symbolp)
      28  {
      29    /* Now we know what object the address lies in.  */
      30    info->dli_fname = match->l_name;
      31    info->dli_fbase = (void *) match->l_map_start;
      32  
      33    /* If this is the main program the information is incomplete.  */
      34    if (__builtin_expect (match->l_name[0], 'a') == '\0'
      35        && match->l_type == lt_executable)
      36      info->dli_fname = _dl_argv[0];
      37  
      38    const ElfW(Sym) *symtab
      39      = (const ElfW(Sym) *) D_PTR (match, l_info[DT_SYMTAB]);
      40    const char *strtab = (const char *) D_PTR (match, l_info[DT_STRTAB]);
      41  
      42    ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val;
      43  
      44    const ElfW(Sym) *matchsym = NULL;
      45    if (match->l_info[ELF_MACHINE_GNU_HASH_ADDRIDX] != NULL)
      46      {
      47        /* We look at all symbol table entries referenced by the hash
      48  	 table.  */
      49        for (Elf_Symndx bucket = 0; bucket < match->l_nbuckets; ++bucket)
      50  	{
      51  	  Elf32_Word symndx = match->l_gnu_buckets[bucket];
      52  	  if (symndx != 0)
      53  	    {
      54  	      const Elf32_Word *hasharr = &match->l_gnu_chain_zero[symndx];
      55  
      56  	      do
      57  		{
      58  		  /* The hash table never references local symbols so
      59  		     we can omit that test here.  */
      60  		  symndx = ELF_MACHINE_HASH_SYMIDX (match, hasharr);
      61  		  if ((symtab[symndx].st_shndx != SHN_UNDEF
      62  		       || symtab[symndx].st_value != 0)
      63  		      && symtab[symndx].st_shndx != SHN_ABS
      64  		      && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS
      65  		      && DL_ADDR_SYM_MATCH (match, &symtab[symndx],
      66  					    matchsym, addr)
      67  		      && symtab[symndx].st_name < strtabsize)
      68  		    matchsym = (ElfW(Sym) *) &symtab[symndx];
      69  		}
      70  	      while ((*hasharr++ & 1u) == 0);
      71  	    }
      72  	}
      73      }
      74    else if (match->l_info[DT_HASH] != NULL)
      75      {
      76        const ElfW (Sym) *symtabend
      77  	  = (symtab + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]);
      78  
      79        for (; (void *) symtab < (void *) symtabend; ++symtab)
      80  	if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
      81  	     || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
      82  	    && __glibc_likely (!dl_symbol_visibility_binds_local_p (symtab))
      83  	    && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
      84  	    && (symtab->st_shndx != SHN_UNDEF
      85  		|| symtab->st_value != 0)
      86  	    && symtab->st_shndx != SHN_ABS
      87  	    && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
      88  	    && symtab->st_name < strtabsize)
      89  	  matchsym = (ElfW(Sym) *) symtab;
      90      }
      91    /* In the absence of a hash table, treat the object as if it has no symbol.
      92     */
      93  
      94    if (mapp)
      95      *mapp = match;
      96    if (symbolp)
      97      *symbolp = matchsym;
      98  
      99    if (matchsym)
     100      {
     101        /* We found a symbol close by.  Fill in its name and exact
     102  	 address.  */
     103        lookup_t matchl = LOOKUP_VALUE (match);
     104  
     105        info->dli_sname = strtab + matchsym->st_name;
     106        info->dli_saddr = DL_SYMBOL_ADDRESS (matchl, matchsym);
     107      }
     108    else
     109      {
     110        /* No symbol matches.  We return only the containing object.  */
     111        info->dli_sname = NULL;
     112        info->dli_saddr = NULL;
     113      }
     114  }
     115  
     116  
     117  int
     118  _dl_addr (const void *address, Dl_info *info,
     119  	  struct link_map **mapp, const ElfW(Sym) **symbolp)
     120  {
     121    const ElfW(Addr) addr = DL_LOOKUP_ADDRESS (address);
     122    int result = 0;
     123  
     124    /* Protect against concurrent loads and unloads.  */
     125    __rtld_lock_lock_recursive (GL(dl_load_lock));
     126  
     127    struct link_map *l = _dl_find_dso_for_object (addr);
     128  
     129    if (l)
     130      {
     131        determine_info (addr, l, info, mapp, symbolp);
     132        result = 1;
     133      }
     134  
     135    __rtld_lock_unlock_recursive (GL(dl_load_lock));
     136  
     137    return result;
     138  }