1 /* Find CU for given offset. 2 Copyright (C) 2003-2010, 2014, 2016, 2017, 2018 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2003. 5 6 This file is free software; you can redistribute it and/or modify 7 it under the terms of either 8 9 * the GNU Lesser General Public License as published by the Free 10 Software Foundation; either version 3 of the License, or (at 11 your option) any later version 12 13 or 14 15 * the GNU General Public License as published by the Free 16 Software Foundation; either version 2 of the License, or (at 17 your option) any later version 18 19 or both in parallel, as here. 20 21 elfutils is distributed in the hope that it will be useful, but 22 WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 General Public License for more details. 25 26 You should have received copies of the GNU General Public License and 27 the GNU Lesser General Public License along with this program. If 28 not, see <http://www.gnu.org/licenses/>. */ 29 30 #ifdef HAVE_CONFIG_H 31 # include <config.h> 32 #endif 33 34 #include <assert.h> 35 #include <search.h> 36 #include "libdwP.h" 37 38 static int 39 findcu_cb (const void *arg1, const void *arg2) 40 { 41 struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1; 42 struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2; 43 44 /* Find out which of the two arguments is the search value. It has 45 end offset 0. */ 46 if (cu1->end == 0) 47 { 48 if (cu1->start < cu2->start) 49 return -1; 50 if (cu1->start >= cu2->end) 51 return 1; 52 } 53 else 54 { 55 if (cu2->start < cu1->start) 56 return 1; 57 if (cu2->start >= cu1->end) 58 return -1; 59 } 60 61 return 0; 62 } 63 64 int 65 __libdw_finddbg_cb (const void *arg1, const void *arg2) 66 { 67 Dwarf *dbg1 = (Dwarf *) arg1; 68 Dwarf *dbg2 = (Dwarf *) arg2; 69 70 Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info]; 71 unsigned char *dbg1_start = dbg1_data->d_buf; 72 size_t dbg1_size = dbg1_data->d_size; 73 74 Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info]; 75 unsigned char *dbg2_start = dbg2_data->d_buf; 76 size_t dbg2_size = dbg2_data->d_size; 77 78 /* Find out which of the two arguments is the search value. It has 79 a size of 0. */ 80 if (dbg1_size == 0) 81 { 82 if (dbg1_start < dbg2_start) 83 return -1; 84 if (dbg1_start >= dbg2_start + dbg2_size) 85 return 1; 86 } 87 else 88 { 89 if (dbg2_start < dbg1_start) 90 return 1; 91 if (dbg2_start >= dbg1_start + dbg1_size) 92 return -1; 93 } 94 95 return 0; 96 } 97 98 struct Dwarf_CU * 99 internal_function 100 __libdw_intern_next_unit (Dwarf *dbg, bool debug_types) 101 { 102 Dwarf_Off *const offsetp 103 = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset; 104 void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree; 105 106 Dwarf_Off oldoff = *offsetp; 107 uint16_t version; 108 uint8_t unit_type; 109 uint8_t address_size; 110 uint8_t offset_size; 111 Dwarf_Off abbrev_offset; 112 uint64_t unit_id8; 113 Dwarf_Off subdie_offset; 114 115 if (__libdw_next_unit (dbg, debug_types, oldoff, offsetp, NULL, 116 &version, &unit_type, &abbrev_offset, 117 &address_size, &offset_size, 118 &unit_id8, &subdie_offset) != 0) 119 /* No more entries. */ 120 return NULL; 121 122 /* We only know how to handle the DWARF version 2 through 5 formats. 123 For v4 debug types we only handle version 4. */ 124 if (unlikely (version < 2) || unlikely (version > 5) 125 || (debug_types && unlikely (version != 4))) 126 { 127 __libdw_seterrno (DWARF_E_VERSION); 128 return NULL; 129 } 130 131 /* We only handle 32 or 64 bit (4 or 8 byte) addresses and offsets. 132 Just assume we are dealing with 64bit in case the size is "unknown". 133 Too much code assumes if it isn't 4 then it is 8 (or the other way 134 around). */ 135 if (unlikely (address_size != 4 && address_size != 8)) 136 address_size = 8; 137 if (unlikely (offset_size != 4 && offset_size != 8)) 138 offset_size = 8; 139 140 /* Invalid or truncated debug section data? */ 141 size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info; 142 Elf_Data *data = dbg->sectiondata[sec_idx]; 143 if (unlikely (*offsetp > data->d_size)) 144 *offsetp = data->d_size; 145 146 /* Create an entry for this CU. */ 147 struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU); 148 149 newp->dbg = dbg; 150 newp->sec_idx = sec_idx; 151 newp->start = oldoff; 152 newp->end = *offsetp; 153 newp->address_size = address_size; 154 newp->offset_size = offset_size; 155 newp->version = version; 156 newp->unit_id8 = unit_id8; 157 newp->subdie_offset = subdie_offset; 158 Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41); 159 newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset; 160 newp->files = NULL; 161 newp->lines = NULL; 162 newp->locs = NULL; 163 newp->split = (Dwarf_CU *) -1; 164 newp->base_address = (Dwarf_Addr) -1; 165 newp->addr_base = (Dwarf_Off) -1; 166 newp->str_off_base = (Dwarf_Off) -1; 167 newp->ranges_base = (Dwarf_Off) -1; 168 newp->locs_base = (Dwarf_Off) -1; 169 170 newp->startp = data->d_buf + newp->start; 171 newp->endp = data->d_buf + newp->end; 172 173 /* v4 debug type units have version == 4 and unit_type == DW_UT_type. */ 174 if (debug_types) 175 newp->unit_type = DW_UT_type; 176 else if (version < 5) 177 { 178 /* This is a reasonable guess (and needed to get the CUDIE). */ 179 newp->unit_type = DW_UT_compile; 180 181 /* But set it correctly from the actual CUDIE tag. */ 182 Dwarf_Die cudie = CUDIE (newp); 183 int tag = INTUSE(dwarf_tag) (&cudie); 184 if (tag == DW_TAG_compile_unit) 185 { 186 Dwarf_Attribute dwo_id; 187 if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL) 188 { 189 Dwarf_Word id8; 190 if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0) 191 { 192 if (INTUSE(dwarf_haschildren) (&cudie) == 0 193 && INTUSE(dwarf_hasattr) (&cudie, 194 DW_AT_GNU_dwo_name) == 1) 195 newp->unit_type = DW_UT_skeleton; 196 else 197 newp->unit_type = DW_UT_split_compile; 198 199 newp->unit_id8 = id8; 200 } 201 } 202 } 203 else if (tag == DW_TAG_partial_unit) 204 newp->unit_type = DW_UT_partial; 205 else if (tag == DW_TAG_type_unit) 206 newp->unit_type = DW_UT_type; 207 } 208 else 209 newp->unit_type = unit_type; 210 211 /* Store a reference to any type unit ids in the hash for quick lookup. */ 212 if (unit_type == DW_UT_type || unit_type == DW_UT_split_type) 213 Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp); 214 215 /* Add the new entry to the search tree. */ 216 if (tsearch (newp, tree, findcu_cb) == NULL) 217 { 218 /* Something went wrong. Undo the operation. */ 219 *offsetp = oldoff; 220 __libdw_seterrno (DWARF_E_NOMEM); 221 return NULL; 222 } 223 224 return newp; 225 } 226 227 struct Dwarf_CU * 228 internal_function 229 __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types) 230 { 231 void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree; 232 Dwarf_Off *next_offset 233 = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset; 234 235 /* Maybe we already know that CU. */ 236 struct Dwarf_CU fake = { .start = start, .end = 0 }; 237 struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb); 238 if (found != NULL) 239 return *found; 240 241 if (start < *next_offset) 242 { 243 __libdw_seterrno (DWARF_E_INVALID_DWARF); 244 return NULL; 245 } 246 247 /* No. Then read more CUs. */ 248 while (1) 249 { 250 struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types); 251 if (newp == NULL) 252 return NULL; 253 254 /* Is this the one we are looking for? */ 255 if (start < *next_offset || start == newp->start) 256 return newp; 257 } 258 /* NOTREACHED */ 259 } 260 261 struct Dwarf_CU * 262 internal_function 263 __libdw_findcu_addr (Dwarf *dbg, void *addr) 264 { 265 void **tree; 266 Dwarf_Off start; 267 if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf 268 && addr < (dbg->sectiondata[IDX_debug_info]->d_buf 269 + dbg->sectiondata[IDX_debug_info]->d_size)) 270 { 271 tree = &dbg->cu_tree; 272 start = addr - dbg->sectiondata[IDX_debug_info]->d_buf; 273 } 274 else if (dbg->sectiondata[IDX_debug_types] != NULL 275 && addr >= dbg->sectiondata[IDX_debug_types]->d_buf 276 && addr < (dbg->sectiondata[IDX_debug_types]->d_buf 277 + dbg->sectiondata[IDX_debug_types]->d_size)) 278 { 279 tree = &dbg->tu_tree; 280 start = addr - dbg->sectiondata[IDX_debug_types]->d_buf; 281 } 282 else 283 return NULL; 284 285 struct Dwarf_CU fake = { .start = start, .end = 0 }; 286 struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb); 287 288 if (found != NULL) 289 return *found; 290 291 return NULL; 292 } 293 294 Dwarf * 295 internal_function 296 __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr) 297 { 298 /* XXX Assumes split DWARF only has CUs in main IDX_debug_info. */ 299 Elf_Data fake_data = { .d_buf = addr, .d_size = 0 }; 300 Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data }; 301 Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb); 302 303 if (found != NULL) 304 return *found; 305 306 return NULL; 307 } 308