Line data Source code
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 :
48 : static ElfW2(LIBELFBITS,Shdr) *
49 1038 : load_shdr_wrlock (Elf_Scn *scn)
50 : {
51 : ElfW2(LIBELFBITS,Shdr) *result;
52 :
53 : /* Read the section header table. */
54 1038 : Elf *elf = scn->elf;
55 1038 : ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
56 :
57 : /* Try again, maybe the data is there now. */
58 1038 : result = scn->shdr.ELFW(e,LIBELFBITS);
59 1038 : if (result != NULL)
60 : goto out;
61 :
62 : size_t shnum;
63 1038 : if (__elf_getshdrnum_rdlock (elf, &shnum) != 0
64 1038 : || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr)))
65 : goto out;
66 1038 : 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 1038 : ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
71 1038 : (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
72 1038 : if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
73 : {
74 0 : __libelf_seterrno (ELF_E_NOMEM);
75 : goto out;
76 : }
77 1038 : elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
78 :
79 1038 : 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 688 : if (unlikely (ehdr->e_shoff >= elf->maximum_size)
84 688 : || unlikely (elf->maximum_size - ehdr->e_shoff < size))
85 : {
86 : /* Something is wrong. */
87 0 : __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 688 : void *file_shdr = ((char *) elf->map_address
98 688 : + elf->start_offset + ehdr->e_shoff);
99 :
100 688 : 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 688 : if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
109 : {
110 538 : 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 3490 : for (size_t cnt = 0; cnt < shnum; ++cnt)
139 : {
140 6980 : CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
141 6980 : CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
142 6980 : CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
143 6980 : CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
144 6980 : CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
145 6980 : CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
146 6980 : CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
147 6980 : CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
148 6980 : CONVERT_TO (shdr[cnt].sh_addralign,
149 : notcvt[cnt].sh_addralign);
150 6980 : 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 3490 : if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
156 0 : && shdr[cnt].sh_link < shnum)
157 : elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
158 0 : = cnt;
159 :
160 : /* Set the own shndx_index field in case it has not yet
161 : been set. */
162 3490 : if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
163 : elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
164 3490 : = -1;
165 : }
166 :
167 : if (copy)
168 : free (notcvt);
169 : }
170 : }
171 350 : else if (likely (elf->fildes != -1))
172 : {
173 : /* Read the header. */
174 350 : ssize_t n = pread_retry (elf->fildes,
175 : elf->state.ELFW(elf,LIBELFBITS).shdr, size,
176 350 : elf->start_offset + ehdr->e_shoff);
177 350 : if (unlikely ((size_t) n != size))
178 : {
179 : /* Severe problems. We cannot read the data. */
180 0 : __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 350 : if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
187 2236 : for (size_t cnt = 0; cnt < shnum; ++cnt)
188 : {
189 4472 : CONVERT (shdr[cnt].sh_name);
190 4472 : CONVERT (shdr[cnt].sh_type);
191 4472 : CONVERT (shdr[cnt].sh_flags);
192 4472 : CONVERT (shdr[cnt].sh_addr);
193 4472 : CONVERT (shdr[cnt].sh_offset);
194 4472 : CONVERT (shdr[cnt].sh_size);
195 4472 : CONVERT (shdr[cnt].sh_link);
196 4472 : CONVERT (shdr[cnt].sh_info);
197 4472 : CONVERT (shdr[cnt].sh_addralign);
198 4472 : 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 0 : __libelf_seterrno (ELF_E_FD_DISABLED);
206 :
207 0 : free_and_out:
208 0 : free (shdr);
209 0 : elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
210 0 : elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
211 :
212 : goto out;
213 : }
214 :
215 : /* Set the pointers in the `scn's. */
216 225299 : for (size_t cnt = 0; cnt < shnum; ++cnt)
217 : elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
218 225299 : = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
219 :
220 1038 : result = scn->shdr.ELFW(e,LIBELFBITS);
221 1038 : assert (result != NULL);
222 :
223 1038 : out:
224 1038 : return result;
225 : }
226 :
227 : static bool
228 410959 : scn_valid (Elf_Scn *scn)
229 : {
230 410959 : if (scn == NULL)
231 : return false;
232 :
233 410958 : if (unlikely (scn->elf->state.elf.ehdr == NULL))
234 : {
235 0 : __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
236 0 : return false;
237 : }
238 :
239 410958 : if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
240 : {
241 0 : __libelf_seterrno (ELF_E_INVALID_CLASS);
242 0 : return false;
243 : }
244 :
245 : return true;
246 : }
247 :
248 : ElfW2(LIBELFBITS,Shdr) *
249 : internal_function
250 205926 : __elfw2(LIBELFBITS,getshdr_rdlock) (Elf_Scn *scn)
251 : {
252 : ElfW2(LIBELFBITS,Shdr) *result;
253 :
254 205926 : if (!scn_valid (scn))
255 : return NULL;
256 :
257 205926 : result = scn->shdr.ELFW(e,LIBELFBITS);
258 205926 : if (result == NULL)
259 : {
260 1032 : rwlock_unlock (scn->elf->lock);
261 : rwlock_wrlock (scn->elf->lock);
262 1032 : result = scn->shdr.ELFW(e,LIBELFBITS);
263 : if (result == NULL)
264 1032 : result = load_shdr_wrlock (scn);
265 : }
266 :
267 : return result;
268 : }
269 :
270 : ElfW2(LIBELFBITS,Shdr) *
271 : internal_function
272 6 : __elfw2(LIBELFBITS,getshdr_wrlock) (Elf_Scn *scn)
273 : {
274 : ElfW2(LIBELFBITS,Shdr) *result;
275 :
276 6 : if (!scn_valid (scn))
277 : return NULL;
278 :
279 6 : result = scn->shdr.ELFW(e,LIBELFBITS);
280 6 : if (result == NULL)
281 6 : result = load_shdr_wrlock (scn);
282 :
283 : return result;
284 : }
285 :
286 : ElfW2(LIBELFBITS,Shdr) *
287 205027 : elfw2(LIBELFBITS,getshdr) (Elf_Scn *scn)
288 : {
289 : ElfW2(LIBELFBITS,Shdr) *result;
290 :
291 205027 : if (!scn_valid (scn))
292 : return NULL;
293 :
294 : rwlock_rdlock (scn->elf->lock);
295 205026 : result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
296 : rwlock_unlock (scn->elf->lock);
297 :
298 205026 : return result;
299 : }
|