Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libelf / elf_getshdrstrndx.c
1 /* Return section index of section header string table.
2    Copyright (C) 2002, 2005, 2009 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2002.
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 <gelf.h>
37 #include <stddef.h>
38 #include <unistd.h>
39
40 #include <system.h>
41 #include "libelfP.h"
42 #include "common.h"
43
44
45 int
46 elf_getshdrstrndx (elf, dst)
47      Elf *elf;
48      size_t *dst;
49 {
50   int result = 0;
51
52   if (elf == NULL)
53     return -1;
54
55   if (unlikely (elf->kind != ELF_K_ELF))
56     {
57       __libelf_seterrno (ELF_E_INVALID_HANDLE);
58       return -1;
59     }
60
61   rwlock_rdlock (elf->lock);
62
63   /* We rely here on the fact that the `elf' element is a common prefix
64      of `elf32' and `elf64'.  */
65   assert (offsetof (struct Elf, state.elf.ehdr)
66           == offsetof (struct Elf, state.elf32.ehdr));
67   assert (sizeof (elf->state.elf.ehdr)
68           == sizeof (elf->state.elf32.ehdr));
69   assert (offsetof (struct Elf, state.elf.ehdr)
70           == offsetof (struct Elf, state.elf64.ehdr));
71   assert (sizeof (elf->state.elf.ehdr)
72           == sizeof (elf->state.elf64.ehdr));
73
74   if (unlikely (elf->state.elf.ehdr == NULL))
75     {
76       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
77       result = -1;
78     }
79   else
80     {
81       Elf32_Word num;
82
83       num = (elf->class == ELFCLASS32
84              ? elf->state.elf32.ehdr->e_shstrndx
85              : elf->state.elf64.ehdr->e_shstrndx);
86
87       /* Determine whether the index is too big to fit in the ELF
88          header.  */
89       if (unlikely (num == SHN_XINDEX))
90         {
91           /* Yes.  Search the zeroth section header.  */
92           if (elf->class == ELFCLASS32)
93             {
94               size_t offset;
95
96               if (elf->state.elf32.scns.data[0].shdr.e32 != NULL)
97                 {
98                   num = elf->state.elf32.scns.data[0].shdr.e32->sh_link;
99                   goto success;
100                 }
101
102               offset = elf->state.elf32.ehdr->e_shoff;
103
104               if (elf->map_address != NULL
105                   && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA
106                   && (ALLOW_UNALIGNED
107                       || (((size_t) ((char *) elf->map_address + offset))
108                           & (__alignof__ (Elf32_Shdr) - 1)) == 0))
109                 /* We can directly access the memory.  */
110                 num = ((Elf32_Shdr *) (elf->map_address + offset))->sh_link;
111               else
112                 {
113                   /* We avoid reading in all the section headers.  Just read
114                      the first one.  */
115                   Elf32_Shdr shdr_mem;
116
117                   if (unlikely (pread_retry (elf->fildes, &shdr_mem,
118                                              sizeof (Elf32_Shdr), offset)
119                                 != sizeof (Elf32_Shdr)))
120                     {
121                       /* We must be able to read this ELF section header.  */
122                       __libelf_seterrno (ELF_E_INVALID_FILE);
123                       result = -1;
124                       goto out;
125                     }
126
127                   if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
128                     CONVERT (shdr_mem.sh_link);
129                   num = shdr_mem.sh_link;
130                 }
131             }
132           else
133             {
134               if (elf->state.elf64.scns.data[0].shdr.e64 != NULL)
135                 {
136                   num = elf->state.elf64.scns.data[0].shdr.e64->sh_link;
137                   goto success;
138                 }
139
140               size_t offset = elf->state.elf64.ehdr->e_shoff;
141
142               if (elf->map_address != NULL
143                   && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA
144                   && (ALLOW_UNALIGNED
145                       || (((size_t) ((char *) elf->map_address + offset))
146                           & (__alignof__ (Elf64_Shdr) - 1)) == 0))
147                 /* We can directly access the memory.  */
148                 num = ((Elf64_Shdr *) (elf->map_address + offset))->sh_link;
149               else
150                 {
151                   /* We avoid reading in all the section headers.  Just read
152                      the first one.  */
153                   Elf64_Shdr shdr_mem;
154
155                   if (unlikely (pread_retry (elf->fildes, &shdr_mem,
156                                              sizeof (Elf64_Shdr), offset)
157                                 != sizeof (Elf64_Shdr)))
158                     {
159                       /* We must be able to read this ELF section header.  */
160                       __libelf_seterrno (ELF_E_INVALID_FILE);
161                       result = -1;
162                       goto out;
163                     }
164
165                   if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
166                     CONVERT (shdr_mem.sh_link);
167                   num = shdr_mem.sh_link;
168                 }
169             }
170         }
171
172       /* Store the result.  */
173     success:
174       *dst = num;
175     }
176
177  out:
178   rwlock_unlock (elf->lock);
179
180   return result;
181 }
182 INTDEF(elf_getshdrstrndx)
183 /* Alias for the deprecated name.  */
184 strong_alias (elf_getshdrstrndx, elf_getshstrndx)