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