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 3061 2014-06-02 00:42:41Z kaiwang27 $"); 30 31 static int 32 _dwarf_loclist_add_locdesc(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Section *ds, 33 Dwarf_Unsigned *off, Dwarf_Locdesc **ld, Dwarf_Signed *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 cu->cu_length_size == 4 ? 4 : 8, cu->cu_version, 79 error); 80 if (ret != DW_DLE_NONE) 81 return (ret); 82 } 83 84 *off += len; 85 } 86 87 if (ldlen != NULL) 88 *ldlen = i; 89 90 return (DW_DLE_NONE); 91 } 92 93 int 94 _dwarf_loclist_find(Dwarf_Debug dbg, Dwarf_CU cu, uint64_t lloff, 95 Dwarf_Locdesc ***ret_llbuf, Dwarf_Signed *listlen, 96 Dwarf_Unsigned *entry_len, Dwarf_Error *error) 97 { 98 Dwarf_Locdesc **llbuf; 99 Dwarf_Section *ds; 100 Dwarf_Signed ldlen; 101 Dwarf_Unsigned off; 102 int i, ret; 103 104 if ((ds = _dwarf_find_section(dbg, ".debug_loc")) == NULL) { 105 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 106 return (DW_DLE_NO_ENTRY); 107 } 108 109 if (lloff >= ds->ds_size) { 110 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 111 return (DW_DLE_NO_ENTRY); 112 } 113 114 /* Get the number of locdesc the first round. */ 115 off = lloff; 116 ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &off, NULL, &ldlen, 117 NULL, error); 118 if (ret != DW_DLE_NONE) 119 return (ret); 120 121 if (ldlen == 0) 122 return (DW_DLE_NO_ENTRY); 123 124 /* 125 * Dwarf_Locdesc list memory is allocated in this way (one more level 126 * of indirect) to make the loclist API be compatible with SGI libdwarf. 127 */ 128 if ((llbuf = calloc(ldlen, sizeof(Dwarf_Locdesc *))) == NULL) { 129 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 130 return (DW_DLE_MEMORY); 131 } 132 for (i = 0; i < ldlen; i++) { 133 if ((llbuf[i] = calloc(1, sizeof(Dwarf_Locdesc))) == NULL) { 134 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 135 ret = DW_DLE_MEMORY; 136 goto fail_cleanup; 137 } 138 } 139 140 off = lloff; 141 142 /* Fill in locdesc. */ 143 ret = _dwarf_loclist_add_locdesc(dbg, cu, ds, &off, llbuf, NULL, 144 entry_len, error); 145 if (ret != DW_DLE_NONE) 146 goto fail_cleanup; 147 148 *ret_llbuf = llbuf; 149 *listlen = ldlen; 150 151 return (DW_DLE_NONE); 152 153 fail_cleanup: 154 155 if (llbuf != NULL) { 156 for (i = 0; i < ldlen; i++) { 157 if (llbuf[i]->ld_s) 158 free(llbuf[i]->ld_s); 159 free(llbuf[i]); 160 } 161 free(llbuf); 162 } 163 164 return (ret); 165 } 166