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