Branch data Line data Source code
1 : : /* Look up the DIE in a reference-form attribute. 2 : : Copyright (C) 2005-2010, 2018 Red Hat, Inc. 3 : : This file is part of elfutils. 4 : : 5 : : This file is free software; you can redistribute it and/or modify 6 : : it under the terms of either 7 : : 8 : : * the GNU Lesser General Public License as published by the Free 9 : : Software Foundation; either version 3 of the License, or (at 10 : : your option) any later version 11 : : 12 : : or 13 : : 14 : : * the GNU General Public License as published by the Free 15 : : Software Foundation; either version 2 of the License, or (at 16 : : your option) any later version 17 : : 18 : : or both in parallel, as here. 19 : : 20 : : elfutils is distributed in the hope that it will be useful, but 21 : : WITHOUT ANY WARRANTY; without even the implied warranty of 22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 : : General Public License for more details. 24 : : 25 : : You should have received copies of the GNU General Public License and 26 : : the GNU Lesser General Public License along with this program. If 27 : : not, see <http://www.gnu.org/licenses/>. */ 28 : : 29 : : #ifdef HAVE_CONFIG_H 30 : : # include <config.h> 31 : : #endif 32 : : 33 : : #include <string.h> 34 : : #include "libdwP.h" 35 : : #include <dwarf.h> 36 : : 37 : : 38 : : Dwarf_Die * 39 : 2431864 : dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *result) 40 : : { 41 [ + + ]: 2431864 : if (attr == NULL) 42 : : return NULL; 43 : : 44 : 2081832 : struct Dwarf_CU *cu = attr->cu; 45 : : 46 : 2081832 : Dwarf_Off offset; 47 [ + + ]: 2081832 : if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt 48 [ + - - + ]: 2081682 : || attr->form == DW_FORM_ref_sup4 || attr->form == DW_FORM_ref_sup8) 49 : : { 50 : : /* This has an absolute offset. */ 51 : : 52 : 150 : uint8_t ref_size; 53 [ - + - - ]: 150 : if (cu->version == 2 && attr->form == DW_FORM_ref_addr) 54 : 0 : ref_size = cu->address_size; 55 [ + - ]: 150 : else if (attr->form == DW_FORM_ref_sup4) 56 : : ref_size = 4; 57 [ + - ]: 150 : else if (attr->form == DW_FORM_ref_sup8) 58 : : ref_size = 8; 59 : : else 60 : 150 : ref_size = cu->offset_size; 61 : : 62 : 300 : Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt 63 [ + + ]: 150 : ? INTUSE(dwarf_getalt) (cu->dbg) : cu->dbg); 64 : : 65 [ - + ]: 150 : if (dbg_ret == NULL) 66 : : { 67 : 0 : __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK); 68 : 0 : return NULL; 69 : : } 70 : : 71 [ - + ]: 150 : if (__libdw_read_offset (cu->dbg, dbg_ret, IDX_debug_info, attr->valp, 72 : : ref_size, &offset, IDX_debug_info, 0)) 73 : : return NULL; 74 : : 75 : 150 : return INTUSE(dwarf_offdie) (dbg_ret, offset, result); 76 : : } 77 : : 78 : 2081682 : const unsigned char *datap; 79 : 2081682 : size_t size; 80 [ + + ]: 2081682 : if (attr->form == DW_FORM_ref_sig8) 81 : : { 82 : : /* This doesn't have an offset, but instead a value we 83 : : have to match in the type unit headers. */ 84 : : 85 [ - + ]: 12 : uint64_t sig = read_8ubyte_unaligned (cu->dbg, attr->valp); 86 : 12 : cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig); 87 [ + + ]: 12 : if (cu == NULL) 88 : : { 89 : : /* Not seen before. We have to scan through the type units. 90 : : Since DWARFv5 these can (also) be found in .debug_info, 91 : : so scan that first. */ 92 : : bool scan_debug_types = false; 93 : 4 : do 94 : : { 95 : 4 : rwlock_wrlock(attr->cu->dbg->dwarf_lock); 96 : 4 : cu = __libdw_intern_next_unit (attr->cu->dbg, scan_debug_types); 97 : 4 : rwlock_unlock(attr->cu->dbg->dwarf_lock); 98 : : 99 [ + + ]: 4 : if (cu == NULL) 100 : : { 101 [ + - ]: 2 : if (scan_debug_types == false) 102 : : scan_debug_types = true; 103 : : else 104 : : { 105 [ # # ]: 0 : __libdw_seterrno (INTUSE(dwarf_errno) () 106 : : ?: DWARF_E_INVALID_REFERENCE); 107 : 0 : return NULL; 108 : : } 109 : : } 110 : : } 111 [ - + ]: 2 : while (cu == NULL || cu->unit_id8 != sig); 112 : : } 113 : : 114 : 12 : int secid = cu_sec_idx (cu); 115 : 12 : datap = cu->dbg->sectiondata[secid]->d_buf; 116 : 12 : size = cu->dbg->sectiondata[secid]->d_size; 117 : 12 : offset = cu->start + cu->subdie_offset; 118 : : } 119 : : else 120 : : { 121 : : /* Other forms produce an offset from the CU. */ 122 [ - + ]: 2081670 : if (unlikely (__libdw_formref (attr, &offset) != 0)) 123 : : return NULL; 124 : : 125 : 2081670 : datap = cu->startp; 126 : 2081670 : size = cu->endp - cu->startp; 127 : : } 128 : : 129 [ - + ]: 2081682 : if (unlikely (offset >= size)) 130 : : { 131 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF); 132 : 0 : return NULL; 133 : : } 134 : : 135 : 2081682 : memset (result, '\0', sizeof (Dwarf_Die)); 136 : 2081682 : result->addr = (char *) datap + offset; 137 : 2081682 : result->cu = cu; 138 : 2081682 : return result; 139 : : } 140 : : INTDEF (dwarf_formref_die)