1 /* Return list address ranges.
2    Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
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 <stdlib.h>
35 #include <assert.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 int
dwarf_getaranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges)57 dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
58 {
59   if (dbg == NULL)
60     return -1;
61 
62   if (dbg->aranges != NULL)
63     {
64       *aranges = dbg->aranges;
65       if (naranges != NULL)
66 	*naranges = dbg->aranges->naranges;
67       return 0;
68     }
69 
70   if (dbg->sectiondata[IDX_debug_aranges] == NULL)
71     {
72       /* No such section.  */
73       *aranges = NULL;
74       if (naranges != NULL)
75 	*naranges = 0;
76       return 0;
77     }
78 
79   if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
80     return -1;
81 
82   struct arangelist *arangelist = NULL;
83   unsigned int narangelist = 0;
84 
85   const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
86   const unsigned char *readendp
87     = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
88 
89   while (readp < readendp)
90     {
91       const unsigned char *hdrstart = readp;
92 
93       /* Each entry starts with a header:
94 
95 	 1. A 4-byte or 12-byte length containing the length of the
96 	 set of entries for this compilation unit, not including the
97 	 length field itself. [...]
98 
99 	 2. A 2-byte version identifier containing the value 2 for
100 	 DWARF Version 2.1.
101 
102 	 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
103 
104 	 4. A 1-byte unsigned integer containing the size in bytes of
105 	 an address (or the offset portion of an address for segmented
106 	 addressing) on the target system.
107 
108 	 5. A 1-byte unsigned integer containing the size in bytes of
109 	 a segment descriptor on the target system.  */
110       if (unlikely (readp + 4 > readendp))
111 	goto invalid;
112 
113       Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
114       unsigned int length_bytes = 4;
115       if (length == DWARF3_LENGTH_64_BIT)
116 	{
117 	  if (unlikely (readp + 8 > readendp))
118 	    goto invalid;
119 
120 	  length = read_8ubyte_unaligned_inc (dbg, readp);
121 	  length_bytes = 8;
122 	}
123       else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
124 			 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
125 	goto invalid;
126 
127       if (unlikely (readp + 2 > readendp))
128 	goto invalid;
129 
130       unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
131       if (version != 2)
132 	{
133 	invalid:
134 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
135 	fail:
136 	  while (arangelist != NULL)
137 	    {
138 	      struct arangelist *next = arangelist->next;
139 	      free (arangelist);
140 	      arangelist = next;
141 	    }
142 	  return -1;
143 	}
144 
145       Dwarf_Word offset = 0;
146       if (__libdw_read_offset_inc (dbg,
147 				   IDX_debug_aranges, &readp,
148 				   length_bytes, &offset, IDX_debug_info, 4))
149 	goto fail;
150 
151       /* Next up two bytes for address and segment size.  */
152       if (readp + 2 > readendp)
153 	goto invalid;
154 
155       unsigned int address_size = *readp++;
156       if (unlikely (address_size != 4 && address_size != 8))
157 	goto invalid;
158 
159       /* We don't actually support segment selectors.  */
160       unsigned int segment_size = *readp++;
161       if (segment_size != 0)
162 	goto invalid;
163 
164       /* Round the address to the next multiple of 2*address_size.  */
165       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
166 		% (2 * address_size));
167 
168       while (1)
169 	{
170 	  Dwarf_Word range_address;
171 	  Dwarf_Word range_length;
172 
173 	  if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
174 					address_size, &range_address))
175 	    goto fail;
176 
177 	  if (readp + address_size > readendp)
178 	    goto invalid;
179 
180 	  if (address_size == 4)
181 	    range_length = read_4ubyte_unaligned_inc (dbg, readp);
182 	  else
183 	    range_length = read_8ubyte_unaligned_inc (dbg, readp);
184 
185 	  /* Two zero values mark the end.  */
186 	  if (range_address == 0 && range_length == 0)
187 	    break;
188 
189 	  /* We don't use alloca for these temporary structures because
190 	     the total number of them can be quite large.  */
191 	  struct arangelist *new_arange = malloc (sizeof *new_arange);
192 	  if (unlikely (new_arange == NULL))
193 	    {
194 	      __libdw_seterrno (DWARF_E_NOMEM);
195 	      goto fail;
196 	    }
197 
198 	  new_arange->arange.addr = range_address;
199 	  new_arange->arange.length = range_length;
200 
201 	  /* We store the actual CU DIE offset, not the CU header offset.  */
202 	  Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
203 	  if (unlikely (cu == NULL))
204 	    {
205 	      /* We haven't gotten a chance to link in the new_arange
206 		 into the arangelist, don't leak it.  */
207 	      free (new_arange);
208 	      goto fail;
209 	    }
210 	  new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
211 
212 	  new_arange->next = arangelist;
213 	  arangelist = new_arange;
214 	  ++narangelist;
215 
216 	  /* Sanity-check the data.  */
217 	  if (unlikely (new_arange->arange.offset
218 			>= dbg->sectiondata[IDX_debug_info]->d_size))
219 	    goto invalid;
220 	}
221     }
222 
223   if (narangelist == 0)
224     {
225       assert (arangelist == NULL);
226       if (naranges != NULL)
227 	*naranges = 0;
228       *aranges = NULL;
229       return 0;
230     }
231 
232   /* Allocate the array for the result.  */
233   void *buf = libdw_alloc (dbg, Dwarf_Aranges,
234 			   sizeof (Dwarf_Aranges)
235 			   + narangelist * sizeof (Dwarf_Arange), 1);
236 
237   /* First use the buffer for the pointers, and sort the entries.
238      We'll write the pointers in the end of the buffer, and then
239      copy into the buffer from the beginning so the overlap works.  */
240   assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
241   struct arangelist **sortaranges
242     = (buf + sizeof (Dwarf_Aranges)
243        + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
244 
245   /* The list is in LIFO order and usually they come in clumps with
246      ascending addresses.  So fill from the back to probably start with
247      runs already in order before we sort.  */
248   unsigned int i = narangelist;
249   while (i-- > 0)
250     {
251       sortaranges[i] = arangelist;
252       arangelist = arangelist->next;
253     }
254   assert (arangelist == NULL);
255 
256   /* Sort by ascending address.  */
257   qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
258 
259   /* Now that they are sorted, put them in the final array.
260      The buffers overlap, so we've clobbered the early elements
261      of SORTARANGES by the time we're reading the later ones.  */
262   *aranges = buf;
263   (*aranges)->dbg = dbg;
264   (*aranges)->naranges = narangelist;
265   dbg->aranges = *aranges;
266   if (naranges != NULL)
267     *naranges = narangelist;
268   for (i = 0; i < narangelist; ++i)
269     {
270       struct arangelist *elt = sortaranges[i];
271       (*aranges)->info[i] = elt->arange;
272       free (elt);
273     }
274 
275   return 0;
276 }
277 INTDEF(dwarf_getaranges)
278