Imported Upstream version 0.165
[platform/upstream/elfutils.git] / libdw / dwarf_getaranges.c
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
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
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       unsigned int address_size = *readp++;
152       if (unlikely (address_size != 4 && address_size != 8))
153         goto invalid;
154
155       /* We don't actually support segment selectors.  */
156       unsigned int segment_size = *readp++;
157       if (segment_size != 0)
158         goto invalid;
159
160       /* Round the address to the next multiple of 2*address_size.  */
161       readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
162                 % (2 * address_size));
163
164       while (1)
165         {
166           Dwarf_Word range_address;
167           Dwarf_Word range_length;
168
169           if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
170                                         address_size, &range_address))
171             goto fail;
172
173           if (readp + address_size > readendp)
174             goto invalid;
175
176           if (address_size == 4)
177             range_length = read_4ubyte_unaligned_inc (dbg, readp);
178           else
179             range_length = read_8ubyte_unaligned_inc (dbg, readp);
180
181           /* Two zero values mark the end.  */
182           if (range_address == 0 && range_length == 0)
183             break;
184
185           /* We don't use alloca for these temporary structures because
186              the total number of them can be quite large.  */
187           struct arangelist *new_arange = malloc (sizeof *new_arange);
188           if (unlikely (new_arange == NULL))
189             {
190               __libdw_seterrno (DWARF_E_NOMEM);
191               goto fail;
192             }
193
194           new_arange->arange.addr = range_address;
195           new_arange->arange.length = range_length;
196
197           /* We store the actual CU DIE offset, not the CU header offset.  */
198           const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
199                                    + offset);
200           unsigned int offset_size;
201           if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT)
202             offset_size = 8;
203           else
204             offset_size = 4;
205           new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
206                                                                  offset_size,
207                                                                  false);
208
209           new_arange->next = arangelist;
210           arangelist = new_arange;
211           ++narangelist;
212
213           /* Sanity-check the data.  */
214           if (unlikely (new_arange->arange.offset
215                         >= dbg->sectiondata[IDX_debug_info]->d_size))
216             goto invalid;
217         }
218     }
219
220   if (narangelist == 0)
221     {
222       assert (arangelist == NULL);
223       if (naranges != NULL)
224         *naranges = 0;
225       *aranges = NULL;
226       return 0;
227     }
228
229   /* Allocate the array for the result.  */
230   void *buf = libdw_alloc (dbg, Dwarf_Aranges,
231                            sizeof (Dwarf_Aranges)
232                            + narangelist * sizeof (Dwarf_Arange), 1);
233
234   /* First use the buffer for the pointers, and sort the entries.
235      We'll write the pointers in the end of the buffer, and then
236      copy into the buffer from the beginning so the overlap works.  */
237   assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
238   struct arangelist **sortaranges
239     = (buf + sizeof (Dwarf_Aranges)
240        + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
241
242   /* The list is in LIFO order and usually they come in clumps with
243      ascending addresses.  So fill from the back to probably start with
244      runs already in order before we sort.  */
245   unsigned int i = narangelist;
246   while (i-- > 0)
247     {
248       sortaranges[i] = arangelist;
249       arangelist = arangelist->next;
250     }
251   assert (arangelist == NULL);
252
253   /* Sort by ascending address.  */
254   qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
255
256   /* Now that they are sorted, put them in the final array.
257      The buffers overlap, so we've clobbered the early elements
258      of SORTARANGES by the time we're reading the later ones.  */
259   *aranges = buf;
260   (*aranges)->dbg = dbg;
261   (*aranges)->naranges = narangelist;
262   dbg->aranges = *aranges;
263   if (naranges != NULL)
264     *naranges = narangelist;
265   for (i = 0; i < narangelist; ++i)
266     {
267       struct arangelist *elt = sortaranges[i];
268       (*aranges)->info[i] = elt->arange;
269       free (elt);
270     }
271
272   return 0;
273 }
274 INTDEF(dwarf_getaranges)