• 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 #include <sys/param.h>
38 
39 #include <libdwP.h>
40 #include <dwarf.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
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);
76       if (len == DWARF3_LENGTH_64_BIT)
77 	{
78 	  len = read_8ubyte_unaligned_inc (dbg, readp);
79 	  len_bytes = 8;
80 	}
81       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 	}
87 
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;
91       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)
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       uint16_t version = read_2ubyte_unaligned (dbg, readp);
100       if (unlikely (version != 2))
101 	{
102 	  __libdw_seterrno (DWARF_E_INVALID_VERSION);
103 	  goto err_return;
104 	}
105 
106       /* Get the CU offset.  */
107       if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames,
108 			       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       unsigned char *infop
115 	= ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
116 	   + mem[cnt].cu_offset);
117       if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT)
118 	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 || cnt == 0)
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 
141 ptrdiff_t
dwarf_getpubnames(dbg,callback,arg,offset)142 dwarf_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 
151   if (unlikely (offset < 0))
152     {
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.  */
165   if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0))
166     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;
189   unsigned char *endp
190     = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
191   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 (readp + dbg->pubnames_sets[cnt].address_len > endp)
203 	    goto invalid_dwarf;
204 	  if (dbg->pubnames_sets[cnt].address_len == 4)
205 	    gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp);
206 	  else
207 	    gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp);
208 
209 	  /* If the offset is zero we reached the end of the set.  */
210 	  if (gl.die_offset == 0)
211 	    break;
212 
213 	  /* Add the CU offset.  */
214 	  gl.die_offset += dbg->pubnames_sets[cnt].cu_offset;
215 
216 	  gl.name = (char *) readp;
217 	  readp = (unsigned char *) memchr (gl.name, '\0', endp - readp);
218 	  if (unlikely (readp == NULL))
219 	    {
220 	    invalid_dwarf:
221 	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
222 	      return -1l;
223 	    }
224 	  readp++;
225 
226 	  /* We found name and DIE offset.  Report it.  */
227 	  if (callback (dbg, &gl, arg) != DWARF_CB_OK)
228 	    {
229 	      /* The user wants us to stop.  Return the offset of the
230 		 next entry.  */
231 	      return readp - startp;
232 	    }
233 	}
234 
235       if (++cnt == dbg->pubnames_nsets)
236 	/* This was the last set.  */
237 	break;
238 
239       startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
240       readp = startp + dbg->pubnames_sets[cnt].set_start;
241     }
242 
243   /* We are done.  No more entries.  */
244   return 0;
245 }
246