xref: /freebsd/contrib/elftoolchain/libdwarf/dwarf_loclist.c (revision 98e0ffaefb0f241cda3a72395d3be04192ae0d47)
12de3b87aSKai Wang /*-
2*cf781b2eSEd Maste  * Copyright (c) 2009,2014 Kai Wang
32de3b87aSKai Wang  * All rights reserved.
42de3b87aSKai Wang  *
52de3b87aSKai Wang  * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang  * modification, are permitted provided that the following conditions
72de3b87aSKai Wang  * are met:
82de3b87aSKai Wang  * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang  * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang  *    documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang  *
142de3b87aSKai Wang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152de3b87aSKai Wang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang  * SUCH DAMAGE.
252de3b87aSKai Wang  */
262de3b87aSKai Wang 
272de3b87aSKai Wang #include "_libdwarf.h"
282de3b87aSKai Wang 
29*cf781b2eSEd Maste ELFTC_VCSID("$Id: dwarf_loclist.c 3066 2014-06-06 19:36:06Z kaiwang27 $");
30*cf781b2eSEd Maste 
31*cf781b2eSEd Maste static int
copy_locdesc(Dwarf_Debug dbg,Dwarf_Locdesc * dst,Dwarf_Locdesc * src,Dwarf_Error * error)32*cf781b2eSEd Maste copy_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *dst, Dwarf_Locdesc *src,
33*cf781b2eSEd Maste     Dwarf_Error *error)
34*cf781b2eSEd Maste {
35*cf781b2eSEd Maste 
36*cf781b2eSEd Maste 	assert(src != NULL && dst != NULL);
37*cf781b2eSEd Maste 
38*cf781b2eSEd Maste 	dst->ld_lopc = src->ld_lopc;
39*cf781b2eSEd Maste 	dst->ld_hipc = src->ld_hipc;
40*cf781b2eSEd Maste 	dst->ld_cents = src->ld_cents;
41*cf781b2eSEd Maste 
42*cf781b2eSEd Maste 	if (dst->ld_cents > 0) {
43*cf781b2eSEd Maste 		dst->ld_s = calloc(dst->ld_cents, sizeof(Dwarf_Loc));
44*cf781b2eSEd Maste 		if (dst->ld_s == NULL) {
45*cf781b2eSEd Maste 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
46*cf781b2eSEd Maste 			return (DW_DLE_MEMORY);
47*cf781b2eSEd Maste 		}
48*cf781b2eSEd Maste 		memcpy(dst->ld_s, src->ld_s, src->ld_cents *
49*cf781b2eSEd Maste 		    sizeof(Dwarf_Loc));
50*cf781b2eSEd Maste 	} else
51*cf781b2eSEd Maste 		dst->ld_s = NULL;
52*cf781b2eSEd Maste 
53*cf781b2eSEd Maste 	return (DW_DLE_NONE);
54*cf781b2eSEd Maste }
552de3b87aSKai Wang 
562de3b87aSKai Wang int
dwarf_loclist_n(Dwarf_Attribute at,Dwarf_Locdesc *** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)572de3b87aSKai Wang dwarf_loclist_n(Dwarf_Attribute at, Dwarf_Locdesc ***llbuf,
582de3b87aSKai Wang     Dwarf_Signed *listlen, Dwarf_Error *error)
592de3b87aSKai Wang {
602de3b87aSKai Wang 	Dwarf_Debug dbg;
612de3b87aSKai Wang 	int ret;
622de3b87aSKai Wang 
632de3b87aSKai Wang 	dbg = at != NULL ? at->at_die->die_dbg : NULL;
642de3b87aSKai Wang 
652de3b87aSKai Wang 	if (at == NULL || llbuf == NULL || listlen == NULL) {
662de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
672de3b87aSKai Wang 		return (DW_DLV_ERROR);
682de3b87aSKai Wang 	}
692de3b87aSKai Wang 
702de3b87aSKai Wang 	switch (at->at_attrib) {
712de3b87aSKai Wang 	case DW_AT_location:
722de3b87aSKai Wang 	case DW_AT_string_length:
732de3b87aSKai Wang 	case DW_AT_return_addr:
742de3b87aSKai Wang 	case DW_AT_data_member_location:
752de3b87aSKai Wang 	case DW_AT_frame_base:
762de3b87aSKai Wang 	case DW_AT_segment:
772de3b87aSKai Wang 	case DW_AT_static_link:
782de3b87aSKai Wang 	case DW_AT_use_location:
792de3b87aSKai Wang 	case DW_AT_vtable_elem_location:
802de3b87aSKai Wang 		switch (at->at_form) {
812de3b87aSKai Wang 		case DW_FORM_data4:
822de3b87aSKai Wang 		case DW_FORM_data8:
83bc5fce8dSKai Wang 			/*
84bc5fce8dSKai Wang 			 * DW_FORM_data[48] can not be used as section offset
85bc5fce8dSKai Wang 			 * since DWARF4. For DWARF[23], the application needs
86bc5fce8dSKai Wang 			 * to determine if DW_FORM_data[48] is representing
87bc5fce8dSKai Wang 			 * a constant or a section offset.
88bc5fce8dSKai Wang 			 */
89bc5fce8dSKai Wang 			if (at->at_die->die_cu->cu_version >= 4) {
90bc5fce8dSKai Wang 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
91bc5fce8dSKai Wang 				return (DW_DLV_NO_ENTRY);
92bc5fce8dSKai Wang 			}
93bc5fce8dSKai Wang 			/* FALLTHROUGH */
94bc5fce8dSKai Wang 		case DW_FORM_sec_offset:
95bc5fce8dSKai Wang 			ret = _dwarf_loclist_find(dbg, at->at_die->die_cu,
96*cf781b2eSEd Maste 			    at->u[0].u64, llbuf, listlen, NULL, error);
972de3b87aSKai Wang 			if (ret == DW_DLE_NO_ENTRY) {
982de3b87aSKai Wang 				DWARF_SET_ERROR(dbg, error, ret);
992de3b87aSKai Wang 				return (DW_DLV_NO_ENTRY);
1002de3b87aSKai Wang 			}
1012de3b87aSKai Wang 			if (ret != DW_DLE_NONE)
1022de3b87aSKai Wang 				return (DW_DLV_ERROR);
1032de3b87aSKai Wang 			return (DW_DLV_OK);
1042de3b87aSKai Wang 		case DW_FORM_block:
1052de3b87aSKai Wang 		case DW_FORM_block1:
1062de3b87aSKai Wang 		case DW_FORM_block2:
1072de3b87aSKai Wang 		case DW_FORM_block4:
108*cf781b2eSEd Maste 		case DW_FORM_exprloc:
1092de3b87aSKai Wang 			if (at->at_ld == NULL) {
1102de3b87aSKai Wang 				ret = _dwarf_loc_add(at->at_die, at, error);
1112de3b87aSKai Wang 				if (ret != DW_DLE_NONE)
1122de3b87aSKai Wang 					return (DW_DLV_ERROR);
1132de3b87aSKai Wang 			}
114*cf781b2eSEd Maste 			*llbuf = calloc(1, sizeof(Dwarf_Locdesc *));
115*cf781b2eSEd Maste 			if (*llbuf == NULL) {
116*cf781b2eSEd Maste 				DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
117*cf781b2eSEd Maste 				return (DW_DLV_ERROR);
118*cf781b2eSEd Maste 			}
119*cf781b2eSEd Maste 			(*llbuf)[0] = calloc(1, sizeof(Dwarf_Locdesc));
120*cf781b2eSEd Maste 			if ((*llbuf)[0] == NULL) {
121*cf781b2eSEd Maste 				free(*llbuf);
122*cf781b2eSEd Maste 				DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
123*cf781b2eSEd Maste 				return (DW_DLV_ERROR);
124*cf781b2eSEd Maste 			}
125*cf781b2eSEd Maste 			if (copy_locdesc(dbg, (*llbuf)[0], at->at_ld, error) !=
126*cf781b2eSEd Maste 			    DW_DLE_NONE) {
127*cf781b2eSEd Maste 				free((*llbuf)[0]);
128*cf781b2eSEd Maste 				free(*llbuf);
129*cf781b2eSEd Maste 				return (DW_DLV_ERROR);
130*cf781b2eSEd Maste 			}
1312de3b87aSKai Wang 			*listlen = 1;
1322de3b87aSKai Wang 			return (DW_DLV_OK);
1332de3b87aSKai Wang 		default:
1342de3b87aSKai Wang 			/* Malformed Attr? */
1352de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
1362de3b87aSKai Wang 			return (DW_DLV_NO_ENTRY);
1372de3b87aSKai Wang 		}
1382de3b87aSKai Wang 	default:
1392de3b87aSKai Wang 		/* Wrong attr supplied. */
1402de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
1412de3b87aSKai Wang 		return (DW_DLV_ERROR);
1422de3b87aSKai Wang 	}
1432de3b87aSKai Wang }
1442de3b87aSKai Wang 
1452de3b87aSKai Wang int
dwarf_loclist(Dwarf_Attribute at,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)1462de3b87aSKai Wang dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf,
1472de3b87aSKai Wang     Dwarf_Signed *listlen, Dwarf_Error *error)
1482de3b87aSKai Wang {
149*cf781b2eSEd Maste 	Dwarf_Locdesc **_llbuf;
150*cf781b2eSEd Maste 	int i, ret;
1512de3b87aSKai Wang 
152*cf781b2eSEd Maste 	ret = dwarf_loclist_n(at, &_llbuf, listlen, error);
153*cf781b2eSEd Maste 	if (ret != DW_DLV_OK)
154*cf781b2eSEd Maste 		return (ret);
1552de3b87aSKai Wang 
156*cf781b2eSEd Maste 	/* Only return the first location description of the list. */
157*cf781b2eSEd Maste 	*llbuf = _llbuf[0];
1582de3b87aSKai Wang 
159*cf781b2eSEd Maste 	/* Free the rest of the list. */
160*cf781b2eSEd Maste 	for (i = 1; i < *listlen; i++) {
161*cf781b2eSEd Maste 		if (_llbuf[i]->ld_s)
162*cf781b2eSEd Maste 			free(_llbuf[i]->ld_s);
163*cf781b2eSEd Maste 		free(_llbuf[i]);
164bc5fce8dSKai Wang 	}
165*cf781b2eSEd Maste 	free(_llbuf);
166*cf781b2eSEd Maste 
1672de3b87aSKai Wang 	*listlen = 1;
168*cf781b2eSEd Maste 
1692de3b87aSKai Wang 	return (DW_DLV_OK);
1702de3b87aSKai Wang }
1712de3b87aSKai Wang 
1722de3b87aSKai Wang 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)1732de3b87aSKai Wang dwarf_get_loclist_entry(Dwarf_Debug dbg, Dwarf_Unsigned offset,
1742de3b87aSKai Wang     Dwarf_Addr *hipc, Dwarf_Addr *lopc, Dwarf_Ptr *data,
1752de3b87aSKai Wang     Dwarf_Unsigned *entry_len, Dwarf_Unsigned *next_entry,
1762de3b87aSKai Wang     Dwarf_Error *error)
1772de3b87aSKai Wang {
178*cf781b2eSEd Maste 	Dwarf_Locdesc *ld, **llbuf;
1792de3b87aSKai Wang 	Dwarf_Section *ds;
180*cf781b2eSEd Maste 	Dwarf_Signed listlen;
1812de3b87aSKai Wang 	int i, ret;
1822de3b87aSKai Wang 
183*cf781b2eSEd Maste 	/*
184*cf781b2eSEd Maste 	 * Note that this API sometimes will not work correctly because
185*cf781b2eSEd Maste 	 * it assumes that all units have the same pointer size and offset
186*cf781b2eSEd Maste 	 * size.
187*cf781b2eSEd Maste 	 */
188*cf781b2eSEd Maste 
1892de3b87aSKai Wang 	if (dbg == NULL || hipc == NULL || lopc == NULL || data == NULL ||
1902de3b87aSKai Wang 	    entry_len == NULL || next_entry == NULL) {
1912de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
1922de3b87aSKai Wang 		return (DW_DLV_ERROR);
1932de3b87aSKai Wang 	}
1942de3b87aSKai Wang 
195*cf781b2eSEd Maste 	ret = _dwarf_loclist_find(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset,
196*cf781b2eSEd Maste 	    &llbuf, &listlen, entry_len, error);
1972de3b87aSKai Wang 	if (ret == DW_DLE_NO_ENTRY) {
1982de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY);
1992de3b87aSKai Wang 		return (DW_DLV_NO_ENTRY);
2002de3b87aSKai Wang 	} else if (ret != DW_DLE_NONE)
2012de3b87aSKai Wang 		return (DW_DLV_ERROR);
2022de3b87aSKai Wang 
2032de3b87aSKai Wang 	*hipc = *lopc = 0;
204*cf781b2eSEd Maste 	for (i = 0; i < listlen; i++) {
205*cf781b2eSEd Maste 		ld = llbuf[i];
2062de3b87aSKai Wang 		if (i == 0) {
2072de3b87aSKai Wang 			*hipc = ld->ld_hipc;
2082de3b87aSKai Wang 			*lopc = ld->ld_lopc;
2092de3b87aSKai Wang 		} else {
2102de3b87aSKai Wang 			if (ld->ld_lopc < *lopc)
2112de3b87aSKai Wang 				*lopc = ld->ld_lopc;
2122de3b87aSKai Wang 			if (ld->ld_hipc > *hipc)
2132de3b87aSKai Wang 				*hipc = ld->ld_hipc;
2142de3b87aSKai Wang 		}
2152de3b87aSKai Wang 	}
2162de3b87aSKai Wang 
2172de3b87aSKai Wang 	ds = _dwarf_find_section(dbg, ".debug_loc");
2182de3b87aSKai Wang 	assert(ds != NULL);
219*cf781b2eSEd Maste 	*data = (uint8_t *) ds->ds_data + offset;
220*cf781b2eSEd Maste 	*next_entry = offset + *entry_len;
2212de3b87aSKai Wang 
2222de3b87aSKai Wang 	return (DW_DLV_OK);
2232de3b87aSKai Wang }
2242de3b87aSKai Wang 
2252de3b87aSKai Wang 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)2262de3b87aSKai Wang dwarf_loclist_from_expr(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
2272de3b87aSKai Wang     Dwarf_Unsigned bytes_len, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
2282de3b87aSKai Wang     Dwarf_Error *error)
2292de3b87aSKai Wang {
2302de3b87aSKai Wang 
231*cf781b2eSEd Maste 	return (dwarf_loclist_from_expr_a(dbg, bytes_in, bytes_len,
232*cf781b2eSEd Maste 	    dbg->dbg_pointer_size, llbuf, listlen, error));
2332de3b87aSKai Wang }
2342de3b87aSKai Wang 
2352de3b87aSKai Wang 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)2362de3b87aSKai Wang dwarf_loclist_from_expr_a(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
2372de3b87aSKai Wang     Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Locdesc **llbuf,
2382de3b87aSKai Wang     Dwarf_Signed *listlen, Dwarf_Error *error)
2392de3b87aSKai Wang {
240*cf781b2eSEd Maste 	Dwarf_Half offset_size;
241*cf781b2eSEd Maste 	Dwarf_Small version;
242*cf781b2eSEd Maste 
243*cf781b2eSEd Maste 	/*
244*cf781b2eSEd Maste 	 * Obtain offset size and DWARF version from the current
245*cf781b2eSEd Maste 	 * Compilation Unit or Type Unit. These values are needed
246*cf781b2eSEd Maste 	 * for correctly parsing DW_OP_GNU_implicit_pointer operator.
247*cf781b2eSEd Maste 	 *
248*cf781b2eSEd Maste 	 * Note that dwarf_loclist_from_expr_b() should be used instead
249*cf781b2eSEd Maste 	 * if the application knows correct values for offset size
250*cf781b2eSEd Maste 	 * and DWARF version.
251*cf781b2eSEd Maste 	 */
252*cf781b2eSEd Maste 	if (dbg->dbg_cu_current) {
253*cf781b2eSEd Maste 		offset_size = dbg->dbg_cu_current->cu_length_size == 4 ? 4 : 8;
254*cf781b2eSEd Maste 		version = dbg->dbg_cu_current->cu_version;
255*cf781b2eSEd Maste 	} else if (dbg->dbg_tu_current) {
256*cf781b2eSEd Maste 		offset_size = dbg->dbg_tu_current->cu_length_size == 4 ? 4 : 8;
257*cf781b2eSEd Maste 		version = dbg->dbg_tu_current->cu_version;
258*cf781b2eSEd Maste 	} else {
259*cf781b2eSEd Maste 		/* Default values if no CU/TU context. */
260*cf781b2eSEd Maste 		offset_size = 4;
261*cf781b2eSEd Maste 		version = 2;	/* DWARF2 */
262*cf781b2eSEd Maste 	}
263*cf781b2eSEd Maste 
264*cf781b2eSEd Maste 	return (dwarf_loclist_from_expr_b(dbg, bytes_in, bytes_len, addr_size,
265*cf781b2eSEd Maste 	    offset_size, version, llbuf, listlen, error));
266*cf781b2eSEd Maste }
267*cf781b2eSEd Maste 
268*cf781b2eSEd Maste int
dwarf_loclist_from_expr_b(Dwarf_Debug dbg,Dwarf_Ptr bytes_in,Dwarf_Unsigned bytes_len,Dwarf_Half addr_size,Dwarf_Half offset_size,Dwarf_Small version,Dwarf_Locdesc ** llbuf,Dwarf_Signed * listlen,Dwarf_Error * error)269*cf781b2eSEd Maste dwarf_loclist_from_expr_b(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
270*cf781b2eSEd Maste     Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Half offset_size,
271*cf781b2eSEd Maste     Dwarf_Small version, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
272*cf781b2eSEd Maste     Dwarf_Error *error)
273*cf781b2eSEd Maste {
2742de3b87aSKai Wang 	Dwarf_Locdesc *ld;
2752de3b87aSKai Wang 	int ret;
2762de3b87aSKai Wang 
2772de3b87aSKai Wang 	if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
2782de3b87aSKai Wang 	    llbuf == NULL || listlen == NULL) {
2792de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2802de3b87aSKai Wang 		return (DW_DLV_ERROR);
2812de3b87aSKai Wang 	}
2822de3b87aSKai Wang 
2832de3b87aSKai Wang 	if (addr_size != 4 && addr_size != 8) {
2842de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2852de3b87aSKai Wang 		return (DW_DLV_ERROR);
2862de3b87aSKai Wang 	}
2872de3b87aSKai Wang 
288*cf781b2eSEd Maste 	if (offset_size != 4 && offset_size != 8) {
289*cf781b2eSEd Maste 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
290*cf781b2eSEd Maste 		return (DW_DLV_ERROR);
291*cf781b2eSEd Maste 	}
292*cf781b2eSEd Maste 
2932de3b87aSKai Wang 	ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, addr_size,
294*cf781b2eSEd Maste 	    offset_size, version, error);
2952de3b87aSKai Wang 	if (ret != DW_DLE_NONE)
2962de3b87aSKai Wang 		return (DW_DLV_ERROR);
2972de3b87aSKai Wang 
2982de3b87aSKai Wang 	*llbuf = ld;
2992de3b87aSKai Wang 	*listlen = 1;
3002de3b87aSKai Wang 
3012de3b87aSKai Wang 	return (DW_DLV_OK);
3022de3b87aSKai Wang }
303