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