1179187Sjb/*-
2179187Sjb * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3179187Sjb * All rights reserved.
4179187Sjb *
5179187Sjb * Redistribution and use in source and binary forms, with or without
6179187Sjb * modification, are permitted provided that the following conditions
7179187Sjb * are met:
8179187Sjb * 1. Redistributions of source code must retain the above copyright
9179187Sjb *    notice, this list of conditions and the following disclaimer.
10179187Sjb * 2. Redistributions in binary form must reproduce the above copyright
11179187Sjb *    notice, this list of conditions and the following disclaimer in the
12179187Sjb *    documentation and/or other materials provided with the distribution.
13179187Sjb *
14179187Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15179187Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16179187Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17179187Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18179187Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19179187Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20179187Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21179187Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22179187Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23179187Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24179187Sjb * SUCH DAMAGE.
25179187Sjb *
26179187Sjb * $FreeBSD$
27179187Sjb */
28179187Sjb
29179187Sjb#include <stdlib.h>
30179187Sjb#include <string.h>
31179187Sjb#include <unistd.h>
32179187Sjb#include "_libdwarf.h"
33179187Sjb
34179187SjbDwarf_AttrValue
35179187Sjbdwarf_attrval_find(Dwarf_Die die, Dwarf_Half attr)
36179187Sjb{
37179187Sjb	Dwarf_AttrValue av;
38179187Sjb
39179187Sjb	STAILQ_FOREACH(av, &die->die_attrval, av_next) {
40179187Sjb		if (av->av_attrib == attr)
41179187Sjb			break;
42179187Sjb	}
43179187Sjb
44179187Sjb	return av;
45179187Sjb}
46179187Sjb
47179187Sjbint
48179187Sjbdwarf_attrval_add(Dwarf_Die die, Dwarf_AttrValue avref, Dwarf_AttrValue *avp, Dwarf_Error *error)
49179187Sjb{
50179187Sjb	Dwarf_AttrValue av;
51179187Sjb	int ret = DWARF_E_NONE;
52179187Sjb
53179187Sjb	if ((av = malloc(sizeof(struct _Dwarf_AttrValue))) == NULL) {
54179187Sjb		DWARF_SET_ERROR(error, DWARF_E_MEMORY);
55179187Sjb		return DWARF_E_MEMORY;
56179187Sjb	}
57179187Sjb
58179187Sjb	memcpy(av, avref, sizeof(struct _Dwarf_AttrValue));
59179187Sjb
60179187Sjb	/* Add the attribute value to the list in the die. */
61179187Sjb	STAILQ_INSERT_TAIL(&die->die_attrval, av, av_next);
62179187Sjb
63179187Sjb	/* Save a pointer to the attribute name if this is one. */
64179187Sjb	if (av->av_attrib == DW_AT_name)
65179187Sjb		switch (av->av_form) {
66179187Sjb		case DW_FORM_strp:
67179187Sjb			die->die_name = av->u[1].s;
68179187Sjb			break;
69179187Sjb		case DW_FORM_string:
70179187Sjb			die->die_name = av->u[0].s;
71179187Sjb			break;
72179187Sjb		default:
73179187Sjb			break;
74179187Sjb		}
75179187Sjb
76179187Sjb	if (avp != NULL)
77179187Sjb		*avp = av;
78179187Sjb
79179187Sjb	return ret;
80179187Sjb}
81179187Sjb
82179187Sjbint
83179187Sjbdwarf_attrval_flag(Dwarf_Die die, uint64_t attr, Dwarf_Bool *valp, Dwarf_Error *err)
84179187Sjb{
85179187Sjb	Dwarf_AttrValue av;
86179187Sjb	int ret = DWARF_E_NONE;
87179187Sjb
88179187Sjb	if (err == NULL)
89179187Sjb		return DWARF_E_ERROR;
90179187Sjb
91179187Sjb	if (die == NULL || valp == NULL) {
92179187Sjb		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
93179187Sjb		return DWARF_E_ARGUMENT;
94179187Sjb	}
95179187Sjb
96179187Sjb	*valp = 0;
97179187Sjb
98179187Sjb	if ((av = dwarf_attrval_find(die, attr)) == NULL) {
99179187Sjb		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
100179187Sjb		ret = DWARF_E_NO_ENTRY;
101179187Sjb	} else {
102179187Sjb		switch (av->av_form) {
103179187Sjb		case DW_FORM_flag:
104239872Sdim		case DW_FORM_flag_present:
105179187Sjb			*valp = (Dwarf_Bool) av->u[0].u64;
106179187Sjb			break;
107179187Sjb		default:
108179187Sjb			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
109179187Sjb			    __func__,__LINE__,get_form_desc(av->av_form),
110179187Sjb			    (u_long) av->av_form);
111179187Sjb			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
112179187Sjb			ret = DWARF_E_BAD_FORM;
113179187Sjb		}
114179187Sjb	}
115179187Sjb
116179187Sjb	return ret;
117179187Sjb}
118179187Sjb
119179187Sjbint
120179187Sjbdwarf_attrval_string(Dwarf_Die die, uint64_t attr, const char **strp, Dwarf_Error *err)
121179187Sjb{
122179187Sjb	Dwarf_AttrValue av;
123179187Sjb	int ret = DWARF_E_NONE;
124179187Sjb
125179187Sjb	if (err == NULL)
126179187Sjb		return DWARF_E_ERROR;
127179187Sjb
128179187Sjb	if (die == NULL || strp == NULL) {
129179187Sjb		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
130179187Sjb		return DWARF_E_ARGUMENT;
131179187Sjb	}
132179187Sjb
133179187Sjb	*strp = NULL;
134179187Sjb
135179187Sjb	if (attr == DW_AT_name)
136179187Sjb		*strp = die->die_name;
137179187Sjb	else if ((av = dwarf_attrval_find(die, attr)) == NULL) {
138179187Sjb		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
139179187Sjb		ret = DWARF_E_NO_ENTRY;
140179187Sjb	} else {
141179187Sjb		switch (av->av_form) {
142179187Sjb		case DW_FORM_strp:
143179187Sjb			*strp = av->u[1].s;
144179187Sjb			break;
145179187Sjb		case DW_FORM_string:
146179187Sjb			*strp = av->u[0].s;
147179187Sjb			break;
148179187Sjb		default:
149179187Sjb			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
150179187Sjb			    __func__,__LINE__,get_form_desc(av->av_form),
151179187Sjb			    (u_long) av->av_form);
152179187Sjb			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
153179187Sjb			ret = DWARF_E_BAD_FORM;
154179187Sjb		}
155179187Sjb	}
156179187Sjb
157179187Sjb	return ret;
158179187Sjb}
159179187Sjb
160179187Sjbint
161179187Sjbdwarf_attrval_signed(Dwarf_Die die, uint64_t attr, Dwarf_Signed *valp, Dwarf_Error *err)
162179187Sjb{
163179187Sjb	Dwarf_AttrValue av;
164179187Sjb	int ret = DWARF_E_NONE;
165179187Sjb
166179187Sjb	if (err == NULL)
167179187Sjb		return DWARF_E_ERROR;
168179187Sjb
169179187Sjb	if (die == NULL || valp == NULL) {
170179187Sjb		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
171179187Sjb		return DWARF_E_ARGUMENT;
172179187Sjb	}
173179187Sjb
174179187Sjb	*valp = 0;
175179187Sjb
176179187Sjb	if ((av = dwarf_attrval_find(die, attr)) == NULL) {
177179187Sjb		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
178179187Sjb		ret = DWARF_E_NO_ENTRY;
179179187Sjb	} else {
180179187Sjb		switch (av->av_form) {
181179187Sjb		case DW_FORM_data1:
182179187Sjb		case DW_FORM_sdata:
183179187Sjb			*valp = av->u[0].s64;
184179187Sjb			break;
185179187Sjb		default:
186179187Sjb			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
187179187Sjb			    __func__,__LINE__,get_form_desc(av->av_form),
188179187Sjb			    (u_long) av->av_form);
189179187Sjb			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
190179187Sjb			ret = DWARF_E_BAD_FORM;
191179187Sjb		}
192179187Sjb	}
193179187Sjb
194179187Sjb	return ret;
195179187Sjb}
196179187Sjb
197179187Sjbint
198179187Sjbdwarf_attrval_unsigned(Dwarf_Die die, uint64_t attr, Dwarf_Unsigned *valp, Dwarf_Error *err)
199179187Sjb{
200179187Sjb	Dwarf_AttrValue av;
201179187Sjb	int ret = DWARF_E_NONE;
202179187Sjb
203179187Sjb	if (err == NULL)
204179187Sjb		return DWARF_E_ERROR;
205179187Sjb
206179187Sjb	if (die == NULL || valp == NULL) {
207179187Sjb		DWARF_SET_ERROR(err, DWARF_E_ARGUMENT);
208179187Sjb		return DWARF_E_ARGUMENT;
209179187Sjb	}
210179187Sjb
211179187Sjb	*valp = 0;
212179187Sjb
213179187Sjb	if ((av = dwarf_attrval_find(die, attr)) == NULL && attr != DW_AT_type) {
214179187Sjb		DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
215179187Sjb		ret = DWARF_E_NO_ENTRY;
216179187Sjb	} else if (av == NULL && (av = dwarf_attrval_find(die,
217179187Sjb	    DW_AT_abstract_origin)) != NULL) {
218179187Sjb		Dwarf_Die die1;
219179187Sjb		Dwarf_Unsigned val;
220179187Sjb
221179187Sjb		switch (av->av_form) {
222179187Sjb		case DW_FORM_data1:
223179187Sjb		case DW_FORM_data2:
224179187Sjb		case DW_FORM_data4:
225179187Sjb		case DW_FORM_data8:
226179187Sjb		case DW_FORM_ref1:
227179187Sjb		case DW_FORM_ref2:
228179187Sjb		case DW_FORM_ref4:
229179187Sjb		case DW_FORM_ref8:
230179187Sjb		case DW_FORM_ref_udata:
231179187Sjb			val = av->u[0].u64;
232179187Sjb
233179187Sjb			if ((die1 = dwarf_die_find(die, val)) == NULL ||
234179187Sjb			    (av = dwarf_attrval_find(die1, attr)) == NULL) {
235179187Sjb				DWARF_SET_ERROR(err, DWARF_E_NO_ENTRY);
236179187Sjb				ret = DWARF_E_NO_ENTRY;
237179187Sjb			}
238179187Sjb			break;
239179187Sjb		default:
240179187Sjb			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
241179187Sjb			    __func__,__LINE__,get_form_desc(av->av_form),
242179187Sjb			    (u_long) av->av_form);
243179187Sjb			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
244179187Sjb			ret = DWARF_E_BAD_FORM;
245179187Sjb		}
246179187Sjb	}
247179187Sjb
248179187Sjb	if (ret == DWARF_E_NONE) {
249179187Sjb		switch (av->av_form) {
250179187Sjb		case DW_FORM_data1:
251179187Sjb		case DW_FORM_data2:
252179187Sjb		case DW_FORM_data4:
253179187Sjb		case DW_FORM_data8:
254179187Sjb		case DW_FORM_ref1:
255179187Sjb		case DW_FORM_ref2:
256179187Sjb		case DW_FORM_ref4:
257179187Sjb		case DW_FORM_ref8:
258179187Sjb		case DW_FORM_ref_udata:
259179187Sjb			*valp = av->u[0].u64;
260179187Sjb			break;
261179187Sjb		default:
262179187Sjb			printf("%s(%d): av->av_form '%s' (0x%lx) not handled\n",
263179187Sjb			    __func__,__LINE__,get_form_desc(av->av_form),
264179187Sjb			    (u_long) av->av_form);
265179187Sjb			DWARF_SET_ERROR(err, DWARF_E_BAD_FORM);
266179187Sjb			ret = DWARF_E_BAD_FORM;
267179187Sjb		}
268179187Sjb	}
269179187Sjb
270179187Sjb	return ret;
271179187Sjb}
272