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