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