Home | History | Annotate | Line # | Download | only in libdwarf
      1 /*	$NetBSD: dwarf_loclist.c,v 1.5 2024/03/03 17:37:31 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2009,2014 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.5 2024/03/03 17:37:31 christos Exp $");
     32 ELFTC_VCSID("Id: dwarf_loclist.c 3066 2014-06-06 19:36:06Z kaiwang27");
     33 
     34 static int
     35 copy_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *dst, Dwarf_Locdesc *src,
     36     Dwarf_Error *error)
     37 {
     38 
     39 	assert(src != NULL && dst != NULL);
     40 
     41 	dst->ld_lopc = src->ld_lopc;
     42 	dst->ld_hipc = src->ld_hipc;
     43 	dst->ld_cents = src->ld_cents;
     44 
     45 	if (dst->ld_cents > 0) {
     46 		dst->ld_s = calloc(dst->ld_cents, sizeof(Dwarf_Loc));
     47 		if (dst->ld_s == NULL) {
     48 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
     49 			return (DW_DLE_MEMORY);
     50 		}
     51 		memcpy(dst->ld_s, src->ld_s, src->ld_cents *
     52 		    sizeof(Dwarf_Loc));
     53 	} else
     54 		dst->ld_s = NULL;
     55 
     56 	return (DW_DLE_NONE);
     57 }
     58 
     59 int
     60 dwarf_loclist_n(Dwarf_Attribute at, Dwarf_Locdesc ***llbuf,
     61     Dwarf_Signed *listlen, Dwarf_Error *error)
     62 {
     63 	Dwarf_Debug dbg;
     64 	int ret;
     65 
     66 	dbg = at != NULL ? at->at_die->die_dbg : NULL;
     67 
     68 	if (at == NULL || llbuf == NULL || listlen == NULL) {
     69 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
     70 		return (DW_DLV_ERROR);
     71 	}
     72 
     73 	switch (at->at_attrib) {
     74 	case DW_AT_location:
     75 	case DW_AT_string_length:
     76 	case DW_AT_return_addr:
     77 	case DW_AT_data_member_location:
     78 	case DW_AT_frame_base:
     79 	case DW_AT_segment:
     80 	case DW_AT_static_link:
     81 	case DW_AT_use_location:
     82 	case DW_AT_vtable_elem_location:
     83 		switch (at->at_form) {
     84 		case DW_FORM_data4:
     85 		case DW_FORM_data8:
     86 			/*
     87 			 * DW_FORM_data[48] can not be used as section offset
     88 			 * since DWARF4. For DWARF[23], the application needs
     89 			 * to determine if DW_FORM_data[48] is representing
     90 			 * a constant or a section offset.
     91 			 */
     92 			if (at->at_die->die_cu->cu_version >= 4) {
     93 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
     94 				return (DW_DLV_NO_ENTRY);
     95 			}
     96 			/* FALLTHROUGH */
     97 		case DW_FORM_sec_offset:
     98 			ret = _dwarf_loclist_find(dbg, at->at_die->die_cu,
     99 			    at->u[0].u64, llbuf, listlen, NULL, error);
    100 			if (ret == DW_DLE_NO_ENTRY) {
    101 				DWARF_SET_ERROR(dbg, error, ret);
    102 				return (DW_DLV_NO_ENTRY);
    103 			}
    104 			if (ret != DW_DLE_NONE)
    105 				return (DW_DLV_ERROR);
    106 			return (DW_DLV_OK);
    107 		case DW_FORM_block:
    108 		case DW_FORM_block1:
    109 		case DW_FORM_block2:
    110 		case DW_FORM_block4:
    111 		case DW_FORM_exprloc:
    112 			if (at->at_ld == NULL) {
    113 				ret = _dwarf_loc_add(at->at_die, at, error);
    114 				if (ret != DW_DLE_NONE)
    115 					return (DW_DLV_ERROR);
    116 			}
    117 			*llbuf = calloc(1, sizeof(Dwarf_Locdesc *));
    118 			if (*llbuf == NULL) {
    119 				DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
    120 				return (DW_DLV_ERROR);
    121 			}
    122 			(*llbuf)[0] = calloc(1, sizeof(Dwarf_Locdesc));
    123 			if ((*llbuf)[0] == NULL) {
    124 				free(*llbuf);
    125 				DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
    126 				return (DW_DLV_ERROR);
    127 			}
    128 			if (copy_locdesc(dbg, (*llbuf)[0], at->at_ld, error) !=
    129 			    DW_DLE_NONE) {
    130 				free((*llbuf)[0]);
    131 				free(*llbuf);
    132 				return (DW_DLV_ERROR);
    133 			}
    134 			*listlen = 1;
    135 			return (DW_DLV_OK);
    136 		default:
    137 			/* Malformed Attr? */
    138 			DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
    139 			return (DW_DLV_NO_ENTRY);
    140 		}
    141 	default:
    142 		/* Wrong attr supplied. */
    143 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
    144 		return (DW_DLV_ERROR);
    145 	}
    146 }
    147 
    148 int
    149 dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf,
    150     Dwarf_Signed *listlen, Dwarf_Error *error)
    151 {
    152 	Dwarf_Locdesc **_llbuf;
    153 	int i, ret;
    154 
    155 	ret = dwarf_loclist_n(at, &_llbuf, listlen, error);
    156 	if (ret != DW_DLV_OK)
    157 		return (ret);
    158 
    159 	/* Only return the first location description of the list. */
    160 	*llbuf = _llbuf[0];
    161 
    162 	/* Free the rest of the list. */
    163 	for (i = 1; i < *listlen; i++) {
    164 		if (_llbuf[i]->ld_s)
    165 			free(_llbuf[i]->ld_s);
    166 		free(_llbuf[i]);
    167 	}
    168 	free(_llbuf);
    169 
    170 	*listlen = 1;
    171 
    172 	return (DW_DLV_OK);
    173 }
    174 
    175 int
    176 dwarf_get_loclist_entry(Dwarf_Debug dbg, Dwarf_Unsigned offset,
    177     Dwarf_Addr *hipc, Dwarf_Addr *lopc, Dwarf_Ptr *data,
    178     Dwarf_Unsigned *entry_len, Dwarf_Unsigned *next_entry,
    179     Dwarf_Error *error)
    180 {
    181 	Dwarf_Locdesc *ld, **llbuf;
    182 	Dwarf_Section *ds;
    183 	Dwarf_Signed listlen;
    184 	int i, ret;
    185 
    186 	/*
    187 	 * Note that this API sometimes will not work correctly because
    188 	 * it assumes that all units have the same pointer size and offset
    189 	 * size.
    190 	 */
    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,
    199 	    &llbuf, &listlen, entry_len, 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 < listlen; i++) {
    208 		ld = llbuf[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 + offset;
    223 	*next_entry = offset + *entry_len;
    224 
    225 	return (DW_DLV_OK);
    226 }
    227 
    228 int
    229 dwarf_loclist_from_expr(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
    230     Dwarf_Unsigned bytes_len, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
    231     Dwarf_Error *error)
    232 {
    233 
    234 	return (dwarf_loclist_from_expr_a(dbg, bytes_in, bytes_len,
    235 	    dbg->dbg_pointer_size, llbuf, listlen, error));
    236 }
    237 
    238 int
    239 dwarf_loclist_from_expr_a(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
    240     Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Locdesc **llbuf,
    241     Dwarf_Signed *listlen, Dwarf_Error *error)
    242 {
    243 	Dwarf_Half offset_size;
    244 	Dwarf_Small version;
    245 
    246 	/*
    247 	 * Obtain offset size and DWARF version from the current
    248 	 * Compilation Unit or Type Unit. These values are needed
    249 	 * for correctly parsing DW_OP_GNU_implicit_pointer operator.
    250 	 *
    251 	 * Note that dwarf_loclist_from_expr_b() should be used instead
    252 	 * if the application knows correct values for offset size
    253 	 * and DWARF version.
    254 	 */
    255 	if (dbg->dbg_cu_current) {
    256 		offset_size = dbg->dbg_cu_current->cu_length_size == 4 ? 4 : 8;
    257 		version = dbg->dbg_cu_current->cu_version;
    258 	} else if (dbg->dbg_tu_current) {
    259 		offset_size = dbg->dbg_tu_current->cu_length_size == 4 ? 4 : 8;
    260 		version = dbg->dbg_tu_current->cu_version;
    261 	} else {
    262 		/* Default values if no CU/TU context. */
    263 		offset_size = 4;
    264 		version = 2;	/* DWARF2 */
    265 	}
    266 
    267 	return (dwarf_loclist_from_expr_b(dbg, bytes_in, bytes_len, addr_size,
    268 	    offset_size, version, llbuf, listlen, error));
    269 }
    270 
    271 int
    272 dwarf_loclist_from_expr_b(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
    273     Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Half offset_size,
    274     Dwarf_Small version, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
    275     Dwarf_Error *error)
    276 {
    277 	Dwarf_Locdesc *ld;
    278 	int ret;
    279 
    280 	if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
    281 	    llbuf == NULL || listlen == NULL) {
    282 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
    283 		return (DW_DLV_ERROR);
    284 	}
    285 
    286 	if (addr_size != 4 && addr_size != 8) {
    287 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
    288 		return (DW_DLV_ERROR);
    289 	}
    290 
    291 	if (offset_size != 4 && offset_size != 8) {
    292 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
    293 		return (DW_DLV_ERROR);
    294 	}
    295 
    296 	ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, addr_size,
    297 	    offset_size, version, error);
    298 	if (ret != DW_DLE_NONE)
    299 		return (DW_DLV_ERROR);
    300 
    301 	*llbuf = ld;
    302 	*listlen = 1;
    303 
    304 	return (DW_DLV_OK);
    305 }
    306