Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libelf / elf32_getshdr.c
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 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     goto out;
65   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   ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
70     (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
71   if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
72     {
73       __libelf_seterrno (ELF_E_NOMEM);
74       goto out;
75     }
76   elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
77
78   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       void *file_shdr = ((char *) elf->map_address
87                          + elf->start_offset + ehdr->e_shoff);
88
89       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       if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
97         {
98           assert ((elf->flags & ELF_F_MALLOCED) || ! ALLOW_UNALIGNED);
99           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           for (size_t cnt = 0; cnt < shnum; ++cnt)
118             {
119               CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
120               CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
121               CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
122               CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
123               CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
124               CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
125               CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
126               CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
127               CONVERT_TO (shdr[cnt].sh_addralign,
128                           notcvt[cnt].sh_addralign);
129               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               if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
135                   && shdr[cnt].sh_link < shnum)
136                 elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
137                   = cnt;
138
139               /* Set the own shndx_index field in case it has not yet
140                  been set.  */
141               if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
142                 elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
143                   = -1;
144             }
145         }
146     }
147   else if (likely (elf->fildes != -1))
148     {
149       /* Read the header.  */
150       ssize_t n = pread_retry (elf->fildes,
151                                elf->state.ELFW(elf,LIBELFBITS).shdr, size,
152                                elf->start_offset + ehdr->e_shoff);
153       if (unlikely ((size_t) n != size))
154         {
155           /* Severe problems.  We cannot read the data.  */
156           __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       if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
163         for (size_t cnt = 0; cnt < shnum; ++cnt)
164           {
165             CONVERT (shdr[cnt].sh_name);
166             CONVERT (shdr[cnt].sh_type);
167             CONVERT (shdr[cnt].sh_flags);
168             CONVERT (shdr[cnt].sh_addr);
169             CONVERT (shdr[cnt].sh_offset);
170             CONVERT (shdr[cnt].sh_size);
171             CONVERT (shdr[cnt].sh_link);
172             CONVERT (shdr[cnt].sh_info);
173             CONVERT (shdr[cnt].sh_addralign);
174             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       __libelf_seterrno (ELF_E_FD_DISABLED);
182
183     free_and_out:
184       free (shdr);
185       elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
186       elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
187
188       goto out;
189     }
190
191   /* Set the pointers in the `scn's.  */
192   for (size_t cnt = 0; cnt < shnum; ++cnt)
193     elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
194       = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
195
196   result = scn->shdr.ELFW(e,LIBELFBITS);
197   assert (result != NULL);
198
199 out:
200   return result;
201 }
202
203 static bool
204 scn_valid (Elf_Scn *scn)
205 {
206   if (scn == NULL)
207     return false;
208
209   if (unlikely (scn->elf->state.elf.ehdr == NULL))
210     {
211       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
212       return false;
213     }
214
215   if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
216     {
217       __libelf_seterrno (ELF_E_INVALID_CLASS);
218       return false;
219     }
220
221   return true;
222 }
223
224 ElfW2(LIBELFBITS,Shdr) *
225 __elfw2(LIBELFBITS,getshdr_rdlock) (scn)
226      Elf_Scn *scn;
227 {
228   ElfW2(LIBELFBITS,Shdr) *result;
229
230   if (!scn_valid (scn))
231     return NULL;
232
233   result = scn->shdr.ELFW(e,LIBELFBITS);
234   if (result == NULL)
235     {
236       rwlock_unlock (scn->elf->lock);
237       rwlock_wrlock (scn->elf->lock);
238       result = scn->shdr.ELFW(e,LIBELFBITS);
239       if (result == NULL)
240         result = load_shdr_wrlock (scn);
241     }
242
243   return result;
244 }
245
246 ElfW2(LIBELFBITS,Shdr) *
247 __elfw2(LIBELFBITS,getshdr_wrlock) (scn)
248      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     result = load_shdr_wrlock (scn);
258
259   return result;
260 }
261
262 ElfW2(LIBELFBITS,Shdr) *
263 elfw2(LIBELFBITS,getshdr) (scn)
264      Elf_Scn *scn;
265 {
266   ElfW2(LIBELFBITS,Shdr) *result;
267
268   if (!scn_valid (scn))
269     return NULL;
270
271   rwlock_rdlock (scn->elf->lock);
272   result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
273   rwlock_unlock (scn->elf->lock);
274
275   return result;
276 }