1 /* $NetBSD: libdwarf_elf_init.c,v 1.2 2014/03/09 16:58:04 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2009 Kai Wang
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "_libdwarf.h"
30
31 __RCSID("$NetBSD: libdwarf_elf_init.c,v 1.2 2014/03/09 16:58:04 christos Exp $");
32 ELFTC_VCSID("Id: libdwarf_elf_init.c 2972 2013-12-23 06:46:04Z kaiwang27 ");
33
34 static const char *debug_name[] = {
35 ".debug_abbrev",
36 ".debug_aranges",
37 ".debug_frame",
38 ".debug_info",
39 ".debug_types",
40 ".debug_line",
41 ".debug_pubnames",
42 ".eh_frame",
43 ".debug_macinfo",
44 ".debug_str",
45 ".debug_loc",
46 ".debug_pubtypes",
47 ".debug_ranges",
48 ".debug_static_func",
49 ".debug_static_vars",
50 ".debug_typenames",
51 ".debug_weaknames",
52 NULL
53 };
54
55 static void
_dwarf_elf_apply_reloc(Dwarf_Debug dbg,void * buf,Elf_Data * rel_data,Elf_Data * symtab_data,int endian)56 _dwarf_elf_apply_reloc(Dwarf_Debug dbg, void *buf, Elf_Data *rel_data,
57 Elf_Data *symtab_data, int endian)
58 {
59 Dwarf_Unsigned type;
60 GElf_Rela rela;
61 GElf_Sym sym;
62 size_t symndx;
63 uint64_t offset;
64 int size, j;
65
66 j = 0;
67 while (gelf_getrela(rel_data, j++, &rela) != NULL) {
68 symndx = GELF_R_SYM(rela.r_info);
69 type = GELF_R_TYPE(rela.r_info);
70
71 if (gelf_getsym(symtab_data, symndx, &sym) == NULL)
72 continue;
73
74 offset = rela.r_offset;
75 size = _dwarf_get_reloc_size(dbg, type);
76
77 if (endian == ELFDATA2MSB)
78 _dwarf_write_msb(buf, &offset, rela.r_addend, size);
79 else
80 _dwarf_write_lsb(buf, &offset, rela.r_addend, size);
81 }
82 }
83
84 static int
_dwarf_elf_relocate(Dwarf_Debug dbg,Elf * elf,Dwarf_Elf_Data * ed,size_t shndx,size_t symtab,Elf_Data * symtab_data,Dwarf_Error * error)85 _dwarf_elf_relocate(Dwarf_Debug dbg, Elf *elf, Dwarf_Elf_Data *ed, size_t shndx,
86 size_t symtab, Elf_Data *symtab_data, Dwarf_Error *error)
87 {
88 GElf_Ehdr eh;
89 GElf_Shdr sh;
90 Elf_Scn *scn;
91 Elf_Data *rel;
92 int elferr;
93
94 if (symtab == 0 || symtab_data == NULL)
95 return (DW_DLE_NONE);
96
97 if (gelf_getehdr(elf, &eh) == NULL) {
98 DWARF_SET_ELF_ERROR(dbg, error);
99 return (DW_DLE_ELF);
100 }
101
102 scn = NULL;
103 (void) elf_errno();
104 while ((scn = elf_nextscn(elf, scn)) != NULL) {
105 if (gelf_getshdr(scn, &sh) == NULL) {
106 DWARF_SET_ELF_ERROR(dbg, error);
107 return (DW_DLE_ELF);
108 }
109
110 if (sh.sh_type != SHT_RELA || sh.sh_size == 0)
111 continue;
112
113 if (sh.sh_info == shndx && sh.sh_link == symtab) {
114 if ((rel = elf_getdata(scn, NULL)) == NULL) {
115 elferr = elf_errno();
116 if (elferr != 0) {
117 _DWARF_SET_ERROR(NULL, error,
118 DW_DLE_ELF, elferr);
119 return (DW_DLE_ELF);
120 } else
121 return (DW_DLE_NONE);
122 }
123
124 ed->ed_alloc = malloc(ed->ed_data->d_size);
125 if (ed->ed_alloc == NULL) {
126 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
127 return (DW_DLE_MEMORY);
128 }
129 memcpy(ed->ed_alloc, ed->ed_data->d_buf,
130 ed->ed_data->d_size);
131 _dwarf_elf_apply_reloc(dbg, ed->ed_alloc, rel,
132 symtab_data, eh.e_ident[EI_DATA]);
133
134 return (DW_DLE_NONE);
135 }
136 }
137 elferr = elf_errno();
138 if (elferr != 0) {
139 DWARF_SET_ELF_ERROR(dbg, error);
140 return (DW_DLE_ELF);
141 }
142
143 return (DW_DLE_NONE);
144 }
145
146 int
_dwarf_elf_init(Dwarf_Debug dbg,Elf * elf,Dwarf_Error * error)147 _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error)
148 {
149 Dwarf_Obj_Access_Interface *iface;
150 Dwarf_Elf_Object *e;
151 const char *name;
152 GElf_Shdr sh;
153 Elf_Scn *scn;
154 Elf_Data *symtab_data;
155 size_t symtab_ndx;
156 int elferr, i, j, n, ret;
157
158 ret = DW_DLE_NONE;
159
160 if ((iface = calloc(1, sizeof(*iface))) == NULL) {
161 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
162 return (DW_DLE_MEMORY);
163 }
164
165 if ((e = calloc(1, sizeof(*e))) == NULL) {
166 free(iface);
167 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
168 return (DW_DLE_MEMORY);
169 }
170
171 e->eo_elf = elf;
172 e->eo_methods.get_section_info = _dwarf_elf_get_section_info;
173 e->eo_methods.get_byte_order = _dwarf_elf_get_byte_order;
174 e->eo_methods.get_length_size = _dwarf_elf_get_length_size;
175 e->eo_methods.get_pointer_size = _dwarf_elf_get_pointer_size;
176 e->eo_methods.get_section_count = _dwarf_elf_get_section_count;
177 e->eo_methods.load_section = _dwarf_elf_load_section;
178
179 iface->object = e;
180 iface->methods = &e->eo_methods;
181
182 dbg->dbg_iface = iface;
183
184 if (gelf_getehdr(elf, &e->eo_ehdr) == NULL) {
185 DWARF_SET_ELF_ERROR(dbg, error);
186 ret = DW_DLE_ELF;
187 goto fail_cleanup;
188 }
189
190 dbg->dbg_machine = e->eo_ehdr.e_machine;
191
192 if (!elf_getshstrndx(elf, &e->eo_strndx)) {
193 DWARF_SET_ELF_ERROR(dbg, error);
194 ret = DW_DLE_ELF;
195 goto fail_cleanup;
196 }
197
198 n = 0;
199 symtab_ndx = 0;
200 symtab_data = NULL;
201 scn = NULL;
202 (void) elf_errno();
203 while ((scn = elf_nextscn(elf, scn)) != NULL) {
204 if (gelf_getshdr(scn, &sh) == NULL) {
205 DWARF_SET_ELF_ERROR(dbg, error);
206 ret = DW_DLE_ELF;
207 goto fail_cleanup;
208 }
209
210 if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) ==
211 NULL) {
212 DWARF_SET_ELF_ERROR(dbg, error);
213 ret = DW_DLE_ELF;
214 goto fail_cleanup;
215 }
216
217 if (!strcmp(name, ".symtab")) {
218 symtab_ndx = elf_ndxscn(scn);
219 if ((symtab_data = elf_getdata(scn, NULL)) == NULL) {
220 elferr = elf_errno();
221 if (elferr != 0) {
222 _DWARF_SET_ERROR(NULL, error,
223 DW_DLE_ELF, elferr);
224 ret = DW_DLE_ELF;
225 goto fail_cleanup;
226 }
227 }
228 continue;
229 }
230
231 for (i = 0; debug_name[i] != NULL; i++) {
232 if (!strcmp(name, debug_name[i]))
233 n++;
234 }
235 }
236 elferr = elf_errno();
237 if (elferr != 0) {
238 DWARF_SET_ELF_ERROR(dbg, error);
239 return (DW_DLE_ELF);
240 }
241
242 e->eo_seccnt = n;
243
244 if (n == 0)
245 return (DW_DLE_NONE);
246
247 if ((e->eo_data = calloc(n, sizeof(Dwarf_Elf_Data))) == NULL ||
248 (e->eo_shdr = calloc(n, sizeof(GElf_Shdr))) == NULL) {
249 DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
250 ret = DW_DLE_MEMORY;
251 goto fail_cleanup;
252 }
253
254 scn = NULL;
255 j = 0;
256 while ((scn = elf_nextscn(elf, scn)) != NULL && j < n) {
257 if (gelf_getshdr(scn, &sh) == NULL) {
258 DWARF_SET_ELF_ERROR(dbg, error);
259 ret = DW_DLE_ELF;
260 goto fail_cleanup;
261 }
262
263 memcpy(&e->eo_shdr[j], &sh, sizeof(sh));
264
265 if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) ==
266 NULL) {
267 DWARF_SET_ELF_ERROR(dbg, error);
268 ret = DW_DLE_ELF;
269 goto fail_cleanup;
270 }
271
272 for (i = 0; debug_name[i] != NULL; i++) {
273 if (strcmp(name, debug_name[i]))
274 continue;
275
276 (void) elf_errno();
277 if ((e->eo_data[j].ed_data = elf_getdata(scn, NULL)) ==
278 NULL) {
279 elferr = elf_errno();
280 if (elferr != 0) {
281 _DWARF_SET_ERROR(dbg, error,
282 DW_DLE_ELF, elferr);
283 ret = DW_DLE_ELF;
284 goto fail_cleanup;
285 }
286 }
287
288 if (_libdwarf.applyrela) {
289 if (_dwarf_elf_relocate(dbg, elf,
290 &e->eo_data[j], elf_ndxscn(scn), symtab_ndx,
291 symtab_data, error) != DW_DLE_NONE)
292 goto fail_cleanup;
293 }
294
295 j++;
296 }
297 }
298
299 assert(j == n);
300
301 return (DW_DLE_NONE);
302
303 fail_cleanup:
304
305 _dwarf_elf_deinit(dbg);
306
307 return (ret);
308 }
309
310 void
_dwarf_elf_deinit(Dwarf_Debug dbg)311 _dwarf_elf_deinit(Dwarf_Debug dbg)
312 {
313 Dwarf_Obj_Access_Interface *iface;
314 Dwarf_Elf_Object *e;
315 int i;
316
317 iface = dbg->dbg_iface;
318 assert(iface != NULL);
319
320 e = iface->object;
321 assert(e != NULL);
322
323 if (e->eo_data) {
324 for (i = 0; (Dwarf_Unsigned) i < e->eo_seccnt; i++) {
325 if (e->eo_data[i].ed_alloc)
326 free(e->eo_data[i].ed_alloc);
327 }
328 free(e->eo_data);
329 }
330 if (e->eo_shdr)
331 free(e->eo_shdr);
332
333 free(e);
334 free(iface);
335
336 dbg->dbg_iface = NULL;
337 }
338