dwarf_loclist.c revision 260879
1/*-
2 * Copyright (c) 2009 Kai Wang
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_loclist.c 2074 2011-10-27 03:34:33Z jkoshy $");
30
31int
32dwarf_loclist_n(Dwarf_Attribute at, Dwarf_Locdesc ***llbuf,
33    Dwarf_Signed *listlen, Dwarf_Error *error)
34{
35	Dwarf_Loclist ll;
36	Dwarf_Debug dbg;
37	int ret;
38
39	dbg = at != NULL ? at->at_die->die_dbg : NULL;
40
41	if (at == NULL || llbuf == NULL || listlen == NULL) {
42		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
43		return (DW_DLV_ERROR);
44	}
45
46	switch (at->at_attrib) {
47	case DW_AT_location:
48	case DW_AT_string_length:
49	case DW_AT_return_addr:
50	case DW_AT_data_member_location:
51	case DW_AT_frame_base:
52	case DW_AT_segment:
53	case DW_AT_static_link:
54	case DW_AT_use_location:
55	case DW_AT_vtable_elem_location:
56		switch (at->at_form) {
57		case DW_FORM_data4:
58		case DW_FORM_data8:
59			/*
60			 * DW_FORM_data[48] can not be used as section offset
61			 * since DWARF4. For DWARF[23], the application needs
62			 * to determine if DW_FORM_data[48] is representing
63			 * a constant or a section offset.
64			 */
65			if (at->at_die->die_cu->cu_version >= 4) {
66				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
67				return (DW_DLV_NO_ENTRY);
68			}
69			/* FALLTHROUGH */
70		case DW_FORM_sec_offset:
71			ret = _dwarf_loclist_find(dbg, at->at_die->die_cu,
72			    at->u[0].u64, &ll, error);
73			if (ret == DW_DLE_NO_ENTRY) {
74				DWARF_SET_ERROR(dbg, error, ret);
75				return (DW_DLV_NO_ENTRY);
76			}
77			if (ret != DW_DLE_NONE)
78				return (DW_DLV_ERROR);
79			*llbuf = ll->ll_ldlist;
80			*listlen = ll->ll_ldlen;
81			return (DW_DLV_OK);
82		case DW_FORM_block:
83		case DW_FORM_block1:
84		case DW_FORM_block2:
85		case DW_FORM_block4:
86			if (at->at_ld == NULL) {
87				ret = _dwarf_loc_add(at->at_die, at, error);
88				if (ret != DW_DLE_NONE)
89					return (DW_DLV_ERROR);
90			}
91			*llbuf = &at->at_ld;
92			*listlen = 1;
93			return (DW_DLV_OK);
94		default:
95			/* Malformed Attr? */
96			DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
97			return (DW_DLV_NO_ENTRY);
98		}
99	default:
100		/* Wrong attr supplied. */
101		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
102		return (DW_DLV_ERROR);
103	}
104}
105
106int
107dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf,
108    Dwarf_Signed *listlen, Dwarf_Error *error)
109{
110	Dwarf_Loclist ll;
111	Dwarf_Debug dbg;
112	int ret;
113
114	dbg = at != NULL ? at->at_die->die_dbg : NULL;
115
116	if (at == NULL || llbuf == NULL || listlen == NULL) {
117		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
118		return (DW_DLV_ERROR);
119	}
120
121	switch (at->at_attrib) {
122	case DW_AT_location:
123	case DW_AT_string_length:
124	case DW_AT_return_addr:
125	case DW_AT_data_member_location:
126	case DW_AT_frame_base:
127	case DW_AT_segment:
128	case DW_AT_static_link:
129	case DW_AT_use_location:
130	case DW_AT_vtable_elem_location:
131		switch (at->at_form) {
132		case DW_FORM_data4:
133		case DW_FORM_data8:
134			/*
135			 * DW_FORM_data[48] can not be used as section offset
136			 * since DWARF4. For DWARF[23], the application needs
137			 * to determine if DW_FORM_data[48] is representing
138			 * a constant or a section offset.
139			 */
140			if (at->at_die->die_cu->cu_version >= 4) {
141				printf("called cu_version >= 4\n");
142				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
143				return (DW_DLV_NO_ENTRY);
144			}
145			/* FALLTHROUGH */
146		case DW_FORM_sec_offset:
147			ret = _dwarf_loclist_find(at->at_die->die_dbg,
148			    at->at_die->die_cu, at->u[0].u64, &ll, error);
149			if (ret == DW_DLE_NO_ENTRY) {
150				DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY);
151				return (DW_DLV_NO_ENTRY);
152			}
153			if (ret != DW_DLE_NONE)
154				return (DW_DLV_ERROR);
155			*llbuf = ll->ll_ldlist[0];
156			*listlen = 1;
157			return (DW_DLV_OK);
158		case DW_FORM_block:
159		case DW_FORM_block1:
160		case DW_FORM_block2:
161		case DW_FORM_block4:
162			if (at->at_ld == NULL) {
163				ret = _dwarf_loc_add(at->at_die, at, error);
164				if (ret != DW_DLE_NONE)
165					return (DW_DLV_ERROR);
166			}
167			*llbuf = at->at_ld;
168			*listlen = 1;
169			return (DW_DLV_OK);
170		default:
171			DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
172			return (DW_DLV_ERROR);
173		}
174	default:
175		/* Wrong attr supplied. */
176		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
177		return (DW_DLV_ERROR);
178	}
179}
180
181int
182dwarf_get_loclist_entry(Dwarf_Debug dbg, Dwarf_Unsigned offset,
183    Dwarf_Addr *hipc, Dwarf_Addr *lopc, Dwarf_Ptr *data,
184    Dwarf_Unsigned *entry_len, Dwarf_Unsigned *next_entry,
185    Dwarf_Error *error)
186{
187	Dwarf_Loclist ll, next_ll;
188	Dwarf_Locdesc *ld;
189	Dwarf_Section *ds;
190	int i, ret;
191
192	if (dbg == NULL || hipc == NULL || lopc == NULL || data == NULL ||
193	    entry_len == NULL || next_entry == NULL) {
194		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
195		return (DW_DLV_ERROR);
196	}
197
198	ret = _dwarf_loclist_find(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset, &ll,
199	    error);
200	if (ret == DW_DLE_NO_ENTRY) {
201		DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY);
202		return (DW_DLV_NO_ENTRY);
203	} else if (ret != DW_DLE_NONE)
204		return (DW_DLV_ERROR);
205
206	*hipc = *lopc = 0;
207	for (i = 0; i < ll->ll_ldlen; i++) {
208		ld = ll->ll_ldlist[i];
209		if (i == 0) {
210			*hipc = ld->ld_hipc;
211			*lopc = ld->ld_lopc;
212		} else {
213			if (ld->ld_lopc < *lopc)
214				*lopc = ld->ld_lopc;
215			if (ld->ld_hipc > *hipc)
216				*hipc = ld->ld_hipc;
217		}
218	}
219
220	ds = _dwarf_find_section(dbg, ".debug_loc");
221	assert(ds != NULL);
222	*data = (uint8_t *) ds->ds_data + ll->ll_offset;
223	*entry_len = ll->ll_length;
224
225	next_ll = TAILQ_NEXT(ll, ll_next);
226	if (next_ll != NULL)
227		*next_entry = next_ll->ll_offset;
228	else
229		*next_entry = ds->ds_size;
230
231	return (DW_DLV_OK);
232}
233
234int
235dwarf_loclist_from_expr(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
236    Dwarf_Unsigned bytes_len, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
237    Dwarf_Error *error)
238{
239	Dwarf_Locdesc *ld;
240	int ret;
241
242	if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
243	    llbuf == NULL || listlen == NULL) {
244		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
245		return (DW_DLV_ERROR);
246	}
247
248	ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len,
249	    dbg->dbg_pointer_size, error);
250	if (ret != DW_DLE_NONE)
251		return (DW_DLV_ERROR);
252
253	*llbuf = ld;
254	*listlen = 1;
255
256	return (DW_DLV_OK);
257}
258
259int
260dwarf_loclist_from_expr_a(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
261    Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Locdesc **llbuf,
262    Dwarf_Signed *listlen, Dwarf_Error *error)
263{
264	Dwarf_Locdesc *ld;
265	int ret;
266
267	if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
268	    llbuf == NULL || listlen == NULL) {
269		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
270		return (DW_DLV_ERROR);
271	}
272
273	if (addr_size != 4 && addr_size != 8) {
274		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
275		return (DW_DLV_ERROR);
276	}
277
278	ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, addr_size,
279	    error);
280	if (ret != DW_DLE_NONE)
281		return (DW_DLV_ERROR);
282
283	*llbuf = ld;
284	*listlen = 1;
285
286	return (DW_DLV_OK);
287}
288