1 /*- 2 * Copyright (c) 2009,2011 Kai Wang 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include "_libdwarf.h" 28 29 ELFTC_VCSID("$Id: libdwarf_loclist.c 2972 2013-12-23 06:46:04Z kaiwang27 $"); 30 31 static int 32 _dwarf_loclist_add_locdesc(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Section *ds, 33 uint64_t *off, Dwarf_Locdesc **ld, uint64_t *ldlen, 34 Dwarf_Unsigned *total_len, Dwarf_Error *error) 35 { 36 uint64_t start, end; 37 int i, len, ret; 38 39 if (total_len != NULL) 40 *total_len = 0; 41 42 for (i = 0; *off < ds->ds_size; i++) { 43 start = dbg->read(ds->ds_data, off, cu->cu_pointer_size); 44 end = dbg->read(ds->ds_data, off, cu->cu_pointer_size); 45 if (ld != NULL) { 46 ld[i]->ld_lopc = start; 47 ld[i]->ld_hipc = end; 48 } 49 50 if (total_len != NULL) 51 *total_len += 2 * cu->cu_pointer_size; 52 53 /* Check if it is the end entry. */ 54 if (start == 0 && end ==0) { 55 i++; 56 break; 57 } 58 59 /* Check if it is base-select entry. */ 60 if ((cu->cu_pointer_size == 4 && start == ~0U) || 61 (cu->cu_pointer_size == 8 && start == ~0ULL)) 62 continue; 63 64 /* Otherwise it's normal entry. */ 65 len = dbg->read(ds->ds_data, off, 2); 66 if (*off + len > ds->ds_size) { 67 DWARF_SET_ERROR(dbg, error, 68 DW_DLE_DEBUG_LOC_SECTION_SHORT); 69 return (DW_DLE_DEBUG_LOC_SECTION_SHORT); 70 } 71 72 if (total_len != NULL) 73 *total_len += len; 74 75 if (ld != NULL) { 76 ret = _dwarf_loc_fill_locdesc(dbg, ld[i], 77 ds->ds_data + *off, len, cu->cu_pointer_size, 78 error); 79 if (ret != DW_DLE_NONE) 80 return (ret); 81 } 82 83 *off += len; 84 } 85 86 if (ldlen != NULL) 87 *ldlen = i; 88 89 return (DW_DLE_NONE); 90 } 91 92 int 93 _dwarf_loclist_find(Dwarf_Debug dbg, Dwarf_CU cu, uint64_t lloff, 94 Dwarf_Loclist *ret_ll, Dwarf_Error *error) 95 { 96 Dwarf_Loclist ll; 97 int ret; 98 99 assert(ret_ll != NULL); 100 ret = DW_DLE_NONE; 101 102 TAILQ_FOREACH(ll, &dbg->dbg_loclist, ll_next) 103 if (ll->ll_offset == lloff) 104 break; 105 106 if (ll == NULL) 107 ret = _dwarf_loclist_add(dbg, cu, lloff, ret_ll, error); 108 else 109 *ret_ll = ll; 110 111 return (ret); 112 } 113 114 int 115 _dwarf_loclist_add(Dwarf_Debug dbg, Dwarf_CU cu, uint64_t lloff, 116 Dwarf_Loclist *ret_ll, Dwarf_Error *error) 117 { 118 Dwarf_Section *ds; 119 Dwarf_Loclist ll, tll; 120 uint64_t ldlen; 121 int i, ret; 122 123 ret = DW_DLE_NONE; 124 125 if ((ds = _dwarf_find_section(dbg, ".debug_loc")) == NULL) { 126 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 127 return (DW_DLE_NO_ENTRY); 128 } 129 130 if (lloff >= ds->ds_size) { 131 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 132 return (DW_DLE_NO_ENTRY); 133 } 134 135 if ((ll = malloc(sizeof(struct _Dwarf_Loclist))) == NULL) { 136 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 137 return (DW_DLE_MEMORY); 138 } 139 140 ll->ll_offset = lloff; 141 142 /* Get the number of locdesc the first round. */ 143 ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &lloff, NULL, &ldlen, 144 NULL, error); 145 if (ret != DW_DLE_NONE) 146 goto fail_cleanup; 147 148 /* 149 * Dwarf_Locdesc list memory is allocated in this way (one more level 150 * of indirect) to make the loclist API be compatible with SGI libdwarf. 151 */ 152 ll->ll_ldlen = ldlen; 153 if (ldlen != 0) { 154 if ((ll->ll_ldlist = calloc(ldlen, sizeof(Dwarf_Locdesc *))) == 155 NULL) { 156 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 157 ret = DW_DLE_MEMORY; 158 goto fail_cleanup; 159 } 160 for (i = 0; (uint64_t) i < ldlen; i++) { 161 if ((ll->ll_ldlist[i] = 162 calloc(1, sizeof(Dwarf_Locdesc))) == NULL) { 163 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 164 ret = DW_DLE_MEMORY; 165 goto fail_cleanup; 166 } 167 } 168 } else 169 ll->ll_ldlist = NULL; 170 171 lloff = ll->ll_offset; 172 173 /* Fill in locdesc. */ 174 ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &lloff, ll->ll_ldlist, 175 NULL, &ll->ll_length, error); 176 if (ret != DW_DLE_NONE) 177 goto fail_cleanup; 178 179 /* Insert to the queue. Sort by offset. */ 180 TAILQ_FOREACH(tll, &dbg->dbg_loclist, ll_next) 181 if (tll->ll_offset > ll->ll_offset) { 182 TAILQ_INSERT_BEFORE(tll, ll, ll_next); 183 break; 184 } 185 186 if (tll == NULL) 187 TAILQ_INSERT_TAIL(&dbg->dbg_loclist, ll, ll_next); 188 189 *ret_ll = ll; 190 return (DW_DLE_NONE); 191 192 fail_cleanup: 193 194 _dwarf_loclist_free(ll); 195 196 return (ret); 197 } 198 199 void 200 _dwarf_loclist_free(Dwarf_Loclist ll) 201 { 202 int i; 203 204 if (ll == NULL) 205 return; 206 207 if (ll->ll_ldlist != NULL) { 208 for (i = 0; i < ll->ll_ldlen; i++) { 209 if (ll->ll_ldlist[i]->ld_s) 210 free(ll->ll_ldlist[i]->ld_s); 211 free(ll->ll_ldlist[i]); 212 } 213 free(ll->ll_ldlist); 214 } 215 free(ll); 216 } 217 218 void 219 _dwarf_loclist_cleanup(Dwarf_Debug dbg) 220 { 221 Dwarf_Loclist ll, tll; 222 223 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); 224 225 TAILQ_FOREACH_SAFE(ll, &dbg->dbg_loclist, ll_next, tll) { 226 TAILQ_REMOVE(&dbg->dbg_loclist, ll, ll_next); 227 _dwarf_loclist_free(ll); 228 } 229 } 230