xref: /netbsd-src/external/bsd/elftoolchain/dist/libdwarf/libdwarf_elf_init.c (revision 76c7fc5f6b13ed0b1508e6b313e88e59977ed78e)
1 /*	$NetBSD: libdwarf_elf_init.c,v 1.4 2016/03/07 14:32:02 hannken 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.4 2016/03/07 14:32:02 hannken Exp $");
32 ELFTC_VCSID("Id: libdwarf_elf_init.c 3161 2015-02-15 21:43:36Z emaste ");
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
56 _dwarf_elf_write_reloc(Dwarf_Debug dbg, Elf_Data *symtab_data, int endian,
57     void *buf, uint64_t offset, GElf_Xword r_info, GElf_Sxword r_addend,
58     int is_rel)
59 {
60 	GElf_Sym sym;
61 	int size;
62 
63 	if (gelf_getsym(symtab_data, GELF_R_SYM(r_info), &sym) == NULL)
64 		return;
65 	if ((size = _dwarf_get_reloc_size(dbg, GELF_R_TYPE(r_info))) == 0)
66 		return; /* Unknown or non-absolute relocation. */
67 	if (is_rel) {
68 		uint64_t roffset = offset;
69 
70 		if (endian == ELFDATA2MSB)
71 			r_addend = _dwarf_read_msb(buf, &roffset, size);
72 		else
73 			r_addend = _dwarf_read_lsb(buf, &roffset, size);
74 	}
75 	if (endian == ELFDATA2MSB)
76 		_dwarf_write_msb(buf, &offset, sym.st_value + r_addend, size);
77 	else
78 		_dwarf_write_lsb(buf, &offset, sym.st_value + r_addend, size);
79 }
80 
81 static void
82 _dwarf_elf_apply_rel_reloc(Dwarf_Debug dbg, void *buf, Elf_Data *rel_data,
83     Elf_Data *symtab_data, int endian)
84 {
85 	GElf_Rel rel;
86 	int j;
87 
88 	j = 0;
89 	while (gelf_getrel(rel_data, j++, &rel) != NULL)
90 		_dwarf_elf_write_reloc(dbg, symtab_data, endian, buf,
91 		     rel.r_offset, rel.r_info, 0, 1);
92 }
93 
94 static void
95 _dwarf_elf_apply_rela_reloc(Dwarf_Debug dbg, void *buf, Elf_Data *rel_data,
96     Elf_Data *symtab_data, int endian)
97 {
98 	GElf_Rela rela;
99 	int j;
100 
101 	j = 0;
102 	while (gelf_getrela(rel_data, j++, &rela) != NULL)
103 		_dwarf_elf_write_reloc(dbg, symtab_data, endian, buf,
104 		    rela.r_offset, rela.r_info, rela.r_addend, 0);
105 }
106 
107 static int
108 _dwarf_elf_relocate(Dwarf_Debug dbg, Elf *elf, Dwarf_Elf_Data *ed, size_t shndx,
109     size_t symtab, Elf_Data *symtab_data, Dwarf_Error *error)
110 {
111 	GElf_Ehdr eh;
112 	GElf_Shdr sh;
113 	Elf_Scn *scn;
114 	Elf_Data *rel;
115 	int elferr;
116 
117 	if (symtab == 0 || symtab_data == NULL)
118 		return (DW_DLE_NONE);
119 
120 	if (gelf_getehdr(elf, &eh) == NULL) {
121 		DWARF_SET_ELF_ERROR(dbg, error);
122 		return (DW_DLE_ELF);
123 	}
124 
125 	scn = NULL;
126 	(void) elf_errno();
127 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
128 		if (gelf_getshdr(scn, &sh) == NULL) {
129 			DWARF_SET_ELF_ERROR(dbg, error);
130 			return (DW_DLE_ELF);
131 		}
132 
133 		if ((sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA) ||
134 		     sh.sh_size == 0)
135 			continue;
136 
137 		if (sh.sh_info == shndx && sh.sh_link == symtab) {
138 			if ((rel = elf_getdata(scn, NULL)) == NULL) {
139 				elferr = elf_errno();
140 				if (elferr != 0) {
141 					_DWARF_SET_ERROR(NULL, error,
142 					    DW_DLE_ELF, elferr);
143 					return (DW_DLE_ELF);
144 				} else
145 					return (DW_DLE_NONE);
146 			}
147 
148 			ed->ed_alloc = malloc(ed->ed_data->d_size);
149 			if (ed->ed_alloc == NULL) {
150 				DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
151 				return (DW_DLE_MEMORY);
152 			}
153 			memcpy(ed->ed_alloc, ed->ed_data->d_buf,
154 			    ed->ed_data->d_size);
155 			if (sh.sh_type == SHT_REL)
156 				_dwarf_elf_apply_rel_reloc(dbg, ed->ed_alloc,
157 				    rel, symtab_data, eh.e_ident[EI_DATA]);
158 			else
159 				_dwarf_elf_apply_rela_reloc(dbg, ed->ed_alloc,
160 				    rel, symtab_data, eh.e_ident[EI_DATA]);
161 
162 			return (DW_DLE_NONE);
163 		}
164 	}
165 	elferr = elf_errno();
166 	if (elferr != 0) {
167 		DWARF_SET_ELF_ERROR(dbg, error);
168 		return (DW_DLE_ELF);
169 	}
170 
171 	return (DW_DLE_NONE);
172 }
173 
174 int
175 _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error)
176 {
177 	Dwarf_Obj_Access_Interface *iface;
178 	Dwarf_Elf_Object *e;
179 	const char *name;
180 	GElf_Shdr sh;
181 	Elf_Scn *scn;
182 	Elf_Data *symtab_data;
183 	size_t symtab_ndx;
184 	int elferr, i, j, n, ret;
185 
186 	ret = DW_DLE_NONE;
187 
188 	if ((iface = calloc(1, sizeof(*iface))) == NULL) {
189 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
190 		return (DW_DLE_MEMORY);
191 	}
192 
193 	if ((e = calloc(1, sizeof(*e))) == NULL) {
194 		free(iface);
195 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
196 		return (DW_DLE_MEMORY);
197 	}
198 
199 	e->eo_elf = elf;
200 	e->eo_methods.get_section_info = _dwarf_elf_get_section_info;
201 	e->eo_methods.get_byte_order = _dwarf_elf_get_byte_order;
202 	e->eo_methods.get_length_size = _dwarf_elf_get_length_size;
203 	e->eo_methods.get_pointer_size = _dwarf_elf_get_pointer_size;
204 	e->eo_methods.get_section_count = _dwarf_elf_get_section_count;
205 	e->eo_methods.load_section = _dwarf_elf_load_section;
206 
207 	iface->object = e;
208 	iface->methods = &e->eo_methods;
209 
210 	dbg->dbg_iface = iface;
211 
212 	if (gelf_getehdr(elf, &e->eo_ehdr) == NULL) {
213 		DWARF_SET_ELF_ERROR(dbg, error);
214 		ret = DW_DLE_ELF;
215 		goto fail_cleanup;
216 	}
217 
218 	dbg->dbg_machine = e->eo_ehdr.e_machine;
219 
220 	if (!elf_getshstrndx(elf, &e->eo_strndx)) {
221 		DWARF_SET_ELF_ERROR(dbg, error);
222 		ret = DW_DLE_ELF;
223 		goto fail_cleanup;
224 	}
225 
226 	n = 0;
227 	symtab_ndx = 0;
228 	symtab_data = NULL;
229 	scn = NULL;
230 	(void) elf_errno();
231 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
232 		if (gelf_getshdr(scn, &sh) == NULL) {
233 			DWARF_SET_ELF_ERROR(dbg, error);
234 			ret = DW_DLE_ELF;
235 			goto fail_cleanup;
236 		}
237 
238 		if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) ==
239 		    NULL) {
240 			DWARF_SET_ELF_ERROR(dbg, error);
241 			ret = DW_DLE_ELF;
242 			goto fail_cleanup;
243 		}
244 
245 		if (!strcmp(name, ".symtab")) {
246 			symtab_ndx = elf_ndxscn(scn);
247 			if ((symtab_data = elf_getdata(scn, NULL)) == NULL) {
248 				elferr = elf_errno();
249 				if (elferr != 0) {
250 					_DWARF_SET_ERROR(NULL, error,
251 					    DW_DLE_ELF, elferr);
252 					ret = DW_DLE_ELF;
253 					goto fail_cleanup;
254 				}
255 			}
256 			continue;
257 		}
258 
259 		for (i = 0; debug_name[i] != NULL; i++) {
260 			if (!strcmp(name, debug_name[i]))
261 				n++;
262 		}
263 	}
264 	elferr = elf_errno();
265 	if (elferr != 0) {
266 		DWARF_SET_ELF_ERROR(dbg, error);
267 		return (DW_DLE_ELF);
268 	}
269 
270 	e->eo_seccnt = n;
271 
272 	if (n == 0)
273 		return (DW_DLE_NONE);
274 
275 	if ((e->eo_data = calloc(n, sizeof(Dwarf_Elf_Data))) == NULL ||
276 	    (e->eo_shdr = calloc(n, sizeof(GElf_Shdr))) == NULL) {
277 		DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
278 		ret = DW_DLE_MEMORY;
279 		goto fail_cleanup;
280 	}
281 
282 	scn = NULL;
283 	j = 0;
284 	while ((scn = elf_nextscn(elf, scn)) != NULL && j < n) {
285 		if (gelf_getshdr(scn, &sh) == NULL) {
286 			DWARF_SET_ELF_ERROR(dbg, error);
287 			ret = DW_DLE_ELF;
288 			goto fail_cleanup;
289 		}
290 
291 		memcpy(&e->eo_shdr[j], &sh, sizeof(sh));
292 
293 		if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) ==
294 		    NULL) {
295 			DWARF_SET_ELF_ERROR(dbg, error);
296 			ret = DW_DLE_ELF;
297 			goto fail_cleanup;
298 		}
299 
300 		for (i = 0; debug_name[i] != NULL; i++) {
301 			if (strcmp(name, debug_name[i]))
302 				continue;
303 
304 			(void) elf_errno();
305 			if ((e->eo_data[j].ed_data = elf_getdata(scn, NULL)) ==
306 			    NULL) {
307 				elferr = elf_errno();
308 				if (elferr != 0) {
309 					_DWARF_SET_ERROR(dbg, error,
310 					    DW_DLE_ELF, elferr);
311 					ret = DW_DLE_ELF;
312 					goto fail_cleanup;
313 				}
314 			}
315 
316 			if (_libdwarf.applyreloc) {
317 				if (_dwarf_elf_relocate(dbg, elf,
318 				    &e->eo_data[j], elf_ndxscn(scn), symtab_ndx,
319 				    symtab_data, error) != DW_DLE_NONE)
320 					goto fail_cleanup;
321 			}
322 
323 			j++;
324 		}
325 	}
326 
327 	assert(j == n);
328 
329 	return (DW_DLE_NONE);
330 
331 fail_cleanup:
332 
333 	_dwarf_elf_deinit(dbg);
334 
335 	return (ret);
336 }
337 
338 void
339 _dwarf_elf_deinit(Dwarf_Debug dbg)
340 {
341 	Dwarf_Obj_Access_Interface *iface;
342 	Dwarf_Elf_Object *e;
343 	int i;
344 
345 	iface = dbg->dbg_iface;
346 	assert(iface != NULL);
347 
348 	e = iface->object;
349 	assert(e != NULL);
350 
351 	if (e->eo_data) {
352 		for (i = 0; (Dwarf_Unsigned) i < e->eo_seccnt; i++) {
353 			if (e->eo_data[i].ed_alloc)
354 				free(e->eo_data[i].ed_alloc);
355 		}
356 		free(e->eo_data);
357 	}
358 	if (e->eo_shdr)
359 		free(e->eo_shdr);
360 
361 	free(e);
362 	free(iface);
363 
364 	dbg->dbg_iface = NULL;
365 }
366