1 /*-
2  * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3  * Copyright (c) 2010,2011,2014 Kai Wang
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include "_libdwarf.h"
29 
30 ELFTC_VCSID("$Id: libdwarf_info.c 3136 2014-12-24 16:04:38Z kaiwang27 $");
31 
32 int
_dwarf_info_first_cu(Dwarf_Debug dbg,Dwarf_Error * error)33 _dwarf_info_first_cu(Dwarf_Debug dbg, Dwarf_Error *error)
34 {
35 	Dwarf_CU cu;
36 	int ret;
37 
38 	assert(dbg->dbg_cu_current == NULL);
39 	cu = STAILQ_FIRST(&dbg->dbg_cu);
40 	if (cu != NULL) {
41 		dbg->dbg_cu_current = cu;
42 		return (DW_DLE_NONE);
43 	}
44 
45 	if (dbg->dbg_info_loaded)
46 		return (DW_DLE_NO_ENTRY);
47 
48 	dbg->dbg_info_off = 0;
49 	ret = _dwarf_info_load(dbg, 0, 1, error);
50 	if (ret != DW_DLE_NONE)
51 		return (ret);
52 
53 	dbg->dbg_cu_current = STAILQ_FIRST(&dbg->dbg_cu);
54 
55 	return (DW_DLE_NONE);
56 }
57 
58 int
_dwarf_info_first_tu(Dwarf_Debug dbg,Dwarf_Error * error)59 _dwarf_info_first_tu(Dwarf_Debug dbg, Dwarf_Error *error)
60 {
61 	Dwarf_CU tu;
62 	int ret;
63 
64 	assert(dbg->dbg_tu_current == NULL);
65 	tu = STAILQ_FIRST(&dbg->dbg_tu);
66 	if (tu != NULL) {
67 		dbg->dbg_tu_current = tu;
68 		return (DW_DLE_NONE);
69 	}
70 
71 	if (dbg->dbg_types_loaded)
72 		return (DW_DLE_NO_ENTRY);
73 
74 	dbg->dbg_types_off = 0;
75 	ret = _dwarf_info_load(dbg, 0, 0, error);
76 	if (ret != DW_DLE_NONE)
77 		return (ret);
78 
79 	dbg->dbg_tu_current = STAILQ_FIRST(&dbg->dbg_tu);
80 
81 	return (DW_DLE_NONE);
82 }
83 
84 int
_dwarf_info_next_cu(Dwarf_Debug dbg,Dwarf_Error * error)85 _dwarf_info_next_cu(Dwarf_Debug dbg, Dwarf_Error *error)
86 {
87 	Dwarf_CU cu;
88 	int ret;
89 
90 	assert(dbg->dbg_cu_current != NULL);
91 	cu = STAILQ_NEXT(dbg->dbg_cu_current, cu_next);
92 	if (cu != NULL) {
93 		dbg->dbg_cu_current = cu;
94 		return (DW_DLE_NONE);
95 	}
96 
97 	if (dbg->dbg_info_loaded) {
98 		dbg->dbg_cu_current = NULL;
99 		return (DW_DLE_NO_ENTRY);
100 	}
101 
102 	ret = _dwarf_info_load(dbg, 0, 1, error);
103 	if (ret != DW_DLE_NONE)
104 		return (ret);
105 
106 	dbg->dbg_cu_current = STAILQ_NEXT(dbg->dbg_cu_current, cu_next);
107 
108 	return (DW_DLE_NONE);
109 }
110 
111 int
_dwarf_info_next_tu(Dwarf_Debug dbg,Dwarf_Error * error)112 _dwarf_info_next_tu(Dwarf_Debug dbg, Dwarf_Error *error)
113 {
114 	Dwarf_CU cu;
115 	int ret;
116 
117 	assert(dbg->dbg_tu_current != NULL);
118 	cu = STAILQ_NEXT(dbg->dbg_tu_current, cu_next);
119 	if (cu != NULL) {
120 		dbg->dbg_tu_current = cu;
121 		return (DW_DLE_NONE);
122 	}
123 
124 	if (dbg->dbg_types_loaded) {
125 		dbg->dbg_tu_current = NULL;
126 		return (DW_DLE_NO_ENTRY);
127 	}
128 
129 	ret = _dwarf_info_load(dbg, 0, 0, error);
130 	if (ret != DW_DLE_NONE)
131 		return (ret);
132 
133 	dbg->dbg_tu_current = STAILQ_NEXT(dbg->dbg_tu_current, cu_next);
134 
135 	return (DW_DLE_NONE);
136 }
137 
138 int
_dwarf_info_load(Dwarf_Debug dbg,Dwarf_Bool load_all,Dwarf_Bool is_info,Dwarf_Error * error)139 _dwarf_info_load(Dwarf_Debug dbg, Dwarf_Bool load_all, Dwarf_Bool is_info,
140     Dwarf_Error *error)
141 {
142 	Dwarf_CU cu;
143 	Dwarf_Section *ds;
144 	int dwarf_size, ret;
145 	uint64_t length;
146 	uint64_t next_offset;
147 	uint64_t offset;
148 
149 	ret = DW_DLE_NONE;
150 
151 	if (is_info) {
152 		if (dbg->dbg_info_loaded)
153 			return (ret);
154 		offset = dbg->dbg_info_off;
155 		ds = dbg->dbg_info_sec;
156 		if (ds == NULL)
157 			return (DW_DLE_NO_ENTRY);
158 	} else {
159 		if (dbg->dbg_types_loaded)
160 			return (ret);
161 		offset = dbg->dbg_types_off;
162 		ds = dbg->dbg_types_sec;
163 		if (ds == NULL)
164 			return (DW_DLE_NO_ENTRY);
165 	}
166 
167 	while (offset < ds->ds_size) {
168 		if ((cu = calloc(1, sizeof(struct _Dwarf_CU))) == NULL) {
169 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
170 			return (DW_DLE_MEMORY);
171 		}
172 
173 		cu->cu_dbg = dbg;
174 		cu->cu_is_info = is_info;
175 		cu->cu_offset = offset;
176 
177 		length = dbg->read(ds->ds_data, &offset, 4);
178 		if (length == 0xffffffff) {
179 			length = dbg->read(ds->ds_data, &offset, 8);
180 			dwarf_size = 8;
181 		} else
182 			dwarf_size = 4;
183 		cu->cu_dwarf_size = dwarf_size;
184 
185 		/*
186 		 * Check if there is enough ELF data for this CU. This assumes
187 		 * that libelf gives us the entire section in one Elf_Data
188 		 * object.
189 		 */
190 		if (length > ds->ds_size - offset) {
191 			free(cu);
192 			DWARF_SET_ERROR(dbg, error, DW_DLE_CU_LENGTH_ERROR);
193 			return (DW_DLE_CU_LENGTH_ERROR);
194 		}
195 
196 		/* Compute the offset to the next compilation unit: */
197 		next_offset = offset + length;
198 		if (is_info)
199 			dbg->dbg_info_off = next_offset;
200 		else
201 			dbg->dbg_types_off = next_offset;
202 
203 		/* Initialise the compilation unit. */
204 		cu->cu_length		 = length;
205 		cu->cu_length_size	 = (dwarf_size == 4 ? 4 : 12);
206 		cu->cu_version		 = dbg->read(ds->ds_data, &offset, 2);
207 		cu->cu_abbrev_offset	 = dbg->read(ds->ds_data, &offset,
208 		    dwarf_size);
209 		cu->cu_abbrev_offset_cur = cu->cu_abbrev_offset;
210 		cu->cu_pointer_size	 = dbg->read(ds->ds_data, &offset, 1);
211 		cu->cu_next_offset	 = next_offset;
212 
213 		/* .debug_types extra fields. */
214 		if (!is_info) {
215 			memcpy(cu->cu_type_sig.signature,
216 			    (char *) ds->ds_data + offset, 8);
217 			offset += 8;
218 			cu->cu_type_offset = dbg->read(ds->ds_data, &offset,
219 			    dwarf_size);
220 		}
221 
222 		/* Add the compilation unit to the list. */
223 		if (is_info)
224 			STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next);
225 		else
226 			STAILQ_INSERT_TAIL(&dbg->dbg_tu, cu, cu_next);
227 
228 		if (cu->cu_version < 2 || cu->cu_version > 4) {
229 			DWARF_SET_ERROR(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
230 			ret = DW_DLE_VERSION_STAMP_ERROR;
231 			break;
232 		}
233 
234 		cu->cu_1st_offset = offset;
235 
236 		offset = next_offset;
237 
238 		if (!load_all)
239 			break;
240 	}
241 
242 	if (is_info) {
243 		if ((Dwarf_Unsigned) dbg->dbg_info_off >= ds->ds_size)
244 			dbg->dbg_info_loaded = 1;
245 	} else {
246 		if ((Dwarf_Unsigned) dbg->dbg_types_off >= ds->ds_size)
247 			dbg->dbg_types_loaded = 1;
248 	}
249 
250 	return (ret);
251 }
252 
253 void
_dwarf_info_cleanup(Dwarf_Debug dbg)254 _dwarf_info_cleanup(Dwarf_Debug dbg)
255 {
256 	Dwarf_CU cu, tcu;
257 
258 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ);
259 
260 	STAILQ_FOREACH_SAFE(cu, &dbg->dbg_cu, cu_next, tcu) {
261 		STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next);
262 		_dwarf_abbrev_cleanup(cu);
263 		if (cu->cu_lineinfo != NULL) {
264 			_dwarf_lineno_cleanup(cu->cu_lineinfo);
265 			cu->cu_lineinfo = NULL;
266 		}
267 		free(cu);
268 	}
269 
270 	_dwarf_type_unit_cleanup(dbg);
271 }
272 
273 void
_dwarf_type_unit_cleanup(Dwarf_Debug dbg)274 _dwarf_type_unit_cleanup(Dwarf_Debug dbg)
275 {
276 	Dwarf_CU cu, tcu;
277 
278 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ);
279 
280 	STAILQ_FOREACH_SAFE(cu, &dbg->dbg_tu, cu_next, tcu) {
281 		STAILQ_REMOVE(&dbg->dbg_tu, cu, _Dwarf_CU, cu_next);
282 		_dwarf_abbrev_cleanup(cu);
283 		free(cu);
284 	}
285 }
286 
287 int
_dwarf_info_gen(Dwarf_P_Debug dbg,Dwarf_Error * error)288 _dwarf_info_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
289 {
290 	Dwarf_P_Section ds;
291 	Dwarf_Rel_Section drs;
292 	Dwarf_Unsigned offset;
293 	Dwarf_CU cu;
294 	int ret;
295 
296 	assert(dbg != NULL && dbg->write_alloc != NULL);
297 
298 	if (dbg->dbgp_root_die == NULL)
299 		return (DW_DLE_NONE);
300 
301 	/* Create the single CU for this debugging object. */
302 	if ((cu = calloc(1, sizeof(struct _Dwarf_CU))) == NULL) {
303 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
304 		return (DW_DLE_MEMORY);
305 	}
306 	cu->cu_dbg = dbg;
307 	cu->cu_version = 2;	/* DWARF2 */
308 	cu->cu_pointer_size = dbg->dbg_pointer_size;
309 	STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next);
310 
311 	/* Create .debug_info section. */
312 	if ((ret = _dwarf_section_init(dbg, &dbg->dbgp_info, ".debug_info", 0,
313 	    error)) != DW_DLE_NONE)
314 		goto gen_fail1;
315 	ds = dbg->dbgp_info;
316 
317 	/* Create relocation section for .debug_init */
318 	if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) !=
319 	    DW_DLE_NONE)
320 		goto gen_fail0;
321 
322 	/* Length placeholder. (We only use 32-bit DWARF format) */
323 	RCHECK(WRITE_VALUE(cu->cu_length, 4));
324 
325 	/* Write CU version */
326 	RCHECK(WRITE_VALUE(cu->cu_version, 2));
327 
328 	/*
329 	 * Write abbrev offset. (always 0, we only support single CU)
330 	 * Also generate a relocation entry for this offset.
331 	 */
332 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4,
333 	    ds->ds_size, 0, cu->cu_abbrev_offset, ".debug_abbrev", error));
334 
335 	/* Pointer size. */
336 	RCHECK(WRITE_VALUE(cu->cu_pointer_size, 1));
337 
338 	/* Transform the DIE(s) of this CU. */
339 	RCHECK(_dwarf_die_gen(dbg, cu, drs, error));
340 
341 	/* Now we can fill in the length of this CU. */
342 	cu->cu_length = ds->ds_size - 4;
343 	offset = 0;
344 	dbg->write(ds->ds_data, &offset, cu->cu_length, 4);
345 
346 	/* Inform application the creation of .debug_info ELF section. */
347 	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
348 
349 	/*
350 	 * Inform application the creation of relocation section for
351 	 * .debug_info.
352 	 */
353 	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
354 
355 	return (DW_DLE_NONE);
356 
357 gen_fail:
358 	_dwarf_reloc_section_free(dbg, &drs);
359 
360 gen_fail0:
361 	_dwarf_section_free(dbg, &dbg->dbgp_info);
362 
363 gen_fail1:
364 	STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next);
365 	free(cu);
366 
367 	return (ret);
368 }
369 
370 void
_dwarf_info_pro_cleanup(Dwarf_P_Debug dbg)371 _dwarf_info_pro_cleanup(Dwarf_P_Debug dbg)
372 {
373 	Dwarf_CU cu;
374 
375 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
376 
377 	cu = STAILQ_FIRST(&dbg->dbg_cu);
378 	if (cu != NULL) {
379 		STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next);
380 		_dwarf_abbrev_cleanup(cu);
381 		free(cu);
382 	}
383 }
384