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 : 20 : get_offsets (Dwarf *dbg)
45 : : {
46 : 20 : size_t allocated = 0;
47 : 20 : size_t cnt = 0;
48 : 20 : struct pubnames_s *mem = NULL;
49 : 20 : const size_t entsize = sizeof (struct pubnames_s);
50 : 20 : unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf;
51 : 20 : unsigned char *readp = startp;
52 : 20 : unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
53 : :
54 [ + + ]: 72 : while (readp + 14 < endp)
55 : : {
56 : : /* If necessary, allocate more entries. */
57 [ + + ]: 52 : if (cnt >= allocated)
58 : : {
59 : 20 : allocated = MAX (10, 2 * allocated);
60 : 20 : struct pubnames_s *newmem = realloc (mem, allocated * entsize);
61 [ - + ]: 20 : 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 : 52 : int len_bytes = 4;
74 [ + + ]: 52 : Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp);
75 [ - + ]: 52 : if (len == DWARF3_LENGTH_64_BIT)
76 : : {
77 [ # # ]: 0 : len = read_8ubyte_unaligned_inc (dbg, readp);
78 : 0 : len_bytes = 8;
79 : : }
80 [ - + ]: 52 : 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 : 52 : mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp;
89 : 52 : mem[cnt].address_len = len_bytes;
90 : 52 : size_t max_size = dbg->sectiondata[IDX_debug_pubnames]->d_size;
91 [ + - ]: 52 : if (mem[cnt].set_start >= max_size
92 [ + - ]: 52 : || 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 [ + + ]: 52 : uint16_t version = read_2ubyte_unaligned (dbg, readp);
99 [ - + ]: 52 : 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 [ - + ]: 52 : if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames,
107 : 52 : 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 : 52 : unsigned char *infop
114 : 52 : = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
115 : 52 : + mem[cnt].cu_offset);
116 [ - + ]: 52 : if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT)
117 : 0 : mem[cnt].cu_header_size = 23;
118 : : else
119 : 52 : mem[cnt].cu_header_size = 11;
120 : :
121 : 52 : ++cnt;
122 : :
123 : : /* Advance to the next set. */
124 : 52 : readp += len;
125 : : }
126 : :
127 [ - + ]: 20 : 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 : 20 : dbg->pubnames_sets = realloc (mem, cnt * entsize);
135 : 20 : dbg->pubnames_nsets = cnt;
136 : :
137 : 20 : return 0;
138 : : }
139 : :
140 : :
141 : : ptrdiff_t
142 : 86 : dwarf_getpubnames (Dwarf *dbg,
143 : : int (*callback) (Dwarf *, Dwarf_Global *, void *),
144 : : void *arg, ptrdiff_t offset)
145 : : {
146 [ + - ]: 86 : if (dbg == NULL)
147 : : return -1l;
148 : :
149 [ - + ]: 86 : 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 [ + + - + ]: 86 : 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 [ + - + - ]: 20 : if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0))
164 : : return -1l;
165 : :
166 : : /* Find the place where to start. */
167 : 20 : size_t cnt;
168 [ + - ]: 20 : if (offset == 0)
169 : : {
170 : 20 : cnt = 0;
171 : 20 : 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 : 20 : unsigned char *startp
186 : 20 : = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
187 : 20 : unsigned char *endp
188 : 20 : = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
189 : 20 : unsigned char *readp = startp + offset;
190 : 84 : while (1)
191 : 32 : {
192 : 52 : Dwarf_Global gl;
193 : :
194 : 52 : gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset
195 : 52 : + dbg->pubnames_sets[cnt].cu_header_size);
196 : :
197 : 136 : while (1)
198 : : {
199 : : /* READP points to the next offset/name pair. */
200 [ - + ]: 136 : if (readp + dbg->pubnames_sets[cnt].address_len > endp)
201 : 0 : goto invalid_dwarf;
202 [ + - ]: 136 : if (dbg->pubnames_sets[cnt].address_len == 4)
203 [ + + ]: 136 : 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 [ + + ]: 136 : if (gl.die_offset == 0)
209 : : break;
210 : :
211 : : /* Add the CU offset. */
212 : 84 : gl.die_offset += dbg->pubnames_sets[cnt].cu_offset;
213 : :
214 : 84 : gl.name = (char *) readp;
215 : 84 : readp = (unsigned char *) memchr (gl.name, '\0', endp - readp);
216 [ - + ]: 84 : if (unlikely (readp == NULL))
217 : : {
218 : 0 : invalid_dwarf:
219 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
220 : 0 : return -1l;
221 : : }
222 : 84 : readp++;
223 : :
224 : : /* We found name and DIE offset. Report it. */
225 [ + - ]: 84 : 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 [ + + ]: 52 : if (++cnt == dbg->pubnames_nsets)
234 : : /* This was the last set. */
235 : : break;
236 : :
237 : 32 : startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
238 : 32 : readp = startp + dbg->pubnames_sets[cnt].set_start;
239 : : }
240 : :
241 : : /* We are done. No more entries. */
242 : 20 : return 0;
243 : : }
|