1/*-
2 * Copyright (c) 2007 John Birrell (jb@freebsd.org)
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 * $FreeBSD: releng/10.3/lib/libdwarf/dwarf_die.c 248641 2013-03-23 08:50:56Z avg $
27 */
28
29#include <stdlib.h>
30#include "_libdwarf.h"
31
32int
33dwarf_die_add(Dwarf_CU cu, int level, uint64_t offset, uint64_t abnum, Dwarf_Abbrev a, Dwarf_Die *diep, Dwarf_Error *err)
34{
35	Dwarf_Die die;
36	uint64_t key;
37	int ret = DWARF_E_NONE;
38
39	if (err == NULL)
40		return DWARF_E_ERROR;
41
42	if (cu == NULL || a == NULL) {
43		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
44		return DWARF_E_ARGUMENT;
45	}
46
47	if ((die = malloc(sizeof(struct _Dwarf_Die))) == NULL) {
48		DWARF_SET_ERROR(err, DWARF_E_MEMORY);
49		return DWARF_E_MEMORY;
50	}
51
52	/* Initialise the abbrev structure. */
53	die->die_level	= level;
54	die->die_offset	= offset;
55	die->die_abnum	= abnum;
56	die->die_a	= a;
57	die->die_cu	= cu;
58	die->die_name	= "";
59
60	/* Initialise the list of attribute values. */
61	STAILQ_INIT(&die->die_attrval);
62
63	/* Add the die to the list in the compilation unit. */
64	STAILQ_INSERT_TAIL(&cu->cu_die, die, die_next);
65
66	/* Add the die to the hash table in the compilation unit. */
67	key = offset % DWARF_DIE_HASH_SIZE;
68	STAILQ_INSERT_TAIL(&cu->cu_die_hash[key], die, die_hash);
69
70	if (diep != NULL)
71		*diep = die;
72
73	return ret;
74}
75
76int
77dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *err __unused)
78{
79	*ret_offset = die->die_offset;
80
81	return DWARF_E_NONE;
82}
83
84int
85dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *err)
86{
87	Dwarf_Die next;
88	int ret = DWARF_E_NONE;
89
90	if (err == NULL)
91		return DWARF_E_ERROR;
92
93	if (die == NULL || ret_die == NULL) {
94		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
95		return DWARF_E_ARGUMENT;
96	}
97
98	if ((next = STAILQ_NEXT(die, die_next)) == NULL ||
99	    next->die_level != die->die_level + 1) {
100		*ret_die = NULL;
101		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
102		ret = DWARF_E_NO_ENTRY;
103	} else
104		*ret_die = next;
105
106	return ret;
107}
108
109int
110dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *err)
111{
112	Dwarf_Abbrev a;
113
114	if (err == NULL)
115		return DWARF_E_ERROR;
116
117	if (die == NULL || tag == NULL || (a = die->die_a) == NULL) {
118		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
119		return DWARF_E_ARGUMENT;
120	}
121
122	*tag = a->a_tag;
123
124	return DWARF_E_NONE;
125}
126
127int
128dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *caller_ret_die, Dwarf_Error *err)
129{
130	Dwarf_Die next;
131	Dwarf_CU cu;
132	int ret = DWARF_E_NONE;
133
134	if (err == NULL)
135		return DWARF_E_ERROR;
136
137	if (dbg == NULL || caller_ret_die == NULL) {
138		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
139		return DWARF_E_ARGUMENT;
140	}
141
142	if ((cu = dbg->dbg_cu_current) == NULL) {
143		DWARF_SET_ERROR(err, DWARF_E_CU_CURRENT);
144		return DWARF_E_CU_CURRENT;
145	}
146
147	if (die == NULL) {
148		*caller_ret_die = STAILQ_FIRST(&cu->cu_die);
149
150		if (*caller_ret_die == NULL) {
151			DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
152			ret = DWARF_E_NO_ENTRY;
153		}
154	} else {
155		next = die;
156		while ((next = STAILQ_NEXT(next, die_next)) != NULL) {
157			if (next->die_level < die->die_level) {
158				next = NULL;
159				break;
160			}
161			if (next->die_level == die->die_level) {
162				*caller_ret_die = next;
163				break;
164			}
165		}
166
167		if (next == NULL) {
168			*caller_ret_die = NULL;
169			DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
170			ret = DWARF_E_NO_ENTRY;
171		}
172	}
173
174	return ret;
175}
176
177Dwarf_Die
178dwarf_die_find(Dwarf_Die die, Dwarf_Unsigned off)
179{
180	Dwarf_CU cu = die->die_cu;
181	Dwarf_Die die1;
182
183	STAILQ_FOREACH(die1, &cu->cu_die, die_next) {
184		if (die1->die_offset == off)
185			return (die1);
186	}
187
188	return (NULL);
189}
190