blob: c8b9f9f6c0d3d53f5e0ecf8f948210f6d5a6754c [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Get public symbol information.
Ulrich Drepper06ec9db2008-01-22 06:08:30 +00002 Copyright (C) 2002, 2003, 2004, 2005, 2008 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 2002.
5
Mark Wielaardde2ed972012-06-05 17:15:16 +02006 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00008
Mark Wielaardde2ed972012-06-05 17:15:16 +02009 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000022 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020026 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000029
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#include <sys/param.h>
38
39#include <libdwP.h>
Ulrich Drepper35f08c42008-01-18 19:59:08 +000040#include <dwarf.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000041
42
43static int
44get_offsets (Dwarf *dbg)
45{
46 size_t allocated = 0;
47 size_t cnt = 0;
48 struct pubnames_s *mem = NULL;
49 const size_t entsize = sizeof (struct pubnames_s);
50 unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf;
51 unsigned char *readp = startp;
52 unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
53
54 while (readp + 14 < endp)
55 {
56 /* If necessary, allocate more entries. */
57 if (cnt >= allocated)
58 {
59 allocated = MAX (10, 2 * allocated);
60 struct pubnames_s *newmem
61 = (struct pubnames_s *) realloc (mem, allocated * entsize);
62 if (newmem == NULL)
63 {
64 __libdw_seterrno (DWARF_E_NOMEM);
65 err_return:
66 free (mem);
67 return -1;
68 }
69
70 mem = newmem;
71 }
72
73 /* Read the set header. */
74 int len_bytes = 4;
75 Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp);
Ulrich Drepper35f08c42008-01-18 19:59:08 +000076 if (len == DWARF3_LENGTH_64_BIT)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000077 {
78 len = read_8ubyte_unaligned_inc (dbg, readp);
79 len_bytes = 8;
80 }
Ulrich Drepper35f08c42008-01-18 19:59:08 +000081 else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE
82 && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
83 {
84 __libdw_seterrno (DWARF_E_INVALID_DWARF);
85 goto err_return;
86 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000087
88 /* Now we know the offset of the first offset/name pair. */
89 mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp;
90 mem[cnt].address_len = len_bytes;
Mark Wielaard38648042014-12-15 14:56:07 +010091 size_t max_size = dbg->sectiondata[IDX_debug_pubnames]->d_size;
92 if (mem[cnt].set_start >= max_size
93 || len - (2 + 2 * len_bytes) > max_size - mem[cnt].set_start)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000094 /* Something wrong, the first entry is beyond the end of
Mark Wielaard38648042014-12-15 14:56:07 +010095 the section. Or the length of the whole unit is too big. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000096 break;
97
98 /* Read the version. It better be two for now. */
99 uint16_t version = read_2ubyte_unaligned (dbg, readp);
Ulrich Drepper8d358d92008-01-22 06:34:31 +0000100 if (unlikely (version != 2))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000101 {
102 __libdw_seterrno (DWARF_E_INVALID_VERSION);
103 goto err_return;
104 }
105
106 /* Get the CU offset. */
Mark Wielaard775375e2012-06-22 12:02:45 +0200107 if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames,
108 readp + 2, len_bytes,
Ulrich Drepper99d23722009-06-14 20:19:45 -0700109 &mem[cnt].cu_offset, IDX_debug_info, 3))
110 /* Error has been already set in reader. */
111 goto err_return;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000112
113 /* Determine the size of the CU header. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000114 unsigned char *infop
115 = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
116 + mem[cnt].cu_offset);
Ulrich Drepper35f08c42008-01-18 19:59:08 +0000117 if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000118 mem[cnt].cu_header_size = 23;
119 else
120 mem[cnt].cu_header_size = 11;
121
122 ++cnt;
123
124 /* Advance to the next set. */
125 readp += len;
126 }
127
128 if (mem == NULL)
129 {
130 __libdw_seterrno (DWARF_E_NO_ENTRY);
131 return -1;
132 }
133
134 dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize);
135 dbg->pubnames_nsets = cnt;
136
137 return 0;
138}
139
140
141ptrdiff_t
142dwarf_getpubnames (dbg, callback, arg, offset)
143 Dwarf *dbg;
144 int (*callback) (Dwarf *, Dwarf_Global *, void *);
145 void *arg;
146 ptrdiff_t offset;
147{
148 if (dbg == NULL)
149 return -1l;
150
Ulrich Drepper8d358d92008-01-22 06:34:31 +0000151 if (unlikely (offset < 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000152 {
153 __libdw_seterrno (DWARF_E_INVALID_OFFSET);
154 return -1l;
155 }
156
157 /* Make sure it is a valid offset. */
158 if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL
159 || ((size_t) offset
160 >= dbg->sectiondata[IDX_debug_pubnames]->d_size)))
161 /* No (more) entry. */
162 return 0;
163
164 /* If necessary read the set information. */
Ulrich Drepper8d358d92008-01-22 06:34:31 +0000165 if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000166 return -1l;
167
168 /* Find the place where to start. */
169 size_t cnt;
170 if (offset == 0)
171 {
172 cnt = 0;
173 offset = dbg->pubnames_sets[0].set_start;
174 }
175 else
176 {
177 for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt)
178 if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start)
179 {
180 assert ((Dwarf_Off) offset
181 < dbg->pubnames_sets[cnt + 1].set_start);
182 break;
183 }
184 assert (cnt + 1 < dbg->pubnames_nsets);
185 }
186
187 unsigned char *startp
188 = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
Mark Wielaard38648042014-12-15 14:56:07 +0100189 unsigned char *endp
190 = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000191 unsigned char *readp = startp + offset;
192 while (1)
193 {
194 Dwarf_Global gl;
195
196 gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset
197 + dbg->pubnames_sets[cnt].cu_header_size);
198
199 while (1)
200 {
201 /* READP points to the next offset/name pair. */
202 if (dbg->pubnames_sets[cnt].address_len == 4)
203 gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp);
204 else
205 gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp);
206
207 /* If the offset is zero we reached the end of the set. */
208 if (gl.die_offset == 0)
209 break;
210
211 /* Add the CU offset. */
212 gl.die_offset += dbg->pubnames_sets[cnt].cu_offset;
213
214 gl.name = (char *) readp;
Mark Wielaard38648042014-12-15 14:56:07 +0100215 readp = (unsigned char *) memchr (gl.name, '\0', endp - readp);
216 if (unlikely (readp == NULL))
217 {
218 __libdw_seterrno (DWARF_E_INVALID_DWARF);
219 return -1l;
220 }
221 readp++;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000222
223 /* We found name and DIE offset. Report it. */
224 if (callback (dbg, &gl, arg) != DWARF_CB_OK)
225 {
226 /* The user wants us to stop. Return the offset of the
227 next entry. */
228 return readp - startp;
229 }
230 }
231
232 if (++cnt == dbg->pubnames_nsets)
233 /* This was the last set. */
234 break;
235
236 startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
237 readp = startp + dbg->pubnames_sets[cnt].set_start;
238 }
239
240 /* We are done. No more entries. */
241 return 0;
242}