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