1 /* Return string pointer from string section.
2 Copyright (C) 1998-2002, 2004, 2008, 2009, 2015 Red Hat, Inc.
3 This file is part of elfutils.
4 Contributed 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 <libelf.h>
35 #include <stddef.h>
36
37 #include "libelfP.h"
38
39
40 static void *
get_zdata(Elf_Scn * strscn)41 get_zdata (Elf_Scn *strscn)
42 {
43 size_t zsize, zalign;
44 void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
45 if (zdata == NULL)
46 return NULL;
47
48 strscn->zdata_base = zdata;
49 strscn->zdata_size = zsize;
50 strscn->zdata_align = zalign;
51
52 return zdata;
53 }
54
55 char *
elf_strptr(Elf * elf,size_t idx,size_t offset)56 elf_strptr (Elf *elf, size_t idx, size_t offset)
57 {
58 if (elf == NULL)
59 return NULL;
60
61 if (elf->kind != ELF_K_ELF)
62 {
63 __libelf_seterrno (ELF_E_INVALID_HANDLE);
64 return NULL;
65 }
66
67 rwlock_rdlock (elf->lock);
68
69 char *result = NULL;
70 Elf_Scn *strscn;
71
72 /* Find the section in the list. */
73 Elf_ScnList *runp = (elf->class == ELFCLASS32
74 || (offsetof (struct Elf, state.elf32.scns)
75 == offsetof (struct Elf, state.elf64.scns))
76 ? &elf->state.elf32.scns : &elf->state.elf64.scns);
77 while (1)
78 {
79 if (idx < runp->max)
80 {
81 if (idx < runp->cnt)
82 strscn = &runp->data[idx];
83 else
84 {
85 __libelf_seterrno (ELF_E_INVALID_INDEX);
86 goto out;
87 }
88 break;
89 }
90
91 idx -= runp->max;
92
93 runp = runp->next;
94 if (runp == NULL)
95 {
96 __libelf_seterrno (ELF_E_INVALID_INDEX);
97 goto out;
98 }
99 }
100
101 size_t sh_size = 0;
102 if (elf->class == ELFCLASS32)
103 {
104 Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
105 if (unlikely (shdr->sh_type != SHT_STRTAB))
106 {
107 /* This is no string section. */
108 __libelf_seterrno (ELF_E_INVALID_SECTION);
109 goto out;
110 }
111
112 if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
113 sh_size = shdr->sh_size;
114 else
115 {
116 if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
117 goto out;
118 sh_size = strscn->zdata_size;
119 }
120
121 if (unlikely (offset >= sh_size))
122 {
123 /* The given offset is too big, it is beyond this section. */
124 __libelf_seterrno (ELF_E_OFFSET_RANGE);
125 goto out;
126 }
127 }
128 else
129 {
130 Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
131 if (unlikely (shdr->sh_type != SHT_STRTAB))
132 {
133 /* This is no string section. */
134 __libelf_seterrno (ELF_E_INVALID_SECTION);
135 goto out;
136 }
137
138 if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
139 sh_size = shdr->sh_size;
140 else
141 {
142 if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
143 goto out;
144 sh_size = strscn->zdata_size;
145 }
146
147 if (unlikely (offset >= sh_size))
148 {
149 /* The given offset is too big, it is beyond this section. */
150 __libelf_seterrno (ELF_E_OFFSET_RANGE);
151 goto out;
152 }
153 }
154
155 if (strscn->rawdata_base == NULL && ! strscn->data_read)
156 {
157 rwlock_unlock (elf->lock);
158 rwlock_wrlock (elf->lock);
159 if (strscn->rawdata_base == NULL && ! strscn->data_read
160 /* Read the section data. */
161 && __libelf_set_rawdata_wrlock (strscn) != 0)
162 goto out;
163 }
164
165 if (unlikely (strscn->zdata_base != NULL))
166 {
167 /* Make sure the string is NUL terminated. Start from the end,
168 which very likely is a NUL char. */
169 if (likely (memrchr (&strscn->zdata_base[offset],
170 '\0', sh_size - offset) != NULL))
171 result = &strscn->zdata_base[offset];
172 else
173 __libelf_seterrno (ELF_E_INVALID_INDEX);
174 }
175 else if (likely (strscn->data_list_rear == NULL))
176 {
177 // XXX The above is currently correct since elf_newdata will
178 // make sure to convert the rawdata into the datalist if
179 // necessary. But it would be more efficient to keep the rawdata
180 // unconverted and only then iterate over the rest of the (newly
181 // added data) list. Note that when the ELF file is mmapped
182 // rawdata_base can be set while rawdata.d hasn't been
183 // initialized yet (when data_read is zero). So we cannot just
184 // look at the rawdata.d.d_size.
185
186 /* Make sure the string is NUL terminated. Start from the end,
187 which very likely is a NUL char. */
188 if (likely (memrchr (&strscn->rawdata_base[offset],
189 '\0', sh_size - offset) != NULL))
190 result = &strscn->rawdata_base[offset];
191 else
192 __libelf_seterrno (ELF_E_INVALID_INDEX);
193 }
194 else
195 {
196 /* This is a file which is currently created. Use the list of
197 data blocks. */
198 struct Elf_Data_List *dl = &strscn->data_list;
199 while (dl != NULL)
200 {
201 if (offset >= (size_t) dl->data.d.d_off
202 && offset < dl->data.d.d_off + dl->data.d.d_size)
203 {
204 /* Make sure the string is NUL terminated. Start from
205 the end, which very likely is a NUL char. */
206 if (likely (memrchr ((char *) dl->data.d.d_buf
207 + (offset - dl->data.d.d_off), '\0',
208 (dl->data.d.d_size
209 - (offset - dl->data.d.d_off))) != NULL))
210 result = ((char *) dl->data.d.d_buf
211 + (offset - dl->data.d.d_off));
212 else
213 __libelf_seterrno (ELF_E_INVALID_INDEX);
214 break;
215 }
216
217 dl = dl->next;
218 }
219 }
220
221 out:
222 rwlock_unlock (elf->lock);
223
224 return result;
225 }
226 INTDEF(elf_strptr)
227