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
27#include "_libdwarf.h"
28
29ELFTC_VCSID("$Id: dwarf_attrval.c 3509 2016-12-29 03:58:41Z emaste $");
30
31int
32dwarf_attrval_flag(Dwarf_Die die, Dwarf_Half attr, Dwarf_Bool *valp, Dwarf_Error *err)
33{
34	Dwarf_Attribute at;
35	Dwarf_Debug dbg;
36
37	dbg = die != NULL ? die->die_dbg : NULL;
38
39	if (die == NULL || valp == NULL) {
40		DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT);
41		return (DW_DLV_ERROR);
42	}
43
44	*valp = 0;
45
46	if ((at = _dwarf_attr_find(die, attr)) == NULL) {
47		DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY);
48		return (DW_DLV_NO_ENTRY);
49	}
50
51	switch (at->at_form) {
52	case DW_FORM_flag:
53	case DW_FORM_flag_present:
54		*valp = (Dwarf_Bool) (!!at->u[0].u64);
55		break;
56	default:
57		DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD);
58		return (DW_DLV_ERROR);
59	}
60
61	return (DW_DLV_OK);
62}
63
64int
65dwarf_attrval_string(Dwarf_Die die, Dwarf_Half attr, const char **strp, Dwarf_Error *err)
66{
67	Dwarf_Attribute at;
68	Dwarf_Debug dbg;
69
70	dbg = die != NULL ? die->die_dbg : NULL;
71
72	if (die == NULL || strp == NULL) {
73		DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT);
74		return (DW_DLV_ERROR);
75	}
76
77	*strp = NULL;
78
79	if ((at = _dwarf_attr_find(die, attr)) == NULL) {
80		DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY);
81		return (DW_DLV_NO_ENTRY);
82	}
83
84	switch (at->at_form) {
85	case DW_FORM_strp:
86		*strp = at->u[1].s;
87		break;
88	case DW_FORM_string:
89		*strp = at->u[0].s;
90		break;
91	default:
92		DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD);
93		return (DW_DLV_ERROR);
94	}
95
96	return (DW_DLV_OK);
97}
98
99int
100dwarf_attrval_signed(Dwarf_Die die, Dwarf_Half attr, Dwarf_Signed *valp, Dwarf_Error *err)
101{
102	Dwarf_Attribute at;
103	Dwarf_Debug dbg;
104
105	dbg = die != NULL ? die->die_dbg : NULL;
106
107	if (die == NULL || valp == NULL) {
108		DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT);
109		return (DW_DLV_ERROR);
110	}
111
112	*valp = 0;
113
114	if ((at = _dwarf_attr_find(die, attr)) == NULL) {
115		DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY);
116		return (DW_DLV_NO_ENTRY);
117	}
118
119	switch (at->at_form) {
120	case DW_FORM_data1:
121		*valp = (int8_t) at->u[0].s64;
122		break;
123	case DW_FORM_data2:
124		*valp = (int16_t) at->u[0].s64;
125		break;
126	case DW_FORM_data4:
127		*valp = (int32_t) at->u[0].s64;
128		break;
129	case DW_FORM_data8:
130	case DW_FORM_sdata:
131		*valp = at->u[0].s64;
132		break;
133	default:
134		DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD);
135		return (DW_DLV_ERROR);
136	}
137
138	return (DW_DLV_OK);
139}
140
141int
142dwarf_attrval_unsigned(Dwarf_Die die, Dwarf_Half attr, Dwarf_Unsigned *valp, Dwarf_Error *err)
143{
144	Dwarf_Attribute at;
145	Dwarf_Die die1;
146	Dwarf_Unsigned val;
147	Dwarf_Debug dbg;
148	int first;
149
150	dbg = die != NULL ? die->die_dbg : NULL;
151
152	if (die == NULL || valp == NULL) {
153		DWARF_SET_ERROR(dbg, err, DW_DLE_ARGUMENT);
154		return (DW_DLV_ERROR);
155	}
156
157	*valp = 0;
158
159	die1 = NULL;
160	for (;;) {
161		if ((at = _dwarf_attr_find(die, attr)) != NULL ||
162		    attr != DW_AT_type)
163			break;
164		if ((at = _dwarf_attr_find(die, DW_AT_abstract_origin)) ==
165		    NULL &&
166		    (at = _dwarf_attr_find(die, DW_AT_specification)) == NULL)
167			break;
168
169		switch (at->at_form) {
170		case DW_FORM_ref1:
171		case DW_FORM_ref2:
172		case DW_FORM_ref4:
173		case DW_FORM_ref8:
174		case DW_FORM_ref_udata:
175			val = at->u[0].u64;
176			first = (die1 == NULL);
177			die1 = _dwarf_die_find(die, val);
178			if (!first)
179				dwarf_dealloc(dbg, die, DW_DLA_DIE);
180			if (die1 == NULL) {
181				DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY);
182				return (DW_DLV_NO_ENTRY);
183			}
184			die = die1;
185			break;
186		default:
187			DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD);
188			return (DW_DLV_ERROR);
189		}
190	}
191
192	if (at == NULL) {
193		DWARF_SET_ERROR(dbg, err, DW_DLE_NO_ENTRY);
194		return (DW_DLV_NO_ENTRY);
195	}
196
197	switch (at->at_form) {
198	case DW_FORM_addr:
199	case DW_FORM_data1:
200	case DW_FORM_data2:
201	case DW_FORM_data4:
202	case DW_FORM_data8:
203	case DW_FORM_udata:
204	case DW_FORM_ref1:
205	case DW_FORM_ref2:
206	case DW_FORM_ref4:
207	case DW_FORM_ref8:
208	case DW_FORM_ref_udata:
209		*valp = at->u[0].u64;
210		break;
211	default:
212		if (die1 != NULL)
213			dwarf_dealloc(dbg, die1, DW_DLA_DIE);
214		DWARF_SET_ERROR(dbg, err, DW_DLE_ATTR_FORM_BAD);
215		return (DW_DLV_ERROR);
216	}
217
218	if (die1 != NULL)
219		dwarf_dealloc(dbg, die1, DW_DLA_DIE);
220
221	return (DW_DLV_OK);
222}
223