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