xref: /freebsd/contrib/elftoolchain/libdwarf/dwarf_loclist.c (revision 0572ccaa4543b0abef8ef81e384c1d04de9f3da1)
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 
29 ELFTC_VCSID("$Id: dwarf_loclist.c 2074 2011-10-27 03:34:33Z jkoshy $");
30 
31 int
32 dwarf_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 
106 int
107 dwarf_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 
181 int
182 dwarf_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 
234 int
235 dwarf_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 
259 int
260 dwarf_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