Branch data Line data Source code
1 : : /* Get public symbol information. 2 : : Copyright (C) 2002, 2003, 2004, 2005, 2008 Red Hat, Inc. 3 : : This file is part of elfutils. 4 : : Written by Ulrich Drepper <drepper@redhat.com>, 2002. 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 <stdlib.h> 36 : : #include <string.h> 37 : : 38 : : #include <libdwP.h> 39 : : #include <dwarf.h> 40 : : #include <system.h> 41 : : 42 : : 43 : : static int 44 : 10 : get_offsets (Dwarf *dbg) 45 : : { 46 : 10 : size_t allocated = 0; 47 : 10 : size_t cnt = 0; 48 : 10 : struct pubnames_s *mem = NULL; 49 : 10 : const size_t entsize = sizeof (struct pubnames_s); 50 : 10 : unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf; 51 : 10 : unsigned char *readp = startp; 52 : 10 : unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size; 53 : : 54 [ + + ]: 36 : while (readp + 14 < endp) 55 : : { 56 : : /* If necessary, allocate more entries. */ 57 [ + + ]: 26 : if (cnt >= allocated) 58 : : { 59 : 10 : allocated = MAX (10, 2 * allocated); 60 : 10 : struct pubnames_s *newmem = realloc (mem, allocated * entsize); 61 [ - + ]: 10 : if (newmem == NULL) 62 : : { 63 : 0 : __libdw_seterrno (DWARF_E_NOMEM); 64 : 0 : err_return: 65 : 0 : free (mem); 66 : 0 : return -1; 67 : : } 68 : : 69 : : mem = newmem; 70 : : } 71 : : 72 : : /* Read the set header. */ 73 : 26 : int len_bytes = 4; 74 [ + + ]: 26 : Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp); 75 [ - + ]: 26 : if (len == DWARF3_LENGTH_64_BIT) 76 : : { 77 [ # # ]: 0 : len = read_8ubyte_unaligned_inc (dbg, readp); 78 : 0 : len_bytes = 8; 79 : : } 80 [ - + ]: 26 : else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE 81 : : && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE)) 82 : : { 83 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF); 84 : 0 : goto err_return; 85 : : } 86 : : 87 : : /* Now we know the offset of the first offset/name pair. */ 88 : 26 : mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp; 89 : 26 : mem[cnt].address_len = len_bytes; 90 : 26 : size_t max_size = dbg->sectiondata[IDX_debug_pubnames]->d_size; 91 [ + - ]: 26 : if (mem[cnt].set_start >= max_size 92 [ + - ]: 26 : || len - (2 + 2 * len_bytes) > max_size - mem[cnt].set_start) 93 : : /* Something wrong, the first entry is beyond the end of 94 : : the section. Or the length of the whole unit is too big. */ 95 : : break; 96 : : 97 : : /* Read the version. It better be two for now. */ 98 [ + + ]: 26 : uint16_t version = read_2ubyte_unaligned (dbg, readp); 99 [ - + ]: 26 : if (unlikely (version != 2)) 100 : : { 101 : 0 : __libdw_seterrno (DWARF_E_INVALID_VERSION); 102 : 0 : goto err_return; 103 : : } 104 : : 105 : : /* Get the CU offset. */ 106 [ - + ]: 26 : if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames, 107 : 26 : readp + 2, len_bytes, 108 : : &mem[cnt].cu_offset, IDX_debug_info, 3)) 109 : : /* Error has been already set in reader. */ 110 : 0 : goto err_return; 111 : : 112 : : /* Determine the size of the CU header. */ 113 : 26 : unsigned char *infop 114 : 26 : = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf 115 : 26 : + mem[cnt].cu_offset); 116 [ - + ]: 26 : if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT) 117 : 0 : mem[cnt].cu_header_size = 23; 118 : : else 119 : 26 : mem[cnt].cu_header_size = 11; 120 : : 121 : 26 : ++cnt; 122 : : 123 : : /* Advance to the next set. */ 124 : 26 : readp += len; 125 : : } 126 : : 127 [ - + ]: 10 : if (mem == NULL || cnt == 0) 128 : : { 129 : 0 : free (mem); 130 : 0 : __libdw_seterrno (DWARF_E_NO_ENTRY); 131 : 0 : return -1; 132 : : } 133 : : 134 : 10 : dbg->pubnames_sets = realloc (mem, cnt * entsize); 135 : 10 : dbg->pubnames_nsets = cnt; 136 : : 137 : 10 : return 0; 138 : : } 139 : : 140 : : 141 : : ptrdiff_t 142 : 43 : dwarf_getpubnames (Dwarf *dbg, 143 : : int (*callback) (Dwarf *, Dwarf_Global *, void *), 144 : : void *arg, ptrdiff_t offset) 145 : : { 146 [ + - ]: 43 : if (dbg == NULL) 147 : : return -1l; 148 : : 149 [ - + ]: 43 : if (unlikely (offset < 0)) 150 : : { 151 : 0 : __libdw_seterrno (DWARF_E_INVALID_OFFSET); 152 : 0 : return -1l; 153 : : } 154 : : 155 : : /* Make sure it is a valid offset. */ 156 [ + + + - ]: 43 : if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL 157 : : || ((size_t) offset 158 : : >= dbg->sectiondata[IDX_debug_pubnames]->d_size))) 159 : : /* No (more) entry. */ 160 : : return 0; 161 : : 162 : : /* If necessary read the set information. */ 163 [ + - + - ]: 10 : if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0)) 164 : : return -1l; 165 : : 166 : : /* Find the place where to start. */ 167 : 10 : size_t cnt; 168 [ + - ]: 10 : if (offset == 0) 169 : : { 170 : 10 : cnt = 0; 171 : 10 : offset = dbg->pubnames_sets[0].set_start; 172 : : } 173 : : else 174 : : { 175 [ # # ]: 0 : for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt) 176 [ # # ]: 0 : if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start) 177 : : { 178 [ # # ]: 0 : assert ((Dwarf_Off) offset 179 : : < dbg->pubnames_sets[cnt + 1].set_start); 180 : : break; 181 : : } 182 [ # # ]: 0 : assert (cnt + 1 < dbg->pubnames_nsets); 183 : : } 184 : : 185 : 10 : unsigned char *startp 186 : 10 : = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; 187 : 10 : unsigned char *endp 188 : 10 : = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size; 189 : 10 : unsigned char *readp = startp + offset; 190 : 42 : while (1) 191 : 16 : { 192 : 26 : Dwarf_Global gl; 193 : : 194 : 26 : gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset 195 : 26 : + dbg->pubnames_sets[cnt].cu_header_size); 196 : : 197 : 68 : while (1) 198 : : { 199 : : /* READP points to the next offset/name pair. */ 200 [ - + ]: 68 : if (readp + dbg->pubnames_sets[cnt].address_len > endp) 201 : 0 : goto invalid_dwarf; 202 [ + - ]: 68 : if (dbg->pubnames_sets[cnt].address_len == 4) 203 [ + + ]: 68 : gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp); 204 : : else 205 [ # # ]: 0 : gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp); 206 : : 207 : : /* If the offset is zero we reached the end of the set. */ 208 [ + + ]: 68 : if (gl.die_offset == 0) 209 : : break; 210 : : 211 : : /* Add the CU offset. */ 212 : 42 : gl.die_offset += dbg->pubnames_sets[cnt].cu_offset; 213 : : 214 : 42 : gl.name = (char *) readp; 215 : 42 : readp = (unsigned char *) memchr (gl.name, '\0', endp - readp); 216 [ - + ]: 42 : if (unlikely (readp == NULL)) 217 : : { 218 : 0 : invalid_dwarf: 219 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF); 220 : 0 : return -1l; 221 : : } 222 : 42 : readp++; 223 : : 224 : : /* We found name and DIE offset. Report it. */ 225 [ + - ]: 42 : if (callback (dbg, &gl, arg) != DWARF_CB_OK) 226 : : { 227 : : /* The user wants us to stop. Return the offset of the 228 : : next entry. */ 229 : 0 : return readp - startp; 230 : : } 231 : : } 232 : : 233 [ + + ]: 26 : if (++cnt == dbg->pubnames_nsets) 234 : : /* This was the last set. */ 235 : : break; 236 : : 237 : 16 : startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; 238 : 16 : readp = startp + dbg->pubnames_sets[cnt].set_start; 239 : : } 240 : : 241 : : /* We are done. No more entries. */ 242 : 10 : return 0; 243 : : }