xref: /aosp_15_r20/external/elfutils/libdw/dwarf_getpubnames.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Get public symbol information.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2002, 2003, 2004, 2005, 2008 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker    Written by Ulrich Drepper <[email protected]>, 2002.
5*7304104dSAndroid Build Coastguard Worker 
6*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker    it under the terms of either
8*7304104dSAndroid Build Coastguard Worker 
9*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker        your option) any later version
12*7304104dSAndroid Build Coastguard Worker 
13*7304104dSAndroid Build Coastguard Worker    or
14*7304104dSAndroid Build Coastguard Worker 
15*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker        your option) any later version
18*7304104dSAndroid Build Coastguard Worker 
19*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker 
21*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker 
26*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
28*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
29*7304104dSAndroid Build Coastguard Worker 
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker 
34*7304104dSAndroid Build Coastguard Worker #include <assert.h>
35*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
36*7304104dSAndroid Build Coastguard Worker #include <string.h>
37*7304104dSAndroid Build Coastguard Worker 
38*7304104dSAndroid Build Coastguard Worker #include <libdwP.h>
39*7304104dSAndroid Build Coastguard Worker #include <dwarf.h>
40*7304104dSAndroid Build Coastguard Worker #include <system.h>
41*7304104dSAndroid Build Coastguard Worker 
42*7304104dSAndroid Build Coastguard Worker 
43*7304104dSAndroid Build Coastguard Worker static int
get_offsets(Dwarf * dbg)44*7304104dSAndroid Build Coastguard Worker get_offsets (Dwarf *dbg)
45*7304104dSAndroid Build Coastguard Worker {
46*7304104dSAndroid Build Coastguard Worker   size_t allocated = 0;
47*7304104dSAndroid Build Coastguard Worker   size_t cnt = 0;
48*7304104dSAndroid Build Coastguard Worker   struct pubnames_s *mem = NULL;
49*7304104dSAndroid Build Coastguard Worker   const size_t entsize = sizeof (struct pubnames_s);
50*7304104dSAndroid Build Coastguard Worker   unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf;
51*7304104dSAndroid Build Coastguard Worker   unsigned char *readp = startp;
52*7304104dSAndroid Build Coastguard Worker   unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
53*7304104dSAndroid Build Coastguard Worker 
54*7304104dSAndroid Build Coastguard Worker   while (readp + 14 < endp)
55*7304104dSAndroid Build Coastguard Worker     {
56*7304104dSAndroid Build Coastguard Worker       /* If necessary, allocate more entries.  */
57*7304104dSAndroid Build Coastguard Worker       if (cnt >= allocated)
58*7304104dSAndroid Build Coastguard Worker 	{
59*7304104dSAndroid Build Coastguard Worker 	  allocated = MAX (10, 2 * allocated);
60*7304104dSAndroid Build Coastguard Worker 	  struct pubnames_s *newmem = realloc (mem, allocated * entsize);
61*7304104dSAndroid Build Coastguard Worker 	  if (newmem == NULL)
62*7304104dSAndroid Build Coastguard Worker 	    {
63*7304104dSAndroid Build Coastguard Worker 	      __libdw_seterrno (DWARF_E_NOMEM);
64*7304104dSAndroid Build Coastguard Worker 	    err_return:
65*7304104dSAndroid Build Coastguard Worker 	      free (mem);
66*7304104dSAndroid Build Coastguard Worker 	      return -1;
67*7304104dSAndroid Build Coastguard Worker 	    }
68*7304104dSAndroid Build Coastguard Worker 
69*7304104dSAndroid Build Coastguard Worker 	  mem = newmem;
70*7304104dSAndroid Build Coastguard Worker 	}
71*7304104dSAndroid Build Coastguard Worker 
72*7304104dSAndroid Build Coastguard Worker       /* Read the set header.  */
73*7304104dSAndroid Build Coastguard Worker       int len_bytes = 4;
74*7304104dSAndroid Build Coastguard Worker       Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp);
75*7304104dSAndroid Build Coastguard Worker       if (len == DWARF3_LENGTH_64_BIT)
76*7304104dSAndroid Build Coastguard Worker 	{
77*7304104dSAndroid Build Coastguard Worker 	  len = read_8ubyte_unaligned_inc (dbg, readp);
78*7304104dSAndroid Build Coastguard Worker 	  len_bytes = 8;
79*7304104dSAndroid Build Coastguard Worker 	}
80*7304104dSAndroid Build Coastguard Worker       else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE
81*7304104dSAndroid Build Coastguard Worker 			 && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
82*7304104dSAndroid Build Coastguard Worker 	{
83*7304104dSAndroid Build Coastguard Worker 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
84*7304104dSAndroid Build Coastguard Worker 	  goto err_return;
85*7304104dSAndroid Build Coastguard Worker 	}
86*7304104dSAndroid Build Coastguard Worker 
87*7304104dSAndroid Build Coastguard Worker       /* Now we know the offset of the first offset/name pair.  */
88*7304104dSAndroid Build Coastguard Worker       mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp;
89*7304104dSAndroid Build Coastguard Worker       mem[cnt].address_len = len_bytes;
90*7304104dSAndroid Build Coastguard Worker       size_t max_size = dbg->sectiondata[IDX_debug_pubnames]->d_size;
91*7304104dSAndroid Build Coastguard Worker       if (mem[cnt].set_start >= max_size
92*7304104dSAndroid Build Coastguard Worker 	  || len - (2 + 2 * len_bytes) > max_size - mem[cnt].set_start)
93*7304104dSAndroid Build Coastguard Worker 	/* Something wrong, the first entry is beyond the end of
94*7304104dSAndroid Build Coastguard Worker 	   the section.  Or the length of the whole unit is too big.  */
95*7304104dSAndroid Build Coastguard Worker 	break;
96*7304104dSAndroid Build Coastguard Worker 
97*7304104dSAndroid Build Coastguard Worker       /* Read the version.  It better be two for now.  */
98*7304104dSAndroid Build Coastguard Worker       uint16_t version = read_2ubyte_unaligned (dbg, readp);
99*7304104dSAndroid Build Coastguard Worker       if (unlikely (version != 2))
100*7304104dSAndroid Build Coastguard Worker 	{
101*7304104dSAndroid Build Coastguard Worker 	  __libdw_seterrno (DWARF_E_INVALID_VERSION);
102*7304104dSAndroid Build Coastguard Worker 	  goto err_return;
103*7304104dSAndroid Build Coastguard Worker 	}
104*7304104dSAndroid Build Coastguard Worker 
105*7304104dSAndroid Build Coastguard Worker       /* Get the CU offset.  */
106*7304104dSAndroid Build Coastguard Worker       if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames,
107*7304104dSAndroid Build Coastguard Worker 			       readp + 2, len_bytes,
108*7304104dSAndroid Build Coastguard Worker 			       &mem[cnt].cu_offset, IDX_debug_info, 3))
109*7304104dSAndroid Build Coastguard Worker 	/* Error has been already set in reader.  */
110*7304104dSAndroid Build Coastguard Worker 	goto err_return;
111*7304104dSAndroid Build Coastguard Worker 
112*7304104dSAndroid Build Coastguard Worker       /* Determine the size of the CU header.  */
113*7304104dSAndroid Build Coastguard Worker       unsigned char *infop
114*7304104dSAndroid Build Coastguard Worker 	= ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
115*7304104dSAndroid Build Coastguard Worker 	   + mem[cnt].cu_offset);
116*7304104dSAndroid Build Coastguard Worker       if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT)
117*7304104dSAndroid Build Coastguard Worker 	mem[cnt].cu_header_size = 23;
118*7304104dSAndroid Build Coastguard Worker       else
119*7304104dSAndroid Build Coastguard Worker 	mem[cnt].cu_header_size = 11;
120*7304104dSAndroid Build Coastguard Worker 
121*7304104dSAndroid Build Coastguard Worker       ++cnt;
122*7304104dSAndroid Build Coastguard Worker 
123*7304104dSAndroid Build Coastguard Worker       /* Advance to the next set.  */
124*7304104dSAndroid Build Coastguard Worker       readp += len;
125*7304104dSAndroid Build Coastguard Worker     }
126*7304104dSAndroid Build Coastguard Worker 
127*7304104dSAndroid Build Coastguard Worker   if (mem == NULL || cnt == 0)
128*7304104dSAndroid Build Coastguard Worker     {
129*7304104dSAndroid Build Coastguard Worker       free (mem);
130*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_NO_ENTRY);
131*7304104dSAndroid Build Coastguard Worker       return -1;
132*7304104dSAndroid Build Coastguard Worker     }
133*7304104dSAndroid Build Coastguard Worker 
134*7304104dSAndroid Build Coastguard Worker   dbg->pubnames_sets = realloc (mem, cnt * entsize);
135*7304104dSAndroid Build Coastguard Worker   dbg->pubnames_nsets = cnt;
136*7304104dSAndroid Build Coastguard Worker 
137*7304104dSAndroid Build Coastguard Worker   return 0;
138*7304104dSAndroid Build Coastguard Worker }
139*7304104dSAndroid Build Coastguard Worker 
140*7304104dSAndroid Build Coastguard Worker 
141*7304104dSAndroid Build Coastguard Worker ptrdiff_t
dwarf_getpubnames(Dwarf * dbg,int (* callback)(Dwarf *,Dwarf_Global *,void *),void * arg,ptrdiff_t offset)142*7304104dSAndroid Build Coastguard Worker dwarf_getpubnames (Dwarf *dbg,
143*7304104dSAndroid Build Coastguard Worker 		   int (*callback) (Dwarf *, Dwarf_Global *, void *),
144*7304104dSAndroid Build Coastguard Worker 		   void *arg, ptrdiff_t offset)
145*7304104dSAndroid Build Coastguard Worker {
146*7304104dSAndroid Build Coastguard Worker   if (dbg == NULL)
147*7304104dSAndroid Build Coastguard Worker     return -1l;
148*7304104dSAndroid Build Coastguard Worker 
149*7304104dSAndroid Build Coastguard Worker   if (unlikely (offset < 0))
150*7304104dSAndroid Build Coastguard Worker     {
151*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
152*7304104dSAndroid Build Coastguard Worker       return -1l;
153*7304104dSAndroid Build Coastguard Worker     }
154*7304104dSAndroid Build Coastguard Worker 
155*7304104dSAndroid Build Coastguard Worker   /* Make sure it is a valid offset.  */
156*7304104dSAndroid Build Coastguard Worker   if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL
157*7304104dSAndroid Build Coastguard Worker 		|| ((size_t) offset
158*7304104dSAndroid Build Coastguard Worker 		    >= dbg->sectiondata[IDX_debug_pubnames]->d_size)))
159*7304104dSAndroid Build Coastguard Worker     /* No (more) entry.  */
160*7304104dSAndroid Build Coastguard Worker     return 0;
161*7304104dSAndroid Build Coastguard Worker 
162*7304104dSAndroid Build Coastguard Worker   /* If necessary read the set information.  */
163*7304104dSAndroid Build Coastguard Worker   if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0))
164*7304104dSAndroid Build Coastguard Worker     return -1l;
165*7304104dSAndroid Build Coastguard Worker 
166*7304104dSAndroid Build Coastguard Worker   /* Find the place where to start.  */
167*7304104dSAndroid Build Coastguard Worker   size_t cnt;
168*7304104dSAndroid Build Coastguard Worker   if (offset == 0)
169*7304104dSAndroid Build Coastguard Worker     {
170*7304104dSAndroid Build Coastguard Worker       cnt = 0;
171*7304104dSAndroid Build Coastguard Worker       offset = dbg->pubnames_sets[0].set_start;
172*7304104dSAndroid Build Coastguard Worker     }
173*7304104dSAndroid Build Coastguard Worker   else
174*7304104dSAndroid Build Coastguard Worker     {
175*7304104dSAndroid Build Coastguard Worker       for (cnt = 0; cnt + 1 < dbg->pubnames_nsets; ++cnt)
176*7304104dSAndroid Build Coastguard Worker 	if ((Dwarf_Off) offset >= dbg->pubnames_sets[cnt].set_start)
177*7304104dSAndroid Build Coastguard Worker 	  {
178*7304104dSAndroid Build Coastguard Worker 	    assert ((Dwarf_Off) offset
179*7304104dSAndroid Build Coastguard Worker 		    < dbg->pubnames_sets[cnt + 1].set_start);
180*7304104dSAndroid Build Coastguard Worker 	    break;
181*7304104dSAndroid Build Coastguard Worker 	  }
182*7304104dSAndroid Build Coastguard Worker       assert (cnt + 1 < dbg->pubnames_nsets);
183*7304104dSAndroid Build Coastguard Worker     }
184*7304104dSAndroid Build Coastguard Worker 
185*7304104dSAndroid Build Coastguard Worker   unsigned char *startp
186*7304104dSAndroid Build Coastguard Worker     = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
187*7304104dSAndroid Build Coastguard Worker   unsigned char *endp
188*7304104dSAndroid Build Coastguard Worker     = startp + dbg->sectiondata[IDX_debug_pubnames]->d_size;
189*7304104dSAndroid Build Coastguard Worker   unsigned char *readp = startp + offset;
190*7304104dSAndroid Build Coastguard Worker   while (1)
191*7304104dSAndroid Build Coastguard Worker     {
192*7304104dSAndroid Build Coastguard Worker       Dwarf_Global gl;
193*7304104dSAndroid Build Coastguard Worker 
194*7304104dSAndroid Build Coastguard Worker       gl.cu_offset = (dbg->pubnames_sets[cnt].cu_offset
195*7304104dSAndroid Build Coastguard Worker 		      + dbg->pubnames_sets[cnt].cu_header_size);
196*7304104dSAndroid Build Coastguard Worker 
197*7304104dSAndroid Build Coastguard Worker       while (1)
198*7304104dSAndroid Build Coastguard Worker 	{
199*7304104dSAndroid Build Coastguard Worker 	  /* READP points to the next offset/name pair.  */
200*7304104dSAndroid Build Coastguard Worker 	  if (readp + dbg->pubnames_sets[cnt].address_len > endp)
201*7304104dSAndroid Build Coastguard Worker 	    goto invalid_dwarf;
202*7304104dSAndroid Build Coastguard Worker 	  if (dbg->pubnames_sets[cnt].address_len == 4)
203*7304104dSAndroid Build Coastguard Worker 	    gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp);
204*7304104dSAndroid Build Coastguard Worker 	  else
205*7304104dSAndroid Build Coastguard Worker 	    gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp);
206*7304104dSAndroid Build Coastguard Worker 
207*7304104dSAndroid Build Coastguard Worker 	  /* If the offset is zero we reached the end of the set.  */
208*7304104dSAndroid Build Coastguard Worker 	  if (gl.die_offset == 0)
209*7304104dSAndroid Build Coastguard Worker 	    break;
210*7304104dSAndroid Build Coastguard Worker 
211*7304104dSAndroid Build Coastguard Worker 	  /* Add the CU offset.  */
212*7304104dSAndroid Build Coastguard Worker 	  gl.die_offset += dbg->pubnames_sets[cnt].cu_offset;
213*7304104dSAndroid Build Coastguard Worker 
214*7304104dSAndroid Build Coastguard Worker 	  gl.name = (char *) readp;
215*7304104dSAndroid Build Coastguard Worker 	  readp = (unsigned char *) memchr (gl.name, '\0', endp - readp);
216*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (readp == NULL))
217*7304104dSAndroid Build Coastguard Worker 	    {
218*7304104dSAndroid Build Coastguard Worker 	    invalid_dwarf:
219*7304104dSAndroid Build Coastguard Worker 	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
220*7304104dSAndroid Build Coastguard Worker 	      return -1l;
221*7304104dSAndroid Build Coastguard Worker 	    }
222*7304104dSAndroid Build Coastguard Worker 	  readp++;
223*7304104dSAndroid Build Coastguard Worker 
224*7304104dSAndroid Build Coastguard Worker 	  /* We found name and DIE offset.  Report it.  */
225*7304104dSAndroid Build Coastguard Worker 	  if (callback (dbg, &gl, arg) != DWARF_CB_OK)
226*7304104dSAndroid Build Coastguard Worker 	    {
227*7304104dSAndroid Build Coastguard Worker 	      /* The user wants us to stop.  Return the offset of the
228*7304104dSAndroid Build Coastguard Worker 		 next entry.  */
229*7304104dSAndroid Build Coastguard Worker 	      return readp - startp;
230*7304104dSAndroid Build Coastguard Worker 	    }
231*7304104dSAndroid Build Coastguard Worker 	}
232*7304104dSAndroid Build Coastguard Worker 
233*7304104dSAndroid Build Coastguard Worker       if (++cnt == dbg->pubnames_nsets)
234*7304104dSAndroid Build Coastguard Worker 	/* This was the last set.  */
235*7304104dSAndroid Build Coastguard Worker 	break;
236*7304104dSAndroid Build Coastguard Worker 
237*7304104dSAndroid Build Coastguard Worker       startp = (unsigned char *) dbg->sectiondata[IDX_debug_pubnames]->d_buf;
238*7304104dSAndroid Build Coastguard Worker       readp = startp + dbg->pubnames_sets[cnt].set_start;
239*7304104dSAndroid Build Coastguard Worker     }
240*7304104dSAndroid Build Coastguard Worker 
241*7304104dSAndroid Build Coastguard Worker   /* We are done.  No more entries.  */
242*7304104dSAndroid Build Coastguard Worker   return 0;
243*7304104dSAndroid Build Coastguard Worker }
244