Home | History | Annotate | Download | only in libelf
      1 /* Return string pointer from string section.
      2    Copyright (C) 1998-2002, 2004, 2008, 2009, 2015 Red Hat, Inc.
      3    This file is part of elfutils.
      4    Contributed by Ulrich Drepper <drepper (at) redhat.com>, 1998.
      5 
      6    This file is free software; you can redistribute it and/or modify
      7    it under the terms of either
      8 
      9      * the GNU Lesser General Public License as published by the Free
     10        Software Foundation; either version 3 of the License, or (at
     11        your option) any later version
     12 
     13    or
     14 
     15      * the GNU General Public License as published by the Free
     16        Software Foundation; either version 2 of the License, or (at
     17        your option) any later version
     18 
     19    or both in parallel, as here.
     20 
     21    elfutils is distributed in the hope that it will be useful, but
     22    WITHOUT ANY WARRANTY; without even the implied warranty of
     23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     24    General Public License for more details.
     25 
     26    You should have received copies of the GNU General Public License and
     27    the GNU Lesser General Public License along with this program.  If
     28    not, see <http://www.gnu.org/licenses/>.  */
     29 
     30 #ifdef HAVE_CONFIG_H
     31 # include <config.h>
     32 #endif
     33 
     34 #include <libelf.h>
     35 #include <stddef.h>
     36 
     37 #include "libelfP.h"
     38 
     39 
     40 static void *
     41 get_zdata (Elf_Scn *strscn)
     42 {
     43   size_t zsize, zalign;
     44   void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
     45   if (zdata == NULL)
     46     return NULL;
     47 
     48   strscn->zdata_base = zdata;
     49   strscn->zdata_size = zsize;
     50   strscn->zdata_align = zalign;
     51 
     52   return zdata;
     53 }
     54 
     55 char *
     56 elf_strptr (Elf *elf, size_t idx, size_t offset)
     57 {
     58   if (elf == NULL)
     59     return NULL;
     60 
     61   if (elf->kind != ELF_K_ELF)
     62     {
     63       __libelf_seterrno (ELF_E_INVALID_HANDLE);
     64       return NULL;
     65     }
     66 
     67   rwlock_rdlock (elf->lock);
     68 
     69   char *result = NULL;
     70   Elf_Scn *strscn;
     71 
     72   /* Find the section in the list.  */
     73   Elf_ScnList *runp = (elf->class == ELFCLASS32
     74 		       || (offsetof (struct Elf, state.elf32.scns)
     75 			   == offsetof (struct Elf, state.elf64.scns))
     76 		       ? &elf->state.elf32.scns : &elf->state.elf64.scns);
     77   while (1)
     78     {
     79       if (idx < runp->max)
     80 	{
     81 	  if (idx < runp->cnt)
     82 	    strscn = &runp->data[idx];
     83 	  else
     84 	    {
     85 	      __libelf_seterrno (ELF_E_INVALID_INDEX);
     86 	      goto out;
     87 	    }
     88 	  break;
     89 	}
     90 
     91       idx -= runp->max;
     92 
     93       runp = runp->next;
     94       if (runp == NULL)
     95 	{
     96 	  __libelf_seterrno (ELF_E_INVALID_INDEX);
     97 	  goto out;
     98 	}
     99     }
    100 
    101   size_t sh_size = 0;
    102   if (elf->class == ELFCLASS32)
    103     {
    104       Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
    105       if (unlikely (shdr->sh_type != SHT_STRTAB))
    106 	{
    107 	  /* This is no string section.  */
    108 	  __libelf_seterrno (ELF_E_INVALID_SECTION);
    109 	  goto out;
    110 	}
    111 
    112       if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
    113 	sh_size = shdr->sh_size;
    114       else
    115 	{
    116 	  if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
    117 	    goto out;
    118 	  sh_size = strscn->zdata_size;
    119 	}
    120 
    121       if (unlikely (offset >= sh_size))
    122 	{
    123 	  /* The given offset is too big, it is beyond this section.  */
    124 	  __libelf_seterrno (ELF_E_OFFSET_RANGE);
    125 	  goto out;
    126 	}
    127     }
    128   else
    129     {
    130       Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
    131       if (unlikely (shdr->sh_type != SHT_STRTAB))
    132 	{
    133 	  /* This is no string section.  */
    134 	  __libelf_seterrno (ELF_E_INVALID_SECTION);
    135 	  goto out;
    136 	}
    137 
    138       if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
    139 	sh_size = shdr->sh_size;
    140       else
    141 	{
    142 	  if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
    143 	    goto out;
    144 	  sh_size = strscn->zdata_size;
    145 	}
    146 
    147       if (unlikely (offset >= sh_size))
    148 	{
    149 	  /* The given offset is too big, it is beyond this section.  */
    150 	  __libelf_seterrno (ELF_E_OFFSET_RANGE);
    151 	  goto out;
    152 	}
    153     }
    154 
    155   if (strscn->rawdata_base == NULL && ! strscn->data_read)
    156     {
    157       rwlock_unlock (elf->lock);
    158       rwlock_wrlock (elf->lock);
    159       if (strscn->rawdata_base == NULL && ! strscn->data_read
    160 	/* Read the section data.  */
    161 	  && __libelf_set_rawdata_wrlock (strscn) != 0)
    162 	goto out;
    163     }
    164 
    165   if (unlikely (strscn->zdata_base != NULL))
    166     {
    167       /* Make sure the string is NUL terminated.  Start from the end,
    168          which very likely is a NUL char.  */
    169       if (likely (memrchr (&strscn->zdata_base[offset],
    170 			   '\0', sh_size - offset) != NULL))
    171         result = &strscn->zdata_base[offset];
    172       else
    173         __libelf_seterrno (ELF_E_INVALID_INDEX);
    174     }
    175   else if (likely (strscn->data_list_rear == NULL))
    176     {
    177       // XXX The above is currently correct since elf_newdata will
    178       // make sure to convert the rawdata into the datalist if
    179       // necessary. But it would be more efficient to keep the rawdata
    180       // unconverted and only then iterate over the rest of the (newly
    181       // added data) list.  Note that when the ELF file is mmapped
    182       // rawdata_base can be set while rawdata.d hasn't been
    183       // initialized yet (when data_read is zero). So we cannot just
    184       // look at the rawdata.d.d_size.
    185 
    186       /* Make sure the string is NUL terminated.  Start from the end,
    187 	 which very likely is a NUL char.  */
    188       if (likely (memrchr (&strscn->rawdata_base[offset],
    189 			  '\0', sh_size - offset) != NULL))
    190 	result = &strscn->rawdata_base[offset];
    191       else
    192 	__libelf_seterrno (ELF_E_INVALID_INDEX);
    193     }
    194   else
    195     {
    196       /* This is a file which is currently created.  Use the list of
    197 	 data blocks.  */
    198       struct Elf_Data_List *dl = &strscn->data_list;
    199       while (dl != NULL)
    200 	{
    201 	  if (offset >= (size_t) dl->data.d.d_off
    202 	      && offset < dl->data.d.d_off + dl->data.d.d_size)
    203 	    {
    204 	      /* Make sure the string is NUL terminated.  Start from
    205 		 the end, which very likely is a NUL char.  */
    206 	      if (likely (memrchr ((char *) dl->data.d.d_buf
    207 				   + (offset - dl->data.d.d_off), '\0',
    208 				   (dl->data.d.d_size
    209 				    - (offset - dl->data.d.d_off))) != NULL))
    210 		result = ((char *) dl->data.d.d_buf
    211 			  + (offset - dl->data.d.d_off));
    212 	      else
    213 		__libelf_seterrno (ELF_E_INVALID_INDEX);
    214 	      break;
    215 	    }
    216 
    217 	  dl = dl->next;
    218 	}
    219     }
    220 
    221  out:
    222   rwlock_unlock (elf->lock);
    223 
    224   return result;
    225 }
    226 INTDEF(elf_strptr)
    227