1 /* $NetBSD: libdwarf_loclist.c,v 1.2 2014/03/09 16:58:04 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2009,2011 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: libdwarf_loclist.c,v 1.2 2014/03/09 16:58:04 christos Exp $"); 32 ELFTC_VCSID("Id: libdwarf_loclist.c 2972 2013-12-23 06:46:04Z kaiwang27 "); 33 34 static int 35 _dwarf_loclist_add_locdesc(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Section *ds, 36 uint64_t *off, Dwarf_Locdesc **ld, uint64_t *ldlen, 37 Dwarf_Unsigned *total_len, Dwarf_Error *error) 38 { 39 uint64_t start, end; 40 int i, len, ret; 41 42 if (total_len != NULL) 43 *total_len = 0; 44 45 for (i = 0; *off < ds->ds_size; i++) { 46 start = dbg->read(ds->ds_data, off, cu->cu_pointer_size); 47 end = dbg->read(ds->ds_data, off, cu->cu_pointer_size); 48 if (ld != NULL) { 49 ld[i]->ld_lopc = start; 50 ld[i]->ld_hipc = end; 51 } 52 53 if (total_len != NULL) 54 *total_len += 2 * cu->cu_pointer_size; 55 56 /* Check if it is the end entry. */ 57 if (start == 0 && end ==0) { 58 i++; 59 break; 60 } 61 62 /* Check if it is base-select entry. */ 63 if ((cu->cu_pointer_size == 4 && start == ~0U) || 64 (cu->cu_pointer_size == 8 && start == ~0ULL)) 65 continue; 66 67 /* Otherwise it's normal entry. */ 68 len = dbg->read(ds->ds_data, off, 2); 69 if (*off + len > ds->ds_size) { 70 DWARF_SET_ERROR(dbg, error, 71 DW_DLE_DEBUG_LOC_SECTION_SHORT); 72 return (DW_DLE_DEBUG_LOC_SECTION_SHORT); 73 } 74 75 if (total_len != NULL) 76 *total_len += len; 77 78 if (ld != NULL) { 79 ret = _dwarf_loc_fill_locdesc(dbg, ld[i], 80 ds->ds_data + *off, len, cu->cu_pointer_size, 81 error); 82 if (ret != DW_DLE_NONE) 83 return (ret); 84 } 85 86 *off += len; 87 } 88 89 if (ldlen != NULL) 90 *ldlen = i; 91 92 return (DW_DLE_NONE); 93 } 94 95 int 96 _dwarf_loclist_find(Dwarf_Debug dbg, Dwarf_CU cu, uint64_t lloff, 97 Dwarf_Loclist *ret_ll, Dwarf_Error *error) 98 { 99 Dwarf_Loclist ll; 100 int ret; 101 102 assert(ret_ll != NULL); 103 ret = DW_DLE_NONE; 104 105 TAILQ_FOREACH(ll, &dbg->dbg_loclist, ll_next) 106 if (ll->ll_offset == lloff) 107 break; 108 109 if (ll == NULL) 110 ret = _dwarf_loclist_add(dbg, cu, lloff, ret_ll, error); 111 else 112 *ret_ll = ll; 113 114 return (ret); 115 } 116 117 int 118 _dwarf_loclist_add(Dwarf_Debug dbg, Dwarf_CU cu, uint64_t lloff, 119 Dwarf_Loclist *ret_ll, Dwarf_Error *error) 120 { 121 Dwarf_Section *ds; 122 Dwarf_Loclist ll, tll; 123 uint64_t ldlen; 124 int i, ret; 125 126 ret = DW_DLE_NONE; 127 128 if ((ds = _dwarf_find_section(dbg, ".debug_loc")) == NULL) { 129 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 130 return (DW_DLE_NO_ENTRY); 131 } 132 133 if (lloff >= ds->ds_size) { 134 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 135 return (DW_DLE_NO_ENTRY); 136 } 137 138 if ((ll = malloc(sizeof(struct _Dwarf_Loclist))) == NULL) { 139 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 140 return (DW_DLE_MEMORY); 141 } 142 143 ll->ll_offset = lloff; 144 145 /* Get the number of locdesc the first round. */ 146 ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &lloff, NULL, &ldlen, 147 NULL, error); 148 if (ret != DW_DLE_NONE) 149 goto fail_cleanup; 150 151 /* 152 * Dwarf_Locdesc list memory is allocated in this way (one more level 153 * of indirect) to make the loclist API be compatible with SGI libdwarf. 154 */ 155 ll->ll_ldlen = ldlen; 156 if (ldlen != 0) { 157 if ((ll->ll_ldlist = calloc(ldlen, sizeof(Dwarf_Locdesc *))) == 158 NULL) { 159 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 160 ret = DW_DLE_MEMORY; 161 goto fail_cleanup; 162 } 163 for (i = 0; (uint64_t) i < ldlen; i++) { 164 if ((ll->ll_ldlist[i] = 165 calloc(1, sizeof(Dwarf_Locdesc))) == NULL) { 166 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 167 ret = DW_DLE_MEMORY; 168 goto fail_cleanup; 169 } 170 } 171 } else 172 ll->ll_ldlist = NULL; 173 174 lloff = ll->ll_offset; 175 176 /* Fill in locdesc. */ 177 ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &lloff, ll->ll_ldlist, 178 NULL, &ll->ll_length, error); 179 if (ret != DW_DLE_NONE) 180 goto fail_cleanup; 181 182 /* Insert to the queue. Sort by offset. */ 183 TAILQ_FOREACH(tll, &dbg->dbg_loclist, ll_next) 184 if (tll->ll_offset > ll->ll_offset) { 185 TAILQ_INSERT_BEFORE(tll, ll, ll_next); 186 break; 187 } 188 189 if (tll == NULL) 190 TAILQ_INSERT_TAIL(&dbg->dbg_loclist, ll, ll_next); 191 192 *ret_ll = ll; 193 return (DW_DLE_NONE); 194 195 fail_cleanup: 196 197 _dwarf_loclist_free(ll); 198 199 return (ret); 200 } 201 202 void 203 _dwarf_loclist_free(Dwarf_Loclist ll) 204 { 205 int i; 206 207 if (ll == NULL) 208 return; 209 210 if (ll->ll_ldlist != NULL) { 211 for (i = 0; i < ll->ll_ldlen; i++) { 212 if (ll->ll_ldlist[i]->ld_s) 213 free(ll->ll_ldlist[i]->ld_s); 214 free(ll->ll_ldlist[i]); 215 } 216 free(ll->ll_ldlist); 217 } 218 free(ll); 219 } 220 221 void 222 _dwarf_loclist_cleanup(Dwarf_Debug dbg) 223 { 224 Dwarf_Loclist ll, tll; 225 226 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); 227 228 TAILQ_FOREACH_SAFE(ll, &dbg->dbg_loclist, ll_next, tll) { 229 TAILQ_REMOVE(&dbg->dbg_loclist, ll, ll_next); 230 _dwarf_loclist_free(ll); 231 } 232 } 233