1 /*	$NetBSD: dwarf_loclist.c,v 1.2 2014/03/09 16:58:04 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 Kai Wang
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "_libdwarf.h"
30 
31 __RCSID("$NetBSD: dwarf_loclist.c,v 1.2 2014/03/09 16:58:04 christos Exp $");
32 ELFTC_VCSID("Id: dwarf_loclist.c 2074 2011-10-27 03:34:33Z jkoshy ");
33 
34 int
dwarf_loclist_n(Dwarf_Attribute at,Dwarf_Locdesc *** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)35 dwarf_loclist_n(Dwarf_Attribute at, Dwarf_Locdesc ***llbuf,
36     Dwarf_Signed *listlen, Dwarf_Error *error)
37 {
38 	Dwarf_Loclist ll;
39 	Dwarf_Debug dbg;
40 	int ret;
41 
42 	dbg = at != NULL ? at->at_die->die_dbg : NULL;
43 
44 	if (at == NULL || llbuf == NULL || listlen == NULL) {
45 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
46 		return (DW_DLV_ERROR);
47 	}
48 
49 	switch (at->at_attrib) {
50 	case DW_AT_location:
51 	case DW_AT_string_length:
52 	case DW_AT_return_addr:
53 	case DW_AT_data_member_location:
54 	case DW_AT_frame_base:
55 	case DW_AT_segment:
56 	case DW_AT_static_link:
57 	case DW_AT_use_location:
58 	case DW_AT_vtable_elem_location:
59 		switch (at->at_form) {
60 		case DW_FORM_data4:
61 		case DW_FORM_data8:
62 			/*
63 			 * DW_FORM_data[48] can not be used as section offset
64 			 * since DWARF4. For DWARF[23], the application needs
65 			 * to determine if DW_FORM_data[48] is representing
66 			 * a constant or a section offset.
67 			 */
68 			if (at->at_die->die_cu->cu_version >= 4) {
69 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
70 				return (DW_DLV_NO_ENTRY);
71 			}
72 			/* FALLTHROUGH */
73 		case DW_FORM_sec_offset:
74 			ret = _dwarf_loclist_find(dbg, at->at_die->die_cu,
75 			    at->u[0].u64, &ll, error);
76 			if (ret == DW_DLE_NO_ENTRY) {
77 				DWARF_SET_ERROR(dbg, error, ret);
78 				return (DW_DLV_NO_ENTRY);
79 			}
80 			if (ret != DW_DLE_NONE)
81 				return (DW_DLV_ERROR);
82 			*llbuf = ll->ll_ldlist;
83 			*listlen = ll->ll_ldlen;
84 			return (DW_DLV_OK);
85 		case DW_FORM_block:
86 		case DW_FORM_block1:
87 		case DW_FORM_block2:
88 		case DW_FORM_block4:
89 			if (at->at_ld == NULL) {
90 				ret = _dwarf_loc_add(at->at_die, at, error);
91 				if (ret != DW_DLE_NONE)
92 					return (DW_DLV_ERROR);
93 			}
94 			*llbuf = &at->at_ld;
95 			*listlen = 1;
96 			return (DW_DLV_OK);
97 		default:
98 			/* Malformed Attr? */
99 			DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
100 			return (DW_DLV_NO_ENTRY);
101 		}
102 	default:
103 		/* Wrong attr supplied. */
104 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
105 		return (DW_DLV_ERROR);
106 	}
107 }
108 
109 int
dwarf_loclist(Dwarf_Attribute at,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)110 dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf,
111     Dwarf_Signed *listlen, Dwarf_Error *error)
112 {
113 	Dwarf_Loclist ll;
114 	Dwarf_Debug dbg;
115 	int ret;
116 
117 	dbg = at != NULL ? at->at_die->die_dbg : NULL;
118 
119 	if (at == NULL || llbuf == NULL || listlen == NULL) {
120 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
121 		return (DW_DLV_ERROR);
122 	}
123 
124 	switch (at->at_attrib) {
125 	case DW_AT_location:
126 	case DW_AT_string_length:
127 	case DW_AT_return_addr:
128 	case DW_AT_data_member_location:
129 	case DW_AT_frame_base:
130 	case DW_AT_segment:
131 	case DW_AT_static_link:
132 	case DW_AT_use_location:
133 	case DW_AT_vtable_elem_location:
134 		switch (at->at_form) {
135 		case DW_FORM_data4:
136 		case DW_FORM_data8:
137 			/*
138 			 * DW_FORM_data[48] can not be used as section offset
139 			 * since DWARF4. For DWARF[23], the application needs
140 			 * to determine if DW_FORM_data[48] is representing
141 			 * a constant or a section offset.
142 			 */
143 			if (at->at_die->die_cu->cu_version >= 4) {
144 				printf("called cu_version >= 4\n");
145 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
146 				return (DW_DLV_NO_ENTRY);
147 			}
148 			/* FALLTHROUGH */
149 		case DW_FORM_sec_offset:
150 			ret = _dwarf_loclist_find(at->at_die->die_dbg,
151 			    at->at_die->die_cu, at->u[0].u64, &ll, error);
152 			if (ret == DW_DLE_NO_ENTRY) {
153 				DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY);
154 				return (DW_DLV_NO_ENTRY);
155 			}
156 			if (ret != DW_DLE_NONE)
157 				return (DW_DLV_ERROR);
158 			*llbuf = ll->ll_ldlist[0];
159 			*listlen = 1;
160 			return (DW_DLV_OK);
161 		case DW_FORM_block:
162 		case DW_FORM_block1:
163 		case DW_FORM_block2:
164 		case DW_FORM_block4:
165 			if (at->at_ld == NULL) {
166 				ret = _dwarf_loc_add(at->at_die, at, error);
167 				if (ret != DW_DLE_NONE)
168 					return (DW_DLV_ERROR);
169 			}
170 			*llbuf = at->at_ld;
171 			*listlen = 1;
172 			return (DW_DLV_OK);
173 		default:
174 			DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
175 			return (DW_DLV_ERROR);
176 		}
177 	default:
178 		/* Wrong attr supplied. */
179 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
180 		return (DW_DLV_ERROR);
181 	}
182 }
183 
184 int
dwarf_get_loclist_entry(Dwarf_Debug dbg,Dwarf_Unsigned offset,Dwarf_Addr * hipc,Dwarf_Addr * lopc,Dwarf_Ptr * data,Dwarf_Unsigned * entry_len,Dwarf_Unsigned * next_entry,Dwarf_Error * error)185 dwarf_get_loclist_entry(Dwarf_Debug dbg, Dwarf_Unsigned offset,
186     Dwarf_Addr *hipc, Dwarf_Addr *lopc, Dwarf_Ptr *data,
187     Dwarf_Unsigned *entry_len, Dwarf_Unsigned *next_entry,
188     Dwarf_Error *error)
189 {
190 	Dwarf_Loclist ll, next_ll;
191 	Dwarf_Locdesc *ld;
192 	Dwarf_Section *ds;
193 	int i, ret;
194 
195 	if (dbg == NULL || hipc == NULL || lopc == NULL || data == NULL ||
196 	    entry_len == NULL || next_entry == NULL) {
197 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
198 		return (DW_DLV_ERROR);
199 	}
200 
201 	ret = _dwarf_loclist_find(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset, &ll,
202 	    error);
203 	if (ret == DW_DLE_NO_ENTRY) {
204 		DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY);
205 		return (DW_DLV_NO_ENTRY);
206 	} else if (ret != DW_DLE_NONE)
207 		return (DW_DLV_ERROR);
208 
209 	*hipc = *lopc = 0;
210 	for (i = 0; i < ll->ll_ldlen; i++) {
211 		ld = ll->ll_ldlist[i];
212 		if (i == 0) {
213 			*hipc = ld->ld_hipc;
214 			*lopc = ld->ld_lopc;
215 		} else {
216 			if (ld->ld_lopc < *lopc)
217 				*lopc = ld->ld_lopc;
218 			if (ld->ld_hipc > *hipc)
219 				*hipc = ld->ld_hipc;
220 		}
221 	}
222 
223 	ds = _dwarf_find_section(dbg, ".debug_loc");
224 	assert(ds != NULL);
225 	*data = (uint8_t *) ds->ds_data + ll->ll_offset;
226 	*entry_len = ll->ll_length;
227 
228 	next_ll = TAILQ_NEXT(ll, ll_next);
229 	if (next_ll != NULL)
230 		*next_entry = next_ll->ll_offset;
231 	else
232 		*next_entry = ds->ds_size;
233 
234 	return (DW_DLV_OK);
235 }
236 
237 int
dwarf_loclist_from_expr(Dwarf_Debug dbg,Dwarf_Ptr bytes_in,Dwarf_Unsigned bytes_len,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)238 dwarf_loclist_from_expr(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
239     Dwarf_Unsigned bytes_len, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
240     Dwarf_Error *error)
241 {
242 	Dwarf_Locdesc *ld;
243 	int ret;
244 
245 	if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
246 	    llbuf == NULL || listlen == NULL) {
247 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
248 		return (DW_DLV_ERROR);
249 	}
250 
251 	ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len,
252 	    dbg->dbg_pointer_size, error);
253 	if (ret != DW_DLE_NONE)
254 		return (DW_DLV_ERROR);
255 
256 	*llbuf = ld;
257 	*listlen = 1;
258 
259 	return (DW_DLV_OK);
260 }
261 
262 int
dwarf_loclist_from_expr_a(Dwarf_Debug dbg,Dwarf_Ptr bytes_in,Dwarf_Unsigned bytes_len,Dwarf_Half addr_size,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)263 dwarf_loclist_from_expr_a(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
264     Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Locdesc **llbuf,
265     Dwarf_Signed *listlen, Dwarf_Error *error)
266 {
267 	Dwarf_Locdesc *ld;
268 	int ret;
269 
270 	if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
271 	    llbuf == NULL || listlen == NULL) {
272 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
273 		return (DW_DLV_ERROR);
274 	}
275 
276 	if (addr_size != 4 && addr_size != 8) {
277 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
278 		return (DW_DLV_ERROR);
279 	}
280 
281 	ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, addr_size,
282 	    error);
283 	if (ret != DW_DLE_NONE)
284 		return (DW_DLV_ERROR);
285 
286 	*llbuf = ld;
287 	*listlen = 1;
288 
289 	return (DW_DLV_OK);
290 }
291