xref: /aosp_15_r20/external/elfutils/libdw/dwarf_getaranges.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1 /* Return list address ranges.
2    Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
3    Copyright (C) 2023 Mark J. Wielaard <[email protected]>
4    This file is part of elfutils.
5    Written by Ulrich Drepper <[email protected]>, 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 "libdwP.h"
37 #include <dwarf.h>
38 
39 struct arangelist
40 {
41   Dwarf_Arange arange;
42   struct arangelist *next;
43 };
44 
45 /* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers.  */
46 static int
compare_aranges(const void * a,const void * b)47 compare_aranges (const void *a, const void *b)
48 {
49   struct arangelist *const *p1 = a, *const *p2 = b;
50   struct arangelist *l1 = *p1, *l2 = *p2;
51   if (l1->arange.addr != l2->arange.addr)
52     return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
53   return 0;
54 }
55 
56 /* Convert ARANGELIST into Dwarf_Aranges and store at ARANGES.  */
57 static bool
finalize_aranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges,struct arangelist * arangelist,unsigned int narangelist)58 finalize_aranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges,
59 		  struct arangelist *arangelist, unsigned int narangelist)
60 {
61   /* Allocate the array for the result.  */
62   void *buf = libdw_alloc (dbg, Dwarf_Aranges,
63 			   sizeof (Dwarf_Aranges)
64 			   + narangelist * sizeof (Dwarf_Arange), 1);
65 
66   /* First use the buffer for the pointers, and sort the entries.
67      We'll write the pointers in the end of the buffer, and then
68      copy into the buffer from the beginning so the overlap works.  */
69   eu_static_assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
70   struct arangelist **sortaranges
71     = (buf + sizeof (Dwarf_Aranges)
72        + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
73 
74   /* The list is in LIFO order and usually they come in clumps with
75      ascending addresses.  So fill from the back to probably start with
76      runs already in order before we sort.  */
77   unsigned int i = narangelist;
78   while (i-- > 0)
79     {
80       sortaranges[i] = arangelist;
81       arangelist = arangelist->next;
82     }
83 
84   /* Something went wrong if narangelist is less then the actual length
85      of arangelist. */
86   if (arangelist != NULL)
87     {
88       __libdw_seterrno (DWARF_E_UNKNOWN_ERROR);
89       return false;
90     }
91 
92   /* Sort by ascending address.  */
93   qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
94 
95   /* Now that they are sorted, put them in the final array.
96      The buffers overlap, so we've clobbered the early elements
97      of SORTARANGES by the time we're reading the later ones.  */
98   *aranges = buf;
99   (*aranges)->dbg = dbg;
100   (*aranges)->naranges = narangelist;
101   if (naranges != NULL)
102     *naranges = narangelist;
103   for (i = 0; i < narangelist; ++i)
104     {
105       struct arangelist *elt = sortaranges[i];
106       (*aranges)->info[i] = elt->arange;
107       free (elt);
108     }
109 
110   return true;
111 }
112 
113 int
__libdw_getdieranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges)114 __libdw_getdieranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
115 {
116   if (dbg == NULL)
117     return -1;
118 
119   if (dbg->dieranges != NULL)
120     {
121       *aranges = dbg->dieranges;
122       if (naranges != NULL)
123 	*naranges = dbg->dieranges->naranges;
124       return 0;
125     }
126 
127   struct arangelist *arangelist = NULL;
128   unsigned int narangelist = 0;
129 
130   Dwarf_CU *cu = NULL;
131   while (INTUSE(dwarf_get_units) (dbg, cu, &cu, NULL, NULL, NULL, NULL) == 0)
132     {
133       Dwarf_Addr base;
134       Dwarf_Addr low;
135       Dwarf_Addr high;
136 
137       Dwarf_Die cudie = CUDIE (cu);
138 
139       /* Skip CUs that only contain type information.  */
140       if (!INTUSE(dwarf_hasattr) (&cudie, DW_AT_low_pc)
141 	  && !INTUSE(dwarf_hasattr) (&cudie, DW_AT_ranges))
142 	continue;
143 
144       ptrdiff_t offset = 0;
145 
146       /* Add arange for each range list entry or high_pc and low_pc.  */
147       while ((offset = INTUSE(dwarf_ranges) (&cudie, offset,
148 					     &base, &low, &high)) > 0)
149 	{
150 	  if (offset == -1)
151 	    {
152 	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
153 	      goto fail;
154 	    }
155 
156 	  struct arangelist *new_arange = malloc (sizeof *new_arange);
157 	  if (unlikely (new_arange == NULL))
158 	    {
159 	      __libdw_seterrno (DWARF_E_NOMEM);
160 	      goto fail;
161 	    }
162 
163 	  new_arange->arange.addr = low;
164 	  new_arange->arange.length = (Dwarf_Word) (high - low);
165 	  new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
166 
167 	  new_arange->next = arangelist;
168 	  arangelist = new_arange;
169 	  ++narangelist;
170 	}
171     }
172 
173   if (narangelist == 0)
174     {
175       if (naranges != NULL)
176 	*naranges = 0;
177       *aranges = NULL;
178       return 0;
179     }
180 
181   if (!finalize_aranges (dbg, aranges, naranges, arangelist, narangelist))
182     goto fail;
183 
184   dbg->dieranges = *aranges;
185   return 0;
186 
187 fail:
188   while (arangelist != NULL)
189     {
190       struct arangelist *next = arangelist->next;
191       free (arangelist);
192       arangelist = next;
193     }
194   return -1;
195 }
196 
197 int
dwarf_getaranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges)198 dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
199 {
200   if (dbg == NULL)
201     return -1;
202 
203   if (dbg->aranges != NULL)
204     {
205       *aranges = dbg->aranges;
206       if (naranges != NULL)
207 	*naranges = dbg->aranges->naranges;
208       return 0;
209     }
210 
211   if (dbg->sectiondata[IDX_debug_aranges] == NULL)
212     {
213       /* No such section.  */
214       *aranges = NULL;
215       if (naranges != NULL)
216 	*naranges = 0;
217       return 0;
218     }
219 
220   if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
221     return -1;
222 
223   struct arangelist *arangelist = NULL;
224   unsigned int narangelist = 0;
225 
226   const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
227   const unsigned char *readendp
228     = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
229 
230   while (readp < readendp)
231     {
232       const unsigned char *hdrstart = readp;
233 
234       /* Each entry starts with a header:
235 
236 	 1. A 4-byte or 12-byte length containing the length of the
237 	 set of entries for this compilation unit, not including the
238 	 length field itself. [...]
239 
240 	 2. A 2-byte version identifier containing the value 2 for
241 	 DWARF Version 2.1.
242 
243 	 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
244 
245 	 4. A 1-byte unsigned integer containing the size in bytes of
246 	 an address (or the offset portion of an address for segmented
247 	 addressing) on the target system.
248 
249 	 5. A 1-byte unsigned integer containing the size in bytes of
250 	 a segment descriptor on the target system.  */
251       if (unlikely (readp + 4 > readendp))
252 	goto invalid;
253 
254       Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
255       unsigned int length_bytes = 4;
256       if (length == DWARF3_LENGTH_64_BIT)
257 	{
258 	  if (unlikely (readp + 8 > readendp))
259 	    goto invalid;
260 
261 	  length = read_8ubyte_unaligned_inc (dbg, readp);
262 	  length_bytes = 8;
263 	}
264       else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
265 			 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
266 	goto invalid;
267 
268       const unsigned char *endp = readp + length;
269       if (unlikely (endp > readendp))
270 	goto invalid;
271 
272       if (unlikely (readp + 2 > readendp))
273 	goto invalid;
274 
275       unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
276       if (version != 2)
277 	{
278 	invalid:
279 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
280 	fail:
281 	  while (arangelist != NULL)
282 	    {
283 	      struct arangelist *next = arangelist->next;
284 	      free (arangelist);
285 	      arangelist = next;
286 	    }
287 	  return -1;
288 	}
289 
290       Dwarf_Word offset = 0;
291       if (__libdw_read_offset_inc (dbg,
292 				   IDX_debug_aranges, &readp,
293 				   length_bytes, &offset, IDX_debug_info, 4))
294 	goto fail;
295 
296       /* Next up two bytes for address and segment size.  */
297       if (readp + 2 > readendp)
298 	goto invalid;
299 
300       unsigned int address_size = *readp++;
301       if (unlikely (address_size != 4 && address_size != 8))
302 	goto invalid;
303 
304       /* We don't actually support segment selectors.  */
305       unsigned int segment_size = *readp++;
306       if (segment_size != 0)
307 	goto invalid;
308 
309       /* Round the address to the next multiple of 2*address_size.  */
310       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
311 		% (2 * address_size));
312 
313       while (1)
314 	{
315 	  Dwarf_Word range_address;
316 	  Dwarf_Word range_length;
317 
318 	  if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
319 					address_size, &range_address))
320 	    goto fail;
321 
322 	  if (readp + address_size > readendp)
323 	    goto invalid;
324 
325 	  if (address_size == 4)
326 	    range_length = read_4ubyte_unaligned_inc (dbg, readp);
327 	  else
328 	    range_length = read_8ubyte_unaligned_inc (dbg, readp);
329 
330 	  /* Two zero values mark the end.  But in some cases (bugs)
331 	     there might be such entries in the middle of the table.
332 	     Ignore and continue, we'll check the actual length of
333 	     the table to see if we are really at the end.  */
334 	  if (range_address == 0 && range_length == 0)
335 	    {
336 	      if (readp >= endp)
337 		break;
338 	      else
339 		continue;
340 	    }
341 
342 	  /* We don't use alloca for these temporary structures because
343 	     the total number of them can be quite large.  */
344 	  struct arangelist *new_arange = malloc (sizeof *new_arange);
345 	  if (unlikely (new_arange == NULL))
346 	    {
347 	      __libdw_seterrno (DWARF_E_NOMEM);
348 	      goto fail;
349 	    }
350 
351 	  new_arange->arange.addr = range_address;
352 	  new_arange->arange.length = range_length;
353 
354 	  /* We store the actual CU DIE offset, not the CU header offset.  */
355 	  Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
356 	  if (unlikely (cu == NULL))
357 	    {
358 	      /* We haven't gotten a chance to link in the new_arange
359 		 into the arangelist, don't leak it.  */
360 	      free (new_arange);
361 	      goto fail;
362 	    }
363 	  new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
364 
365 	  new_arange->next = arangelist;
366 	  arangelist = new_arange;
367 	  ++narangelist;
368 
369 	  /* Sanity-check the data.  */
370 	  if (unlikely (new_arange->arange.offset
371 			>= dbg->sectiondata[IDX_debug_info]->d_size))
372 	    goto invalid;
373 	}
374     }
375 
376   if (narangelist == 0)
377     {
378       if (naranges != NULL)
379 	*naranges = 0;
380       *aranges = NULL;
381       return 0;
382     }
383 
384   if (!finalize_aranges (dbg, aranges, naranges, arangelist, narangelist))
385     goto fail;
386 
387   dbg->aranges = *aranges;
388   return 0;
389 }
390 INTDEF(dwarf_getaranges)
391