1 /* Get public symbol information.
2 Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@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
get_offsets(Dwarf * dbg)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
dwarf_getpubnames(dbg,callback,arg,offset)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