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$
27 */
28
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32#include "_libdwarf.h"
33
34Dwarf_AttrValue
35dwarf_attrval_find(Dwarf_Die die, Dwarf_Half attr)
36{
37	Dwarf_AttrValue av;
38
39	STAILQ_FOREACH(av, &die->die_attrval, av_next) {
40		if (av->av_attrib == attr)
41			break;
42	}
43
44	return av;
45}
46
47int
48dwarf_attrval_add(Dwarf_Die die, Dwarf_AttrValue avref, Dwarf_AttrValue *avp, Dwarf_Error *error)
49{
50	Dwarf_AttrValue av;
51	int ret = DWARF_E_NONE;
52
53	if ((av = malloc(sizeof(struct _Dwarf_AttrValue))) == NULL) {
54		DWARF_SET_ERROR(error, DWARF_E_MEMORY);
55		return DWARF_E_MEMORY;
56	}
57
58	memcpy(av, avref, sizeof(struct _Dwarf_AttrValue));
59
60	/* Add the attribute value to the list in the die. */
61	STAILQ_INSERT_TAIL(&die->die_attrval, av, av_next);
62
63	/* Save a pointer to the attribute name if this is one. */
64	if (av->av_attrib == DW_AT_name)
65		switch (av->av_form) {
66		case DW_FORM_strp:
67			die->die_name = av->u[1].s;
68			break;
69		case DW_FORM_string:
70			die->die_name = av->u[0].s;
71			break;
72		default:
73			break;
74		}
75
76	if (avp != NULL)
77		*avp = av;
78
79	return ret;
80}
81
82int
83dwarf_attrval_flag(Dwarf_Die die, uint64_t attr, Dwarf_Bool *valp, Dwarf_Error *err)
84{
85	Dwarf_AttrValue av;
86	int ret = DWARF_E_NONE;
87
88	if (err == NULL)
89		return DWARF_E_ERROR;
90
91	if (die == NULL || valp == NULL) {
92		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
93		return DWARF_E_ARGUMENT;
94	}
95
96	*valp = 0;
97
98	if ((av = dwarf_attrval_find(die, attr)) == NULL) {
99		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
100		ret = DWARF_E_NO_ENTRY;
101	} else {
102		switch (av->av_form) {
103		case DW_FORM_flag:
104		case DW_FORM_flag_present:
105			*valp = (Dwarf_Bool) av->u[0].u64;
106			break;
107		default:
108			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
109			    __func__,__LINE__,get_form_desc(av->av_form),
110			    (u_long) av->av_form);
111			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
112			ret = DWARF_E_BAD_FORM;
113		}
114	}
115
116	return ret;
117}
118
119int
120dwarf_attrval_string(Dwarf_Die die, uint64_t attr, const char **strp, Dwarf_Error *err)
121{
122	Dwarf_AttrValue av;
123	int ret = DWARF_E_NONE;
124
125	if (err == NULL)
126		return DWARF_E_ERROR;
127
128	if (die == NULL || strp == NULL) {
129		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
130		return DWARF_E_ARGUMENT;
131	}
132
133	*strp = NULL;
134
135	if (attr == DW_AT_name)
136		*strp = die->die_name;
137	else if ((av = dwarf_attrval_find(die, attr)) == NULL) {
138		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
139		ret = DWARF_E_NO_ENTRY;
140	} else {
141		switch (av->av_form) {
142		case DW_FORM_strp:
143			*strp = av->u[1].s;
144			break;
145		case DW_FORM_string:
146			*strp = av->u[0].s;
147			break;
148		default:
149			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
150			    __func__,__LINE__,get_form_desc(av->av_form),
151			    (u_long) av->av_form);
152			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
153			ret = DWARF_E_BAD_FORM;
154		}
155	}
156
157	return ret;
158}
159
160int
161dwarf_attrval_signed(Dwarf_Die die, uint64_t attr, Dwarf_Signed *valp, Dwarf_Error *err)
162{
163	Dwarf_AttrValue av;
164	int ret = DWARF_E_NONE;
165
166	if (err == NULL)
167		return DWARF_E_ERROR;
168
169	if (die == NULL || valp == NULL) {
170		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
171		return DWARF_E_ARGUMENT;
172	}
173
174	*valp = 0;
175
176	if ((av = dwarf_attrval_find(die, attr)) == NULL) {
177		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
178		ret = DWARF_E_NO_ENTRY;
179	} else {
180		switch (av->av_form) {
181		case DW_FORM_data1:
182		case DW_FORM_sdata:
183			*valp = av->u[0].s64;
184			break;
185		default:
186			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
187			    __func__,__LINE__,get_form_desc(av->av_form),
188			    (u_long) av->av_form);
189			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
190			ret = DWARF_E_BAD_FORM;
191		}
192	}
193
194	return ret;
195}
196
197int
198dwarf_attrval_unsigned(Dwarf_Die die, uint64_t attr, Dwarf_Unsigned *valp, Dwarf_Error *err)
199{
200	Dwarf_AttrValue av;
201	int ret = DWARF_E_NONE;
202
203	if (err == NULL)
204		return DWARF_E_ERROR;
205
206	if (die == NULL || valp == NULL) {
207		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
208		return DWARF_E_ARGUMENT;
209	}
210
211	*valp = 0;
212
213	if ((av = dwarf_attrval_find(die, attr)) == NULL && attr != DW_AT_type) {
214		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
215		ret = DWARF_E_NO_ENTRY;
216	} else if (av == NULL && (av = dwarf_attrval_find(die,
217	    DW_AT_abstract_origin)) != NULL) {
218		Dwarf_Die die1;
219		Dwarf_Unsigned val;
220
221		switch (av->av_form) {
222		case DW_FORM_data1:
223		case DW_FORM_data2:
224		case DW_FORM_data4:
225		case DW_FORM_data8:
226		case DW_FORM_ref1:
227		case DW_FORM_ref2:
228		case DW_FORM_ref4:
229		case DW_FORM_ref8:
230		case DW_FORM_ref_udata:
231			val = av->u[0].u64;
232
233			if ((die1 = dwarf_die_find(die, val)) == NULL ||
234			    (av = dwarf_attrval_find(die1, attr)) == NULL) {
235				DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
236				ret = DWARF_E_NO_ENTRY;
237			}
238			break;
239		default:
240			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
241			    __func__,__LINE__,get_form_desc(av->av_form),
242			    (u_long) av->av_form);
243			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
244			ret = DWARF_E_BAD_FORM;
245		}
246	}
247
248	if (ret == DWARF_E_NONE) {
249		switch (av->av_form) {
250		case DW_FORM_data1:
251		case DW_FORM_data2:
252		case DW_FORM_data4:
253		case DW_FORM_data8:
254		case DW_FORM_ref1:
255		case DW_FORM_ref2:
256		case DW_FORM_ref4:
257		case DW_FORM_ref8:
258		case DW_FORM_ref_udata:
259			*valp = av->u[0].u64;
260			break;
261		default:
262			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
263			    __func__,__LINE__,get_form_desc(av->av_form),
264			    (u_long) av->av_form);
265			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
266			ret = DWARF_E_BAD_FORM;
267		}
268	}
269
270	return ret;
271}
272