1 /* Get public symbol information. 2 Copyright (C) 2002, 2003, 2004 Red Hat, Inc. 3 Written by Ulrich Drepper <drepper (at) redhat.com>, 2002. 4 5 This program is Open Source software; you can redistribute it and/or 6 modify it under the terms of the Open Software License version 1.0 as 7 published by the Open Source Initiative. 8 9 You should have received a copy of the Open Software License along 10 with this program; if not, you may obtain a copy of the Open Software 11 License version 1.0 from http://www.opensource.org/licenses/osl.php or 12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq., 13 3001 King Ranch Road, Ukiah, CA 95482. */ 14 15 #ifdef HAVE_CONFIG_H 16 # include <config.h> 17 #endif 18 19 #include <assert.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <sys/param.h> 23 24 #include <libdwP.h> 25 26 27 static int 28 get_offsets (Dwarf *dbg) 29 { 30 size_t allocated = 0; 31 size_t cnt = 0; 32 struct pubnames_s *mem = NULL; 33 const size_t entsize = sizeof (struct pubnames_s); 34 unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf; 35 unsigned char *readp = startp; 36 unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size; 37 38 while (readp + 14 < endp) 39 { 40 /* If necessary, allocate more entries. */ 41 if (cnt >= allocated) 42 { 43 allocated = MAX (10, 2 * allocated); 44 struct pubnames_s *newmem 45 = (struct pubnames_s *) realloc (mem, allocated * entsize); 46 if (newmem == NULL) 47 { 48 __libdw_seterrno (DWARF_E_NOMEM); 49 err_return: 50 free (mem); 51 return -1; 52 } 53 54 mem = newmem; 55 } 56 57 /* Read the set header. */ 58 int len_bytes = 4; 59 Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp); 60 if (len == 0xffffffff) 61 { 62 len = read_8ubyte_unaligned_inc (dbg, readp); 63 len_bytes = 8; 64 } 65 66 /* Now we know the offset of the first offset/name pair. */ 67 mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp; 68 mem[cnt].address_len = len_bytes; 69 if (mem[cnt].set_start >= dbg->sectiondata[IDX_debug_pubnames]->d_size) 70 /* Something wrong, the first entry is beyond the end of 71 the section. */ 72 break; 73 74 /* Read the version. It better be two for now. */ 75 uint16_t version = read_2ubyte_unaligned (dbg, readp); 76 if (version != 2) 77 { 78 __libdw_seterrno (DWARF_E_INVALID_VERSION); 79 goto err_return; 80 } 81 82 /* Get the CU offset. */ 83 if (len_bytes == 4) 84 mem[cnt].cu_offset = read_4ubyte_unaligned (dbg, readp + 2); 85 else 86 mem[cnt].cu_offset = read_8ubyte_unaligned (dbg, readp + 2); 87 88 /* Determine the size of the CU header. */ 89 assert (dbg->sectiondata[IDX_debug_info] != NULL); 90 assert (dbg->sectiondata[IDX_debug_info]->d_buf != NULL); 91 assert (mem[cnt].cu_offset + 3 92 < dbg->sectiondata[IDX_debug_info]->d_size); 93 unsigned char *infop 94 = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf 95 + mem[cnt].cu_offset); 96 if (read_4ubyte_unaligned_noncvt (infop) == 0xffffffff) 97 mem[cnt].cu_header_size = 23; 98 else 99 mem[cnt].cu_header_size = 11; 100 101 ++cnt; 102 103 /* Advance to the next set. */ 104 readp += len; 105 } 106 107 if (mem == NULL) 108 { 109 __libdw_seterrno (DWARF_E_NO_ENTRY); 110 return -1; 111 } 112 113 dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize); 114 dbg->pubnames_nsets = cnt; 115 116 return 0; 117 } 118 119 120 ptrdiff_t 121 dwarf_getpubnames (dbg, callback, arg, offset) 122 Dwarf *dbg; 123 int (*callback) (Dwarf *, Dwarf_Global *, void *); 124 void *arg; 125 ptrdiff_t offset; 126 { 127 if (dbg == NULL) 128 return -1l; 129 130 /* Make sure it is a valid offset. */ 131 if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL 132 || offset >= dbg->sectiondata[IDX_debug_pubnames]->d_size)) 133 /* No (more) entry. */ 134 return 0; 135 136 /* If necessary read the set information. */ 137 if (dbg->pubnames_nsets == 0 && get_offsets (dbg) != 0) 138 return -1l; 139 140 /* Find the place where to start. */ 141 size_t cnt; 142 if (offset == 0) 143 { 144 cnt = 0; 145 offset = dbg->pubnames_sets[0].set_start; 146 } 147 else 148 { 149 for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt) 150 if (offset >= dbg->pubnames_sets[cnt].set_start) 151 { 152 assert (offset < dbg->pubnames_sets[cnt + 1].set_start); 153 break; 154 } 155 assert (cnt + 1 < dbg->pubnames_nsets); 156 } 157 158 unsigned char *startp 159 = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; 160 unsigned char *readp = startp + offset; 161 while (1) 162 { 163 Dwarf_Global gl; 164 165 gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset 166 + dbg->pubnames_sets[cnt].cu_header_size); 167 168 while (1) 169 { 170 /* READP points to the next offset/name pair. */ 171 if (dbg->pubnames_sets[cnt].address_len == 4) 172 gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp); 173 else 174 gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp); 175 176 /* If the offset is zero we reached the end of the set. */ 177 if (gl.die_offset == 0) 178 break; 179 180 /* Add the CU offset. */ 181 gl.die_offset += dbg->pubnames_sets[cnt].cu_offset; 182 183 gl.name = (char *) readp; 184 readp = (unsigned char *) rawmemchr (gl.name, '\0') + 1; 185 186 /* We found name and DIE offset. Report it. */ 187 if (callback (dbg, &gl, arg) != DWARF_CB_OK) 188 { 189 /* The user wants us to stop. Return the offset of the 190 next entry. */ 191 return readp - startp; 192 } 193 } 194 195 if (++cnt == dbg->pubnames_nsets) 196 /* This was the last set. */ 197 break; 198 199 startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf; 200 readp = startp + dbg->pubnames_sets[cnt].set_start; 201 } 202 203 /* We are done. No more entries. */ 204 return 0; 205 } 206