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