• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
get_offsets(Dwarf * dbg)44 get_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 = realloc (mem, allocated * entsize);
61 	  if (newmem == NULL)
62 	    {
63 	      __libdw_seterrno (DWARF_E_NOMEM);
64 	    err_return:
65 	      free (mem);
66 	      return -1;
67 	    }
68 
69 	  mem = newmem;
70 	}
71 
72       /* Read the set header.  */
73       int len_bytes = 4;
74       Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp);
75       if (len == DWARF3_LENGTH_64_BIT)
76 	{
77 	  len = read_8ubyte_unaligned_inc (dbg, readp);
78 	  len_bytes = 8;
79 	}
80       else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE
81 			 && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
82 	{
83 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
84 	  goto err_return;
85 	}
86 
87       /* Now we know the offset of the first offset/name pair.  */
88       mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp;
89       mem[cnt].address_len = len_bytes;
90       size_t max_size = dbg->sectiondata[IDX_debug_pubnames]->d_size;
91       if (mem[cnt].set_start >= max_size
92 	  || 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       uint16_t version = read_2ubyte_unaligned (dbg, readp);
99       if (unlikely (version != 2))
100 	{
101 	  __libdw_seterrno (DWARF_E_INVALID_VERSION);
102 	  goto err_return;
103 	}
104 
105       /* Get the CU offset.  */
106       if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames,
107 			       readp + 2, len_bytes,
108 			       &mem[cnt].cu_offset, IDX_debug_info, 3))
109 	/* Error has been already set in reader.  */
110 	goto err_return;
111 
112       /* Determine the size of the CU header.  */
113       unsigned char *infop
114 	= ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
115 	   + mem[cnt].cu_offset);
116       if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT)
117 	mem[cnt].cu_header_size = 23;
118       else
119 	mem[cnt].cu_header_size = 11;
120 
121       ++cnt;
122 
123       /* Advance to the next set.  */
124       readp += len;
125     }
126 
127   if (mem == NULL || cnt == 0)
128     {
129       free (mem);
130       __libdw_seterrno (DWARF_E_NO_ENTRY);
131       return -1;
132     }
133 
134   dbg->pubnames_sets = realloc (mem, cnt * entsize);
135   dbg->pubnames_nsets = cnt;
136 
137   return 0;
138 }
139 
140 
141 ptrdiff_t
dwarf_getpubnames(Dwarf * dbg,int (* callback)(Dwarf *,Dwarf_Global *,void *),void * arg,ptrdiff_t offset)142 dwarf_getpubnames (Dwarf *dbg,
143 		   int (*callback) (Dwarf *, Dwarf_Global *, void *),
144 		   void *arg, ptrdiff_t offset)
145 {
146   if (dbg == NULL)
147     return -1l;
148 
149   if (unlikely (offset < 0))
150     {
151       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
152       return -1l;
153     }
154 
155   /* Make sure it is a valid offset.  */
156   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   if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0))
164     return -1l;
165 
166   /* Find the place where to start.  */
167   size_t cnt;
168   if (offset == 0)
169     {
170       cnt = 0;
171       offset = dbg->pubnames_sets[0].set_start;
172     }
173   else
174     {
175       for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt)
176 	if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start)
177 	  {
178 	    assert ((Dwarf_Off) offset
179 		    < dbg->pubnames_sets[cnt + 1].set_start);
180 	    break;
181 	  }
182       assert (cnt + 1 < dbg->pubnames_nsets);
183     }
184 
185   unsigned char *startp
186     = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
187   unsigned char *endp
188     = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
189   unsigned char *readp = startp + offset;
190   while (1)
191     {
192       Dwarf_Global gl;
193 
194       gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset
195 		      + dbg->pubnames_sets[cnt].cu_header_size);
196 
197       while (1)
198 	{
199 	  /* READP points to the next offset/name pair.  */
200 	  if (readp + dbg->pubnames_sets[cnt].address_len > endp)
201 	    goto invalid_dwarf;
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;
215 	  readp = (unsigned char *) memchr (gl.name, '\0', endp - readp);
216 	  if (unlikely (readp == NULL))
217 	    {
218 	    invalid_dwarf:
219 	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
220 	      return -1l;
221 	    }
222 	  readp++;
223 
224 	  /* We found name and DIE offset.  Report it.  */
225 	  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 	      return readp - startp;
230 	    }
231 	}
232 
233       if (++cnt == dbg->pubnames_nsets)
234 	/* This was the last set.  */
235 	break;
236 
237       startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
238       readp = startp + dbg->pubnames_sets[cnt].set_start;
239     }
240 
241   /* We are done.  No more entries.  */
242   return 0;
243 }
244