• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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