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