• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Return list address ranges.
2    Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
3    Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
4    This file is part of elfutils.
5    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
6 
7    This file is free software; you can redistribute it and/or modify
8    it under the terms of either
9 
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at
12        your option) any later version
13 
14    or
15 
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at
18        your option) any later version
19 
20    or both in parallel, as here.
21 
22    elfutils is distributed in the hope that it will be useful, but
23    WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26 
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see <http://www.gnu.org/licenses/>.  */
30 
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #include <stdlib.h>
36 #include <assert.h>
37 #include "libdwP.h"
38 #include <dwarf.h>
39 
40 struct arangelist
41 {
42   Dwarf_Arange arange;
43   struct arangelist *next;
44 };
45 
46 /* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers.  */
47 static int
compare_aranges(const void * a,const void * b)48 compare_aranges (const void *a, const void *b)
49 {
50   struct arangelist *const *p1 = a, *const *p2 = b;
51   struct arangelist *l1 = *p1, *l2 = *p2;
52   if (l1->arange.addr != l2->arange.addr)
53     return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
54   return 0;
55 }
56 
57 int
dwarf_getaranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges)58 dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
59 {
60   if (dbg == NULL)
61     return -1;
62 
63   if (dbg->aranges != NULL)
64     {
65       *aranges = dbg->aranges;
66       if (naranges != NULL)
67 	*naranges = dbg->aranges->naranges;
68       return 0;
69     }
70 
71   if (dbg->sectiondata[IDX_debug_aranges] == NULL)
72     {
73       /* No such section.  */
74       *aranges = NULL;
75       if (naranges != NULL)
76 	*naranges = 0;
77       return 0;
78     }
79 
80   if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
81     return -1;
82 
83   struct arangelist *arangelist = NULL;
84   unsigned int narangelist = 0;
85 
86   const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
87   const unsigned char *readendp
88     = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
89 
90   while (readp < readendp)
91     {
92       const unsigned char *hdrstart = readp;
93 
94       /* Each entry starts with a header:
95 
96 	 1. A 4-byte or 12-byte length containing the length of the
97 	 set of entries for this compilation unit, not including the
98 	 length field itself. [...]
99 
100 	 2. A 2-byte version identifier containing the value 2 for
101 	 DWARF Version 2.1.
102 
103 	 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
104 
105 	 4. A 1-byte unsigned integer containing the size in bytes of
106 	 an address (or the offset portion of an address for segmented
107 	 addressing) on the target system.
108 
109 	 5. A 1-byte unsigned integer containing the size in bytes of
110 	 a segment descriptor on the target system.  */
111       if (unlikely (readp + 4 > readendp))
112 	goto invalid;
113 
114       Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
115       unsigned int length_bytes = 4;
116       if (length == DWARF3_LENGTH_64_BIT)
117 	{
118 	  if (unlikely (readp + 8 > readendp))
119 	    goto invalid;
120 
121 	  length = read_8ubyte_unaligned_inc (dbg, readp);
122 	  length_bytes = 8;
123 	}
124       else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
125 			 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
126 	goto invalid;
127 
128       const unsigned char *endp = readp + length;
129       if (unlikely (endp > readendp))
130 	goto invalid;
131 
132       if (unlikely (readp + 2 > readendp))
133 	goto invalid;
134 
135       unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
136       if (version != 2)
137 	{
138 	invalid:
139 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
140 	fail:
141 	  while (arangelist != NULL)
142 	    {
143 	      struct arangelist *next = arangelist->next;
144 	      free (arangelist);
145 	      arangelist = next;
146 	    }
147 	  return -1;
148 	}
149 
150       Dwarf_Word offset = 0;
151       if (__libdw_read_offset_inc (dbg,
152 				   IDX_debug_aranges, &readp,
153 				   length_bytes, &offset, IDX_debug_info, 4))
154 	goto fail;
155 
156       /* Next up two bytes for address and segment size.  */
157       if (readp + 2 > readendp)
158 	goto invalid;
159 
160       unsigned int address_size = *readp++;
161       if (unlikely (address_size != 4 && address_size != 8))
162 	goto invalid;
163 
164       /* We don't actually support segment selectors.  */
165       unsigned int segment_size = *readp++;
166       if (segment_size != 0)
167 	goto invalid;
168 
169       /* Round the address to the next multiple of 2*address_size.  */
170       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
171 		% (2 * address_size));
172 
173       while (1)
174 	{
175 	  Dwarf_Word range_address;
176 	  Dwarf_Word range_length;
177 
178 	  if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
179 					address_size, &range_address))
180 	    goto fail;
181 
182 	  if (readp + address_size > readendp)
183 	    goto invalid;
184 
185 	  if (address_size == 4)
186 	    range_length = read_4ubyte_unaligned_inc (dbg, readp);
187 	  else
188 	    range_length = read_8ubyte_unaligned_inc (dbg, readp);
189 
190 	  /* Two zero values mark the end.  But in some cases (bugs)
191 	     there might be such entries in the middle of the table.
192 	     Ignore and continue, we'll check the actual length of
193 	     the table to see if we are really at the end.  */
194 	  if (range_address == 0 && range_length == 0)
195 	    {
196 	      if (readp >= endp)
197 		break;
198 	      else
199 		continue;
200 	    }
201 
202 	  /* We don't use alloca for these temporary structures because
203 	     the total number of them can be quite large.  */
204 	  struct arangelist *new_arange = malloc (sizeof *new_arange);
205 	  if (unlikely (new_arange == NULL))
206 	    {
207 	      __libdw_seterrno (DWARF_E_NOMEM);
208 	      goto fail;
209 	    }
210 
211 	  new_arange->arange.addr = range_address;
212 	  new_arange->arange.length = range_length;
213 
214 	  /* We store the actual CU DIE offset, not the CU header offset.  */
215 	  Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
216 	  if (unlikely (cu == NULL))
217 	    {
218 	      /* We haven't gotten a chance to link in the new_arange
219 		 into the arangelist, don't leak it.  */
220 	      free (new_arange);
221 	      goto fail;
222 	    }
223 	  new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
224 
225 	  new_arange->next = arangelist;
226 	  arangelist = new_arange;
227 	  ++narangelist;
228 
229 	  /* Sanity-check the data.  */
230 	  if (unlikely (new_arange->arange.offset
231 			>= dbg->sectiondata[IDX_debug_info]->d_size))
232 	    goto invalid;
233 	}
234     }
235 
236   if (narangelist == 0)
237     {
238       assert (arangelist == NULL);
239       if (naranges != NULL)
240 	*naranges = 0;
241       *aranges = NULL;
242       return 0;
243     }
244 
245   /* Allocate the array for the result.  */
246   void *buf = libdw_alloc (dbg, Dwarf_Aranges,
247 			   sizeof (Dwarf_Aranges)
248 			   + narangelist * sizeof (Dwarf_Arange), 1);
249 
250   /* First use the buffer for the pointers, and sort the entries.
251      We'll write the pointers in the end of the buffer, and then
252      copy into the buffer from the beginning so the overlap works.  */
253   assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
254   struct arangelist **sortaranges
255     = (buf + sizeof (Dwarf_Aranges)
256        + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
257 
258   /* The list is in LIFO order and usually they come in clumps with
259      ascending addresses.  So fill from the back to probably start with
260      runs already in order before we sort.  */
261   unsigned int i = narangelist;
262   while (i-- > 0)
263     {
264       sortaranges[i] = arangelist;
265       arangelist = arangelist->next;
266     }
267   assert (arangelist == NULL);
268 
269   /* Sort by ascending address.  */
270   qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
271 
272   /* Now that they are sorted, put them in the final array.
273      The buffers overlap, so we've clobbered the early elements
274      of SORTARANGES by the time we're reading the later ones.  */
275   *aranges = buf;
276   (*aranges)->dbg = dbg;
277   (*aranges)->naranges = narangelist;
278   dbg->aranges = *aranges;
279   if (naranges != NULL)
280     *naranges = narangelist;
281   for (i = 0; i < narangelist; ++i)
282     {
283       struct arangelist *elt = sortaranges[i];
284       (*aranges)->info[i] = elt->arange;
285       free (elt);
286     }
287 
288   return 0;
289 }
290 INTDEF(dwarf_getaranges)
291