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 $"); 32ELFTC_VCSID("Id: dwarf_loclist.c 3066 2014-06-06 19:36:06Z kaiwang27"); 33 34static int 35copy_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 59int 60dwarf_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 148int 149dwarf_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 175int 176dwarf_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 228int 229dwarf_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 238int 239dwarf_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 271int 272dwarf_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