dwarf_getaranges.c revision b08d5a8fb42f4586d756068065186b5af7e48dad
1/* Return list address ranges.
2   Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
3   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
4
5   This program is Open Source software; you can redistribute it and/or
6   modify it under the terms of the Open Software License version 1.0 as
7   published by the Open Source Initiative.
8
9   You should have received a copy of the Open Software License along
10   with this program; if not, you may obtain a copy of the Open Software
11   License version 1.0 from http://www.opensource.org/licenses/osl.php or
12   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13   3001 King Ranch Road, Ukiah, CA 95482.   */
14
15#ifdef HAVE_CONFIG_H
16# include <config.h>
17#endif
18
19#include <stdlib.h>
20#include <assert.h>
21#include "libdwP.h"
22
23
24struct arangelist
25{
26  Dwarf_Arange arange;
27  struct arangelist *next;
28};
29
30/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers.  */
31static int
32compare_aranges (const void *a, const void *b)
33{
34  Dwarf_Arange *const *p1 = a, *const *p2 = b;
35  Dwarf_Arange *l1 = *p1, *l2 = *p2;
36  return l1->addr - l2->addr;
37}
38
39int
40dwarf_getaranges (dbg, aranges, naranges)
41     Dwarf *dbg;
42     Dwarf_Aranges **aranges;
43     size_t *naranges;
44{
45  if (dbg == NULL)
46    return -1;
47
48  if (dbg->aranges != NULL)
49    {
50      *aranges = dbg->aranges;
51      if (naranges != NULL)
52	*naranges = dbg->aranges->naranges;
53      return 0;
54    }
55
56  if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
57    return -1;
58
59  struct arangelist *arangelist = NULL;
60  unsigned int narangelist = 0;
61
62  const char *readp
63    = (const char *) dbg->sectiondata[IDX_debug_aranges]->d_buf;
64  const char *readendp = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
65
66  while (readp < readendp)
67    {
68      const char *hdrstart = readp;
69
70      /* Each entry starts with a header:
71
72	 1. A 4-byte or 12-byte length containing the length of the
73	 set of entries for this compilation unit, not including the
74	 length field itself. [...]
75
76	 2. A 2-byte version identifier containing the value 2 for
77	 DWARF Version 2.1.
78
79	 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
80
81	 4. A 1-byte unsigned integer containing the size in bytes of
82	 an address (or the offset portion of an address for segmented
83	 addressing) on the target system.
84
85	 5. A 1-byte unsigned integer containing the size in bytes of
86	 a segment descriptor on the target system.  */
87      Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
88      unsigned int length_bytes = 4;
89      if (length == 0xffffffff)
90	{
91	  length = read_8ubyte_unaligned_inc (dbg, readp);
92	  length_bytes = 8;
93	}
94
95      unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
96      if (version != 2)
97	{
98	invalid:
99	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
100	  return -1;
101	}
102
103      Dwarf_Word offset;
104      if (length_bytes == 4)
105	offset = read_4ubyte_unaligned_inc (dbg, readp);
106      else
107	offset = read_8ubyte_unaligned_inc (dbg, readp);
108
109      unsigned int address_size = *readp++;
110      if (address_size != 4 && address_size != 8)
111	goto invalid;
112
113      /* Ignore the segment size value.  */
114      // XXX Really?
115      (void) *readp++;
116
117      /* Round the address to the next multiple of 2*address_size.  */
118      readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
119		% (2 * address_size));
120
121      while (1)
122	{
123	  Dwarf_Word range_address;
124	  Dwarf_Word range_length;
125
126	  if (address_size == 4)
127	    {
128	      range_address = read_4ubyte_unaligned_inc (dbg, readp);
129	      range_length = read_4ubyte_unaligned_inc (dbg, readp);
130	    }
131	  else
132	    {
133	      range_address = read_8ubyte_unaligned_inc (dbg, readp);
134	      range_length = read_8ubyte_unaligned_inc (dbg, readp);
135	    }
136
137	  /* Two zero values mark the end.  */
138	  if (range_address == 0 && range_length == 0)
139	    break;
140
141	  struct arangelist *new_arange =
142	    (struct arangelist *) alloca (sizeof (struct arangelist));
143
144	  new_arange->arange.addr = range_address;
145	  new_arange->arange.length = range_length;
146
147	  /* We store the actual CU DIE offset, not the CU header offset.  */
148	  const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
149				   + offset);
150	  unsigned int offset_size;
151	  if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff)
152	    offset_size = 8;
153	  else
154	    offset_size = 4;
155	  new_arange->arange.offset = offset + 3 * offset_size - 4 + 3;
156
157	  new_arange->next = arangelist;
158	  arangelist = new_arange;
159	  ++narangelist;
160	}
161    }
162
163  if (narangelist == 0)
164    {
165      if (naranges != NULL)
166	*naranges = 0;
167      *aranges = NULL;
168      return 0;
169    }
170
171  /* Allocate the array for the result.  */
172  void *buf = libdw_alloc (dbg, Dwarf_Aranges,
173			   sizeof (Dwarf_Aranges)
174			   + narangelist * sizeof (Dwarf_Arange), 1);
175
176  /* First use the buffer for the pointers, and sort the entries.
177     We'll write the pointers in the end of the buffer, and then
178     copy into the buffer from the beginning so the overlap works.  */
179  assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
180  Dwarf_Arange **sortaranges = (buf + sizeof (Dwarf_Aranges)
181				+ ((sizeof (Dwarf_Arange)
182				    - sizeof (Dwarf_Arange *)) * narangelist));
183
184  /* The list is in LIFO order and usually they come in clumps with
185     ascending addresses.  So fill from the back to probably start with
186     runs already in order before we sort.  */
187  unsigned int i = narangelist;
188  while (i-- > 0)
189    {
190      sortaranges[i] = &arangelist->arange;
191      arangelist = arangelist->next;
192    }
193  assert (arangelist == NULL);
194
195  /* Sort by ascending address.  */
196  qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
197
198  /* Now that they are sorted, put them in the final array.
199     The buffers overlap, so we've clobbered the early elements
200     of SORTARANGES by the time we're reading the later ones.  */
201  *aranges = buf;
202  (*aranges)->dbg = dbg;
203  (*aranges)->naranges = narangelist;
204  dbg->aranges = *aranges;
205  if (naranges != NULL)
206    *naranges = narangelist;
207  for (i = 0; i < narangelist; ++i)
208    (*aranges)->info[i] = *sortaranges[i];
209
210  return 0;
211}
212INTDEF(dwarf_getaranges)
213