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