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
39struct 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.  */
46static int
47compare_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
56int
57dwarf_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}
265INTDEF(dwarf_getaranges)
266