1260684Skaiw/*-
2260684Skaiw * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3260684Skaiw * Copyright (c) 2009-2011 Kai Wang
4260684Skaiw * All rights reserved.
5260684Skaiw *
6260684Skaiw * Redistribution and use in source and binary forms, with or without
7260684Skaiw * modification, are permitted provided that the following conditions
8260684Skaiw * are met:
9260684Skaiw * 1. Redistributions of source code must retain the above copyright
10260684Skaiw *    notice, this list of conditions and the following disclaimer.
11260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
12260684Skaiw *    notice, this list of conditions and the following disclaimer in the
13260684Skaiw *    documentation and/or other materials provided with the distribution.
14260684Skaiw *
15260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18260684Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25260684Skaiw * SUCH DAMAGE.
26260684Skaiw */
27260684Skaiw
28260684Skaiw#include "_libdwarf.h"
29260684Skaiw
30276371SemasteELFTC_VCSID("$Id: libdwarf_die.c 3039 2014-05-18 15:10:56Z kaiwang27 $");
31260684Skaiw
32260684Skaiwint
33260684Skaiw_dwarf_die_alloc(Dwarf_Debug dbg, Dwarf_Die *ret_die, Dwarf_Error *error)
34260684Skaiw{
35260684Skaiw	Dwarf_Die die;
36260684Skaiw
37260684Skaiw	assert(ret_die != NULL);
38260684Skaiw
39260684Skaiw	if ((die = calloc(1, sizeof(struct _Dwarf_Die))) == NULL) {
40260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
41260684Skaiw		return (DW_DLE_MEMORY);
42260684Skaiw	}
43260684Skaiw
44260684Skaiw	STAILQ_INIT(&die->die_attr);
45260684Skaiw
46260684Skaiw	*ret_die = die;
47260684Skaiw
48260684Skaiw	return (DW_DLE_NONE);
49260684Skaiw}
50260684Skaiw
51260684Skaiwstatic int
52260684Skaiw_dwarf_die_add(Dwarf_CU cu, uint64_t offset, uint64_t abnum, Dwarf_Abbrev ab,
53260684Skaiw    Dwarf_Die *diep, Dwarf_Error *error)
54260684Skaiw{
55260684Skaiw	Dwarf_Debug dbg;
56260684Skaiw	Dwarf_Die die;
57260684Skaiw	int ret;
58260684Skaiw
59260684Skaiw	assert(cu != NULL);
60260684Skaiw	assert(ab != NULL);
61260684Skaiw
62260684Skaiw	dbg = cu->cu_dbg;
63260684Skaiw
64260684Skaiw	if ((ret = _dwarf_die_alloc(dbg, &die, error)) != DW_DLE_NONE)
65260684Skaiw		return (ret);
66260684Skaiw
67260684Skaiw	die->die_offset	= offset;
68260684Skaiw	die->die_abnum	= abnum;
69260684Skaiw	die->die_ab	= ab;
70260684Skaiw	die->die_cu	= cu;
71260684Skaiw	die->die_dbg	= cu->cu_dbg;
72260684Skaiw
73367466Sdim	*diep = die;
74260684Skaiw
75260684Skaiw	return (DW_DLE_NONE);
76260684Skaiw}
77260684Skaiw
78260684Skaiw/* Find die at offset 'off' within the same CU. */
79260684SkaiwDwarf_Die
80260684Skaiw_dwarf_die_find(Dwarf_Die die, Dwarf_Unsigned off)
81260684Skaiw{
82260684Skaiw	Dwarf_Debug dbg;
83276371Semaste	Dwarf_Section *ds;
84260684Skaiw	Dwarf_CU cu;
85260684Skaiw	Dwarf_Die die1;
86260684Skaiw	Dwarf_Error de;
87260684Skaiw	int ret;
88260684Skaiw
89260684Skaiw	cu = die->die_cu;
90260684Skaiw	dbg = die->die_dbg;
91276371Semaste	ds = cu->cu_is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec;
92260684Skaiw
93276371Semaste	ret = _dwarf_die_parse(dbg, ds, cu, cu->cu_dwarf_size, off,
94276371Semaste	    cu->cu_next_offset, &die1, 0, &de);
95260684Skaiw
96260684Skaiw	if (ret == DW_DLE_NONE)
97260684Skaiw		return (die1);
98260684Skaiw	else
99260684Skaiw		return (NULL);
100260684Skaiw}
101260684Skaiw
102260684Skaiwint
103260684Skaiw_dwarf_die_parse(Dwarf_Debug dbg, Dwarf_Section *ds, Dwarf_CU cu,
104260684Skaiw    int dwarf_size, uint64_t offset, uint64_t next_offset, Dwarf_Die *ret_die,
105260684Skaiw    int search_sibling, Dwarf_Error *error)
106260684Skaiw{
107260684Skaiw	Dwarf_Abbrev ab;
108260684Skaiw	Dwarf_AttrDef ad;
109260684Skaiw	Dwarf_Die die;
110260684Skaiw	uint64_t abnum;
111260684Skaiw	uint64_t die_offset;
112260684Skaiw	int ret, level;
113260684Skaiw
114260684Skaiw	assert(cu != NULL);
115260684Skaiw
116260684Skaiw	level = 1;
117260684Skaiw	die = NULL;
118260684Skaiw
119260684Skaiw	while (offset < next_offset && offset < ds->ds_size) {
120260684Skaiw
121260684Skaiw		die_offset = offset;
122260684Skaiw
123260684Skaiw		abnum = _dwarf_read_uleb128(ds->ds_data, &offset);
124260684Skaiw
125260684Skaiw		if (abnum == 0) {
126260684Skaiw			if (level == 0 || !search_sibling)
127260684Skaiw				return (DW_DLE_NO_ENTRY);
128260684Skaiw
129260684Skaiw			/*
130260684Skaiw			 * Return to previous DIE level.
131260684Skaiw			 */
132260684Skaiw			level--;
133260684Skaiw			continue;
134260684Skaiw		}
135260684Skaiw
136260684Skaiw		if ((ret = _dwarf_abbrev_find(cu, abnum, &ab, error)) !=
137260684Skaiw		    DW_DLE_NONE)
138260684Skaiw			return (ret);
139260684Skaiw
140260684Skaiw		if ((ret = _dwarf_die_add(cu, die_offset, abnum, ab, &die,
141260684Skaiw		    error)) != DW_DLE_NONE)
142260684Skaiw			return (ret);
143260684Skaiw
144260684Skaiw		STAILQ_FOREACH(ad, &ab->ab_attrdef, ad_next) {
145260684Skaiw			if ((ret = _dwarf_attr_init(dbg, ds, &offset,
146260684Skaiw			    dwarf_size, cu, die, ad, ad->ad_form, 0,
147260684Skaiw			    error)) != DW_DLE_NONE)
148260684Skaiw				return (ret);
149260684Skaiw		}
150260684Skaiw
151260684Skaiw		die->die_next_off = offset;
152260684Skaiw		if (search_sibling && level > 0) {
153260684Skaiw			dwarf_dealloc(dbg, die, DW_DLA_DIE);
154260684Skaiw			if (ab->ab_children == DW_CHILDREN_yes) {
155260684Skaiw				/* Advance to next DIE level. */
156260684Skaiw				level++;
157260684Skaiw			}
158260684Skaiw		} else {
159260684Skaiw			*ret_die = die;
160260684Skaiw			return (DW_DLE_NONE);
161260684Skaiw		}
162260684Skaiw	}
163260684Skaiw
164260684Skaiw	return (DW_DLE_NO_ENTRY);
165260684Skaiw}
166260684Skaiw
167260684Skaiwvoid
168260684Skaiw_dwarf_die_link(Dwarf_P_Die die, Dwarf_P_Die parent, Dwarf_P_Die child,
169260684Skaiw    Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling)
170260684Skaiw{
171260684Skaiw	Dwarf_P_Die last_child;
172260684Skaiw
173260684Skaiw	assert(die != NULL);
174260684Skaiw
175260684Skaiw	if (parent) {
176260684Skaiw
177260684Skaiw		/* Disconnect from old parent. */
178260684Skaiw		if (die->die_parent) {
179260684Skaiw			if (die->die_parent != parent) {
180260684Skaiw				if (die->die_parent->die_child == die)
181260684Skaiw					die->die_parent->die_child = NULL;
182260684Skaiw				die->die_parent = NULL;
183260684Skaiw                     }
184260684Skaiw		}
185260684Skaiw
186260684Skaiw		/* Find the last child of this parent. */
187260684Skaiw		last_child = parent->die_child;
188260684Skaiw		if (last_child) {
189260684Skaiw			while (last_child->die_right != NULL)
190260684Skaiw				last_child = last_child->die_right;
191260684Skaiw		}
192260684Skaiw
193260684Skaiw		/* Connect to new parent. */
194260684Skaiw		die->die_parent = parent;
195260684Skaiw
196260684Skaiw		/*
197260684Skaiw		 * Attach this DIE to the end of sibling list. If new
198260684Skaiw		 * parent doesn't have any child, set this DIE as the
199260684Skaiw		 * first child.
200260684Skaiw		 */
201260684Skaiw		if (last_child) {
202260684Skaiw			assert(last_child->die_right == NULL);
203260684Skaiw			last_child->die_right = die;
204260684Skaiw			die->die_left = last_child;
205260684Skaiw		} else
206260684Skaiw			parent->die_child = die;
207260684Skaiw	}
208260684Skaiw
209260684Skaiw	if (child) {
210260684Skaiw
211260684Skaiw		/* Disconnect from old child. */
212260684Skaiw		if (die->die_child) {
213260684Skaiw			if (die->die_child != child) {
214260684Skaiw				die->die_child->die_parent = NULL;
215260684Skaiw				die->die_child = NULL;
216260684Skaiw			}
217260684Skaiw		}
218260684Skaiw
219260684Skaiw		/* Connect to new child. */
220260684Skaiw		die->die_child = child;
221260684Skaiw		child->die_parent = die;
222260684Skaiw	}
223260684Skaiw
224260684Skaiw	if (left_sibling) {
225260684Skaiw
226260684Skaiw		/* Disconnect from old left sibling. */
227260684Skaiw		if (die->die_left) {
228260684Skaiw			if (die->die_left != left_sibling) {
229260684Skaiw				die->die_left->die_right = NULL;
230260684Skaiw				die->die_left = NULL;
231260684Skaiw			}
232260684Skaiw		}
233260684Skaiw
234260684Skaiw		/* Connect to new right sibling. */
235260684Skaiw		die->die_left = left_sibling;
236260684Skaiw		left_sibling->die_right = die;
237260684Skaiw	}
238260684Skaiw
239260684Skaiw	if (right_sibling) {
240260684Skaiw
241260684Skaiw		/* Disconnect from old right sibling. */
242260684Skaiw		if (die->die_right) {
243260684Skaiw			if (die->die_right != right_sibling) {
244260684Skaiw				die->die_right->die_left = NULL;
245260684Skaiw				die->die_right = NULL;
246260684Skaiw			}
247260684Skaiw		}
248260684Skaiw
249260684Skaiw		/* Connect to new right sibling. */
250260684Skaiw		die->die_right = right_sibling;
251260684Skaiw		right_sibling->die_left = die;
252260684Skaiw	}
253260684Skaiw}
254260684Skaiw
255260684Skaiwint
256260684Skaiw_dwarf_die_count_links(Dwarf_P_Die parent, Dwarf_P_Die child,
257260684Skaiw    Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling)
258260684Skaiw{
259260684Skaiw	int count;
260260684Skaiw
261260684Skaiw	count = 0;
262260684Skaiw
263260684Skaiw	if (parent)
264260684Skaiw		count++;
265260684Skaiw	if (child)
266260684Skaiw		count++;
267260684Skaiw	if (left_sibling)
268260684Skaiw		count++;
269260684Skaiw	if (right_sibling)
270260684Skaiw		count++;
271260684Skaiw
272260684Skaiw	return (count);
273260684Skaiw}
274260684Skaiw
275260684Skaiwstatic int
276260684Skaiw_dwarf_die_gen_recursive(Dwarf_P_Debug dbg, Dwarf_CU cu, Dwarf_Rel_Section drs,
277260684Skaiw    Dwarf_P_Die die, int pass2, Dwarf_Error *error)
278260684Skaiw{
279260684Skaiw	Dwarf_P_Section ds;
280260684Skaiw	Dwarf_Abbrev ab;
281260684Skaiw	Dwarf_Attribute at;
282260684Skaiw	Dwarf_AttrDef ad;
283260684Skaiw	int match, ret;
284260684Skaiw
285260684Skaiw	ds = dbg->dbgp_info;
286260684Skaiw	assert(ds != NULL);
287260684Skaiw
288260684Skaiw	if (pass2)
289260684Skaiw		goto attr_gen;
290260684Skaiw
291260684Skaiw	/*
292260684Skaiw	 * Add DW_AT_sibling attribute for DIEs with children, so consumers
293260684Skaiw	 * can quickly scan chains of siblings, while ignoring the children
294260684Skaiw	 * of individual siblings.
295260684Skaiw	 */
296260684Skaiw	if (die->die_child && die->die_right) {
297260684Skaiw		if (_dwarf_attr_find(die, DW_AT_sibling) == NULL)
298260684Skaiw			(void) dwarf_add_AT_reference(dbg, die, DW_AT_sibling,
299260684Skaiw			    die->die_right, error);
300260684Skaiw	}
301260684Skaiw
302260684Skaiw	/*
303260684Skaiw	 * Search abbrev list to find a matching entry.
304260684Skaiw	 */
305260684Skaiw	die->die_ab = NULL;
306260684Skaiw	for (ab = cu->cu_abbrev_hash; ab != NULL; ab = ab->ab_hh.next) {
307260684Skaiw		if (die->die_tag != ab->ab_tag)
308260684Skaiw			continue;
309260684Skaiw		if (ab->ab_children == DW_CHILDREN_no && die->die_child != NULL)
310260684Skaiw			continue;
311260684Skaiw		if (ab->ab_children == DW_CHILDREN_yes &&
312260684Skaiw		    die->die_child == NULL)
313260684Skaiw			continue;
314260684Skaiw		at = STAILQ_FIRST(&die->die_attr);
315260684Skaiw		ad = STAILQ_FIRST(&ab->ab_attrdef);
316260684Skaiw		match = 1;
317260684Skaiw		while (at != NULL && ad != NULL) {
318260684Skaiw			if (at->at_attrib != ad->ad_attrib ||
319260684Skaiw			    at->at_form != ad->ad_form) {
320260684Skaiw				match = 0;
321260684Skaiw				break;
322260684Skaiw			}
323260684Skaiw			at = STAILQ_NEXT(at, at_next);
324260684Skaiw			ad = STAILQ_NEXT(ad, ad_next);
325260684Skaiw		}
326260684Skaiw		if ((at == NULL && ad != NULL) || (at != NULL && ad == NULL))
327260684Skaiw			match = 0;
328260684Skaiw		if (match) {
329260684Skaiw			die->die_ab = ab;
330260684Skaiw			break;
331260684Skaiw		}
332260684Skaiw	}
333260684Skaiw
334260684Skaiw	/*
335260684Skaiw	 * Create a new abbrev entry if we can not reuse any existing one.
336260684Skaiw	 */
337260684Skaiw	if (die->die_ab == NULL) {
338260684Skaiw		ret = _dwarf_abbrev_add(cu, ++cu->cu_abbrev_cnt, die->die_tag,
339260684Skaiw		    die->die_child != NULL ? DW_CHILDREN_yes : DW_CHILDREN_no,
340260684Skaiw		    0, &ab, error);
341260684Skaiw		if (ret != DW_DLE_NONE)
342260684Skaiw			return (ret);
343260684Skaiw		STAILQ_FOREACH(at, &die->die_attr, at_next) {
344260684Skaiw			ret = _dwarf_attrdef_add(dbg, ab, at->at_attrib,
345260684Skaiw			    at->at_form, 0, NULL, error);
346260684Skaiw			if (ret != DW_DLE_NONE)
347260684Skaiw				return (ret);
348260684Skaiw		}
349260684Skaiw		die->die_ab = ab;
350260684Skaiw	}
351260684Skaiw
352260684Skaiw	die->die_offset = ds->ds_size;
353260684Skaiw
354260684Skaiw	/*
355260684Skaiw	 * Transform the DIE to bytes stream.
356260684Skaiw	 */
357260684Skaiw	ret = _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap,
358260684Skaiw	    &ds->ds_size, die->die_ab->ab_entry, error);
359260684Skaiw	if (ret != DW_DLE_NONE)
360260684Skaiw		return (ret);
361260684Skaiw
362260684Skaiwattr_gen:
363260684Skaiw
364260684Skaiw	/* Transform the attributes of this DIE. */
365260684Skaiw	ret = _dwarf_attr_gen(dbg, ds, drs, cu, die, pass2, error);
366260684Skaiw	if (ret != DW_DLE_NONE)
367260684Skaiw		return (ret);
368260684Skaiw
369260684Skaiw	/* Proceed to child DIE. */
370260684Skaiw	if (die->die_child != NULL) {
371260684Skaiw		ret = _dwarf_die_gen_recursive(dbg, cu, drs, die->die_child,
372260684Skaiw		    pass2, error);
373260684Skaiw		if (ret != DW_DLE_NONE)
374260684Skaiw			return (ret);
375260684Skaiw	}
376260684Skaiw
377260684Skaiw	/* Proceed to sibling DIE. */
378260684Skaiw	if (die->die_right != NULL) {
379260684Skaiw		ret = _dwarf_die_gen_recursive(dbg, cu, drs, die->die_right,
380260684Skaiw		    pass2, error);
381260684Skaiw		if (ret != DW_DLE_NONE)
382260684Skaiw			return (ret);
383260684Skaiw	}
384260684Skaiw
385260684Skaiw	/* Write a null DIE indicating the end of current level. */
386260684Skaiw	if (die->die_right == NULL) {
387260684Skaiw		ret = _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap,
388260684Skaiw		    &ds->ds_size, 0, error);
389260684Skaiw		if (ret != DW_DLE_NONE)
390260684Skaiw			return (ret);
391260684Skaiw	}
392260684Skaiw
393260684Skaiw	return (DW_DLE_NONE);
394260684Skaiw}
395260684Skaiw
396260684Skaiwint
397260684Skaiw_dwarf_die_gen(Dwarf_P_Debug dbg, Dwarf_CU cu, Dwarf_Rel_Section drs,
398260684Skaiw    Dwarf_Error *error)
399260684Skaiw{
400260684Skaiw	Dwarf_Abbrev ab, tab;
401260684Skaiw	Dwarf_AttrDef ad, tad;
402260684Skaiw	Dwarf_Die die;
403260684Skaiw	int ret;
404260684Skaiw
405260684Skaiw	assert(dbg != NULL && cu != NULL);
406260684Skaiw	assert(dbg->dbgp_root_die != NULL);
407260684Skaiw
408260684Skaiw	die = dbg->dbgp_root_die;
409260684Skaiw
410260684Skaiw	/*
411260684Skaiw	 * Insert a DW_AT_stmt_list attribute into root DIE, if there are
412260684Skaiw	 * line number information.
413260684Skaiw	 */
414260684Skaiw	if (!STAILQ_EMPTY(&dbg->dbgp_lineinfo->li_lnlist))
415260684Skaiw		RCHECK(_dwarf_add_AT_dataref(dbg, die, DW_AT_stmt_list, 0, 0,
416260684Skaiw		    ".debug_line", NULL, error));
417260684Skaiw
418260684Skaiw	RCHECK(_dwarf_die_gen_recursive(dbg, cu, drs, die, 0, error));
419260684Skaiw
420260684Skaiw	if (cu->cu_pass2)
421260684Skaiw		RCHECK(_dwarf_die_gen_recursive(dbg, cu, drs, die, 1, error));
422260684Skaiw
423260684Skaiw	return (DW_DLE_NONE);
424260684Skaiw
425260684Skaiwgen_fail:
426260684Skaiw
427260684Skaiw	HASH_ITER(ab_hh, cu->cu_abbrev_hash, ab, tab) {
428260684Skaiw		HASH_DELETE(ab_hh, cu->cu_abbrev_hash, ab);
429260684Skaiw		STAILQ_FOREACH_SAFE(ad, &ab->ab_attrdef, ad_next, tad) {
430260684Skaiw			STAILQ_REMOVE(&ab->ab_attrdef, ad, _Dwarf_AttrDef,
431260684Skaiw			    ad_next);
432260684Skaiw			free(ad);
433260684Skaiw		}
434260684Skaiw		free(ab);
435260684Skaiw	}
436260684Skaiw
437260684Skaiw	return (ret);
438260684Skaiw}
439260684Skaiw
440260684Skaiwvoid
441260684Skaiw_dwarf_die_pro_cleanup(Dwarf_P_Debug dbg)
442260684Skaiw{
443260684Skaiw	Dwarf_P_Die die, tdie;
444260684Skaiw	Dwarf_P_Attribute at, tat;
445260684Skaiw
446260684Skaiw	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
447260684Skaiw
448260684Skaiw	STAILQ_FOREACH_SAFE(die, &dbg->dbgp_dielist, die_pro_next, tdie) {
449260684Skaiw		STAILQ_FOREACH_SAFE(at, &die->die_attr, at_next, tat) {
450260684Skaiw			STAILQ_REMOVE(&die->die_attr, at, _Dwarf_Attribute,
451260684Skaiw			    at_next);
452260684Skaiw			free(at);
453260684Skaiw		}
454260684Skaiw		free(die);
455260684Skaiw	}
456260684Skaiw}
457