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
30ELFTC_VCSID("$Id: libdwarf_info.c 3136 2014-12-24 16:04:38Z kaiwang27 $");
31
32int
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
58int
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
84int
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
111int
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
138int
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
253void
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
273void
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
287int
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
357gen_fail:
358	_dwarf_reloc_section_free(dbg, &drs);
359
360gen_fail0:
361	_dwarf_section_free(dbg, &dbg->dbgp_info);
362
363gen_fail1:
364	STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next);
365	free(cu);
366
367	return (ret);
368}
369
370void
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