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