• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Return section header.
2    Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014, 2015 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@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 <assert.h>
35 #include <errno.h>
36 #include <stdbool.h>
37 
38 #include "libelfP.h"
39 #include "common.h"
40 
41 #ifndef LIBELFBITS
42 # define LIBELFBITS 32
43 #endif
44 
45 
ElfW2(LIBELFBITS,Shdr)46 static ElfW2(LIBELFBITS,Shdr) *
47 load_shdr_wrlock (Elf_Scn *scn)
48 {
49   ElfW2(LIBELFBITS,Shdr) *result;
50 
51   /* Read the section header table.  */
52   Elf *elf = scn->elf;
53   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
54 
55   /* Try again, maybe the data is there now.  */
56   result = scn->shdr.ELFW(e,LIBELFBITS);
57   if (result != NULL)
58     goto out;
59 
60   size_t shnum;
61   if (__elf_getshdrnum_rdlock (elf, &shnum) != 0
62       || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr)))
63     goto out;
64   size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr));
65 
66   /* Allocate memory for the section headers.  We know the number
67      of entries from the ELF header.  */
68   ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
69     (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
70   if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
71     {
72       __libelf_seterrno (ELF_E_NOMEM);
73       goto out;
74     }
75   elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
76 
77   if (elf->map_address != NULL)
78     {
79       /* First see whether the information in the ELF header is
80 	 valid and it does not ask for too much.  */
81       if (unlikely (ehdr->e_shoff >= elf->maximum_size)
82 	  || unlikely (elf->maximum_size - ehdr->e_shoff < size))
83 	{
84 	  /* Something is wrong.  */
85 	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
86 	  goto free_and_out;
87 	}
88 
89       ElfW2(LIBELFBITS,Shdr) *notcvt;
90 
91       /* All the data is already mapped.  If we could use it
92 	 directly this would already have happened.  Unless
93 	 we allocated the memory ourselves and the ELF_F_MALLOCED
94 	 flag is set.  */
95       void *file_shdr = ((char *) elf->map_address
96 			 + elf->start_offset + ehdr->e_shoff);
97 
98       assert ((elf->flags & ELF_F_MALLOCED)
99 	      || ehdr->e_ident[EI_DATA] != MY_ELFDATA
100 	      || elf->cmd == ELF_C_READ_MMAP
101 	      || (! ALLOW_UNALIGNED
102 		  && ((uintptr_t) file_shdr
103 		      & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
104 
105       /* Now copy the data and at the same time convert the byte order.  */
106       if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
107 	{
108 	  assert ((elf->flags & ELF_F_MALLOCED)
109 		  || elf->cmd == ELF_C_READ_MMAP
110 		  || ! ALLOW_UNALIGNED);
111 	  memcpy (shdr, file_shdr, size);
112 	}
113       else
114 	{
115 	  bool copy = ! (ALLOW_UNALIGNED
116 			 || ((uintptr_t) file_shdr
117 			     & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1))
118 			     == 0);
119 	  if (! copy)
120 	    notcvt = (ElfW2(LIBELFBITS,Shdr) *)
121 	      ((char *) elf->map_address
122 	       + elf->start_offset + ehdr->e_shoff);
123 	  else
124 	    {
125 	      notcvt = (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
126 	      if (unlikely (notcvt == NULL))
127 		{
128 		  __libelf_seterrno (ELF_E_NOMEM);
129 		  goto out;
130 		}
131 	      memcpy (notcvt, ((char *) elf->map_address
132 			       + elf->start_offset + ehdr->e_shoff),
133 		      size);
134 	    }
135 
136 	  for (size_t cnt = 0; cnt < shnum; ++cnt)
137 	    {
138 	      CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
139 	      CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
140 	      CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
141 	      CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
142 	      CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
143 	      CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
144 	      CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
145 	      CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
146 	      CONVERT_TO (shdr[cnt].sh_addralign,
147 			  notcvt[cnt].sh_addralign);
148 	      CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
149 
150 	      /* If this is a section with an extended index add a
151 		 reference in the section which uses the extended
152 		 index.  */
153 	      if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
154 		  && shdr[cnt].sh_link < shnum)
155 		elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
156 		  = cnt;
157 
158 	      /* Set the own shndx_index field in case it has not yet
159 		 been set.  */
160 	      if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
161 		elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
162 		  = -1;
163 	    }
164 
165 	  if (copy)
166 	    free (notcvt);
167 	}
168     }
169   else if (likely (elf->fildes != -1))
170     {
171       /* Read the header.  */
172       ssize_t n = pread_retry (elf->fildes,
173 			       elf->state.ELFW(elf,LIBELFBITS).shdr, size,
174 			       elf->start_offset + ehdr->e_shoff);
175       if (unlikely ((size_t) n != size))
176 	{
177 	  /* Severe problems.  We cannot read the data.  */
178 	  __libelf_seterrno (ELF_E_READ_ERROR);
179 	  goto free_and_out;
180 	}
181 
182       /* If the byte order of the file is not the same as the one
183 	 of the host convert the data now.  */
184       if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
185 	for (size_t cnt = 0; cnt < shnum; ++cnt)
186 	  {
187 	    CONVERT (shdr[cnt].sh_name);
188 	    CONVERT (shdr[cnt].sh_type);
189 	    CONVERT (shdr[cnt].sh_flags);
190 	    CONVERT (shdr[cnt].sh_addr);
191 	    CONVERT (shdr[cnt].sh_offset);
192 	    CONVERT (shdr[cnt].sh_size);
193 	    CONVERT (shdr[cnt].sh_link);
194 	    CONVERT (shdr[cnt].sh_info);
195 	    CONVERT (shdr[cnt].sh_addralign);
196 	    CONVERT (shdr[cnt].sh_entsize);
197 	  }
198     }
199   else
200     {
201       /* The file descriptor was already enabled and not all data was
202 	 read.  Undo the allocation.  */
203       __libelf_seterrno (ELF_E_FD_DISABLED);
204 
205     free_and_out:
206       free (shdr);
207       elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
208       elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
209 
210       goto out;
211     }
212 
213   /* Set the pointers in the `scn's.  */
214   for (size_t cnt = 0; cnt < shnum; ++cnt)
215     elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
216       = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
217 
218   result = scn->shdr.ELFW(e,LIBELFBITS);
219   assert (result != NULL);
220 
221 out:
222   return result;
223 }
224 
225 static bool
scn_valid(Elf_Scn * scn)226 scn_valid (Elf_Scn *scn)
227 {
228   if (scn == NULL)
229     return false;
230 
231   if (unlikely (scn->elf->state.elf.ehdr == NULL))
232     {
233       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
234       return false;
235     }
236 
237   if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
238     {
239       __libelf_seterrno (ELF_E_INVALID_CLASS);
240       return false;
241     }
242 
243   return true;
244 }
245 
ElfW2(LIBELFBITS,Shdr)246 ElfW2(LIBELFBITS,Shdr) *
247 internal_function
248 __elfw2(LIBELFBITS,getshdr_rdlock) (Elf_Scn *scn)
249 {
250   ElfW2(LIBELFBITS,Shdr) *result;
251 
252   if (!scn_valid (scn))
253     return NULL;
254 
255   result = scn->shdr.ELFW(e,LIBELFBITS);
256   if (result == NULL)
257     {
258       rwlock_unlock (scn->elf->lock);
259       rwlock_wrlock (scn->elf->lock);
260       result = scn->shdr.ELFW(e,LIBELFBITS);
261       if (result == NULL)
262 	result = load_shdr_wrlock (scn);
263     }
264 
265   return result;
266 }
267 
ElfW2(LIBELFBITS,Shdr)268 ElfW2(LIBELFBITS,Shdr) *
269 internal_function
270 __elfw2(LIBELFBITS,getshdr_wrlock) (Elf_Scn *scn)
271 {
272   ElfW2(LIBELFBITS,Shdr) *result;
273 
274   if (!scn_valid (scn))
275     return NULL;
276 
277   result = scn->shdr.ELFW(e,LIBELFBITS);
278   if (result == NULL)
279     result = load_shdr_wrlock (scn);
280 
281   return result;
282 }
283 
ElfW2(LIBELFBITS,Shdr)284 ElfW2(LIBELFBITS,Shdr) *
285 elfw2(LIBELFBITS,getshdr) (Elf_Scn *scn)
286 {
287   ElfW2(LIBELFBITS,Shdr) *result;
288 
289   if (!scn_valid (scn))
290     return NULL;
291 
292   rwlock_rdlock (scn->elf->lock);
293   result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
294   rwlock_unlock (scn->elf->lock);
295 
296   return result;
297 }
298