xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_arange.c (revision 8a2b682e57a046b828f37bcde1776f131ef4629f)
1 /*
2 
3   Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
4   Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of version 2.1 of the GNU Lesser General Public License
8   as published by the Free Software Foundation.
9 
10   This program is distributed in the hope that it would be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14   Further, this software is distributed without any warranty that it is
15   free of the rightful claim of any third person regarding infringement
16   or the like.  Any license provided herein, whether implied or
17   otherwise, applies only to this software file.  Patent licenses, if
18   any, provided herein do not apply to combinations of this program with
19   other software, or any other product whatsoever.
20 
21   You should have received a copy of the GNU Lesser General Public
22   License along with this program; if not, write the Free Software
23   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24   USA.
25 
26   Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
27   Mountain View, CA 94043, or:
28 
29   http://www.sgi.com
30 
31   For further information regarding this notice, see:
32 
33   http://oss.sgi.com/projects/GenInfo/NoticeExplan
34 
35 */
36 /* The address of the Free Software Foundation is
37    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
38    Boston, MA 02110-1301, USA.
39    SGI has moved from the Crittenden Lane address.
40 */
41 
42 
43 
44 
45 
46 
47 #include "config.h"
48 #include "dwarf_incl.h"
49 #include <stdio.h>
50 #include "dwarf_arange.h"
51 #include "dwarf_global.h"       /* for _dwarf_fixup_* */
52 
53 
54 /* Common code for two user-visible routines to share.
55    Errors here result in memory leaks, but errors here
56    are serious (making aranges unusable) so we assume
57    callers will not repeat the error often or mind the leaks.
58 */
59 static int
60 dwarf_get_aranges_list(Dwarf_Debug dbg,
61     Dwarf_Chain  * chain_out,
62     Dwarf_Signed * chain_count_out,
63     Dwarf_Error  * error)
64 {
65     /* Sweeps through the arange. */
66     Dwarf_Small *arange_ptr = 0;
67     Dwarf_Small *arange_ptr_start = 0;
68 
69     /* Start of arange header.  Used for rounding offset of arange_ptr
70        to twice the tuple size.  Libdwarf requirement. */
71     Dwarf_Small *header_ptr = 0;
72 
73     /* Version of .debug_aranges header. */
74     Dwarf_Half version = 0;
75 
76     /* Offset of current set of aranges into .debug_info. */
77     Dwarf_Off info_offset = 0;
78 
79     /* Size in bytes of addresses in target. */
80     Dwarf_Small address_size = 0;
81 
82     /* Size in bytes of segment offsets in target. */
83     Dwarf_Small segment_size = 0;
84 
85     /* Count of total number of aranges. */
86     Dwarf_Unsigned arange_count = 0;
87 
88     Dwarf_Arange arange = 0;
89 
90     /* Used to chain Dwarf_Aranges structs. */
91     Dwarf_Chain curr_chain = NULL;
92     Dwarf_Chain prev_chain = NULL;
93     Dwarf_Chain head_chain = NULL;
94 
95     arange_ptr = dbg->de_debug_aranges.dss_data;
96     arange_ptr_start = arange_ptr;
97     do {
98         /* Length of current set of aranges. */
99         Dwarf_Unsigned length = 0;
100         Dwarf_Small remainder = 0;
101         Dwarf_Small *arange_ptr_past_end = 0;
102         Dwarf_Unsigned range_entry_size = 0;
103 
104         int local_length_size;
105 
106          /*REFERENCED*/ /* Not used in this instance of the macro */
107         int local_extension_size = 0;
108 
109         header_ptr = arange_ptr;
110 
111         /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
112         READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
113             arange_ptr, local_length_size,
114             local_extension_size);
115         arange_ptr_past_end = arange_ptr + length;
116 
117 
118         READ_UNALIGNED(dbg, version, Dwarf_Half,
119             arange_ptr, sizeof(Dwarf_Half));
120         arange_ptr += sizeof(Dwarf_Half);
121         length = length - sizeof(Dwarf_Half);
122         if (version != CURRENT_VERSION_STAMP) {
123             _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
124             return (DW_DLV_ERROR);
125         }
126 
127         READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
128             arange_ptr, local_length_size);
129         arange_ptr += local_length_size;
130         length = length - local_length_size;
131         if (info_offset >= dbg->de_debug_info.dss_size) {
132             FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
133                 "arange info offset.a");
134             if (info_offset >= dbg->de_debug_info.dss_size) {
135                 _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
136                 return (DW_DLV_ERROR);
137             }
138         }
139 
140         address_size = *(Dwarf_Small *) arange_ptr;
141         /* It is not an error if the sizes differ.
142            Unusual, but not an error. */
143         arange_ptr = arange_ptr + sizeof(Dwarf_Small);
144         length = length - sizeof(Dwarf_Small);
145 
146         segment_size = *(Dwarf_Small *) arange_ptr;
147         arange_ptr = arange_ptr + sizeof(Dwarf_Small);
148         length = length - sizeof(Dwarf_Small);
149         if (segment_size != 0) {
150             _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
151             return (DW_DLV_ERROR);
152         }
153 
154         range_entry_size = 2*address_size + segment_size;
155         /* Round arange_ptr offset to next multiple of address_size. */
156         remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
157             (range_entry_size);
158         if (remainder != 0) {
159             arange_ptr = arange_ptr + (2 * address_size) - remainder;
160             length = length - ((2 * address_size) - remainder);
161         }
162         do {
163             Dwarf_Addr range_address = 0;
164             Dwarf_Unsigned segment_selector = 0;
165             Dwarf_Unsigned range_length = 0;
166             /* For segmented address spaces, the first field to
167                read is a segment selector (new in DWARF4) */
168             if(version == 4 && segment_size != 0) {
169                 READ_UNALIGNED(dbg, segment_selector, Dwarf_Unsigned,
170                     arange_ptr, segment_size);
171                 arange_ptr += address_size;
172                 length = length - address_size;
173             }
174 
175             READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
176                 arange_ptr, address_size);
177             arange_ptr += address_size;
178             length = length - address_size;
179 
180             READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
181                 arange_ptr, address_size);
182             arange_ptr += address_size;
183             length = length - address_size;
184 
185             { /* We used to suppress all-zero entries, but
186                  now we return all aranges entries so we show
187                  the entire content.  March 31, 2010. */
188 
189                 arange = (Dwarf_Arange)
190                     _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
191                 if (arange == NULL) {
192                     _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
193                     return (DW_DLV_ERROR);
194                 }
195 
196                 arange->ar_segment_selector = segment_selector;
197                 arange->ar_segment_selector_size = segment_size;
198                 arange->ar_address = range_address;
199                 arange->ar_length = range_length;
200                 arange->ar_info_offset = info_offset;
201                 arange->ar_dbg = dbg;
202                 arange_count++;
203 
204                 curr_chain = (Dwarf_Chain)
205                     _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
206                 if (curr_chain == NULL) {
207                     _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
208                     return (DW_DLV_ERROR);
209                 }
210 
211                 curr_chain->ch_item = arange;
212                 if (head_chain == NULL)
213                     head_chain = prev_chain = curr_chain;
214                 else {
215                     prev_chain->ch_next = curr_chain;
216                     prev_chain = curr_chain;
217                 }
218             }
219             /* The current set of ranges is terminated by
220                range_address 0 and range_length 0, but that
221                does not necessarily terminate the ranges for this CU!
222                There can be multiple sets in that DWARF
223                does not explicitly forbid multiple sets.
224                DWARF2,3,4 section 7.20
225                We stop short to avoid overrun of the end of the CU.
226                */
227 
228         } while (arange_ptr_past_end >= (arange_ptr + range_entry_size));
229 
230         /* A compiler could emit some padding bytes here. dwarf2/3
231            (dwarf4 sec 7.20) does not clearly make extra padding
232            bytes illegal. */
233         if (arange_ptr_past_end < arange_ptr) {
234             char buf[200];
235             Dwarf_Unsigned pad_count = arange_ptr - arange_ptr_past_end;
236             Dwarf_Unsigned offset = arange_ptr - arange_ptr_start;
237             snprintf(buf,sizeof(buf),"DW_DLE_ARANGE_LENGTH_BAD."
238                 " 0x%" DW_PR_DUx
239                 " pad bytes at offset 0x%" DW_PR_DUx
240                 " in .debug_aranges",
241                 pad_count, offset);
242             dwarf_insert_harmless_error(dbg,buf);
243         }
244         /* For most compilers, arange_ptr == arange_ptr_past_end at
245            this point. But not if there were padding bytes */
246         arange_ptr = arange_ptr_past_end;
247     } while (arange_ptr <
248         dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size);
249 
250     if (arange_ptr !=
251         dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) {
252         _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
253         return (DW_DLV_ERROR);
254     }
255     *chain_out = head_chain;
256     *chain_count_out = arange_count;
257     return DW_DLV_OK;
258 }
259 
260 /*
261     This function returns the count of the number of
262     aranges in the .debug_aranges section.  It sets
263     aranges to point to a block of Dwarf_Arange's
264     describing the arange's.  It returns DW_DLV_ERROR
265     on error.
266 
267     Must be identical in most aspects to
268         dwarf_get_aranges_addr_offsets!
269 
270 */
271 int
272 dwarf_get_aranges(Dwarf_Debug dbg,
273     Dwarf_Arange ** aranges,
274     Dwarf_Signed * returned_count, Dwarf_Error * error)
275 {
276     /* Count of total number of aranges. */
277     Dwarf_Signed arange_count = 0;
278 
279     Dwarf_Arange *arange_block = 0;
280 
281     /* Used to chain Dwarf_Aranges structs. */
282     Dwarf_Chain curr_chain = NULL;
283     Dwarf_Chain prev_chain = NULL;
284     Dwarf_Chain head_chain = NULL;
285     Dwarf_Unsigned i = 0;
286     int res = DW_DLV_ERROR;
287 
288     /* ***** BEGIN CODE ***** */
289 
290     if (dbg == NULL) {
291         _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
292         return (DW_DLV_ERROR);
293     }
294 
295     res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error);
296     if (res != DW_DLV_OK) {
297         return res;
298     }
299 
300     res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
301     if(res != DW_DLV_OK) {
302         return res;
303     }
304 
305     arange_block = (Dwarf_Arange *)
306         _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
307     if (arange_block == NULL) {
308         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
309         return (DW_DLV_ERROR);
310     }
311 
312     curr_chain = head_chain;
313     for (i = 0; i < arange_count; i++) {
314         *(arange_block + i) = curr_chain->ch_item;
315         prev_chain = curr_chain;
316         curr_chain = curr_chain->ch_next;
317         dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
318     }
319 
320     *aranges = arange_block;
321     *returned_count = (arange_count);
322     return DW_DLV_OK;
323 }
324 
325 /*
326     This function returns DW_DLV_OK if it succeeds
327     and DW_DLV_ERR or DW_DLV_OK otherwise.
328     count is set to the number of addresses in the
329     .debug_aranges section.
330     For each address, the corresponding element in
331     an array is set to the address itself(aranges) and
332     the section offset (offsets).
333     Must be identical in most aspects to
334         dwarf_get_aranges!
335 */
336 int
337 _dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
338     Dwarf_Addr ** addrs,
339     Dwarf_Off ** offsets,
340     Dwarf_Signed * count,
341     Dwarf_Error * error)
342 {
343     Dwarf_Unsigned i = 0;
344 
345     /* Used to chain Dwarf_Aranges structs. */
346     Dwarf_Chain curr_chain = NULL;
347     Dwarf_Chain prev_chain = NULL;
348     Dwarf_Chain head_chain = NULL;
349 
350     Dwarf_Signed arange_count = 0;
351     Dwarf_Addr *arange_addrs = 0;
352     Dwarf_Off *arange_offsets = 0;
353 
354     int res = DW_DLV_ERROR;
355 
356     /* ***** BEGIN CODE ***** */
357 
358     if (error != NULL)
359         *error = NULL;
360 
361     if (dbg == NULL) {
362         _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
363         return (DW_DLV_ERROR);
364     }
365 
366     res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error);
367     if (res != DW_DLV_OK) {
368         return res;
369     }
370 
371     res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
372     if(res != DW_DLV_OK) {
373         return res;
374     }
375 
376     arange_addrs = (Dwarf_Addr *)
377         _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
378     if (arange_addrs == NULL) {
379         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
380         return (DW_DLV_ERROR);
381     }
382     arange_offsets = (Dwarf_Off *)
383         _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
384     if (arange_offsets == NULL) {
385         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
386         return (DW_DLV_ERROR);
387     }
388 
389     curr_chain = head_chain;
390     for (i = 0; i < arange_count; i++) {
391         Dwarf_Arange ar = curr_chain->ch_item;
392 
393         arange_addrs[i] = ar->ar_address;
394         arange_offsets[i] = ar->ar_info_offset;
395         prev_chain = curr_chain;
396         curr_chain = curr_chain->ch_next;
397         dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
398         dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
399     }
400     *count = arange_count;
401     *offsets = arange_offsets;
402     *addrs = arange_addrs;
403     return (DW_DLV_OK);
404 }
405 
406 
407 /*
408     This function takes a pointer to a block
409     of Dwarf_Arange's, and a count of the
410     length of the block.  It checks if the
411     given address is within the range of an
412     address range in the block.  If yes, it
413     returns the appropriate Dwarf_Arange.
414     Otherwise, it returns DW_DLV_ERROR.
415 */
416 int
417 dwarf_get_arange(Dwarf_Arange * aranges,
418     Dwarf_Unsigned arange_count,
419     Dwarf_Addr address,
420     Dwarf_Arange * returned_arange, Dwarf_Error * error)
421 {
422     Dwarf_Arange curr_arange = 0;
423     Dwarf_Unsigned i = 0;
424 
425     if (aranges == NULL) {
426         _dwarf_error(NULL, error, DW_DLE_ARANGES_NULL);
427         return (DW_DLV_ERROR);
428     }
429     for (i = 0; i < arange_count; i++) {
430         curr_arange = *(aranges + i);
431         if (address >= curr_arange->ar_address &&
432             address <
433             curr_arange->ar_address + curr_arange->ar_length) {
434             *returned_arange = curr_arange;
435             return (DW_DLV_OK);
436         }
437     }
438 
439     return (DW_DLV_NO_ENTRY);
440 }
441 
442 
443 /*
444     This function takes an Dwarf_Arange,
445     and returns the offset of the first
446     die in the compilation-unit that the
447     arange belongs to.  Returns DW_DLV_ERROR
448     on error.
449 */
450 int
451 dwarf_get_cu_die_offset(Dwarf_Arange arange,
452     Dwarf_Off * returned_offset,
453     Dwarf_Error * error)
454 {
455     Dwarf_Debug dbg = 0;
456     Dwarf_Off offset = 0;
457 
458     if (arange == NULL) {
459         _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
460         return (DW_DLV_ERROR);
461     }
462     dbg = arange->ar_dbg;
463     offset = arange->ar_info_offset;
464     if (!dbg->de_debug_info.dss_data) {
465         int res = _dwarf_load_debug_info(dbg, error);
466 
467         if (res != DW_DLV_OK) {
468             return res;
469         }
470     }
471     *returned_offset = offset + _dwarf_length_of_cu_header(dbg, offset);
472     return DW_DLV_OK;
473 }
474 
475 /*
476     This function takes an Dwarf_Arange,
477     and returns the offset of the CU header
478     in the compilation-unit that the
479     arange belongs to.  Returns DW_DLV_ERROR
480     on error.
481     Ensures .debug_info loaded so
482     the cu_offset is meaningful.
483 */
484 int
485 dwarf_get_arange_cu_header_offset(Dwarf_Arange arange,
486     Dwarf_Off * cu_header_offset_returned,
487     Dwarf_Error * error)
488 {
489     Dwarf_Debug dbg = 0;
490     if (arange == NULL) {
491         _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
492         return (DW_DLV_ERROR);
493     }
494     dbg = arange->ar_dbg;
495     /* Like dwarf_get_arange_info this ensures debug_info loaded:
496        the cu_header is in debug_info and will be used else
497        we would not call dwarf_get_arange_cu_header_offset. */
498     if (!dbg->de_debug_info.dss_data) {
499         int res = _dwarf_load_debug_info(dbg, error);
500         if (res != DW_DLV_OK) {
501                 return res;
502         }
503     }
504     *cu_header_offset_returned = arange->ar_info_offset;
505     return DW_DLV_OK;
506 }
507 
508 
509 
510 
511 /*
512     This function takes a Dwarf_Arange, and returns
513     true if it is not NULL.  It also stores the start
514     address of the range in *start, the length of the
515     range in *length, and the offset of the first die
516     in the compilation-unit in *cu_die_offset.  It
517     returns false on error.
518     If cu_die_offset returned ensures .debug_info loaded so
519     the cu_die_offset is meaningful.
520 */
521 int
522 dwarf_get_arange_info(Dwarf_Arange arange,
523     Dwarf_Addr * start,
524     Dwarf_Unsigned * length,
525     Dwarf_Off * cu_die_offset, Dwarf_Error * error)
526 {
527     if (arange == NULL) {
528         _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
529         return (DW_DLV_ERROR);
530     }
531 
532     if (start != NULL)
533         *start = arange->ar_address;
534     if (length != NULL)
535         *length = arange->ar_length;
536     if (cu_die_offset != NULL) {
537         Dwarf_Debug dbg = arange->ar_dbg;
538         Dwarf_Off offset = arange->ar_info_offset;
539 
540         if (!dbg->de_debug_info.dss_data) {
541             int res = _dwarf_load_debug_info(dbg, error);
542             if (res != DW_DLV_OK) {
543                 return res;
544             }
545         }
546         *cu_die_offset =
547             offset + _dwarf_length_of_cu_header(dbg, offset);
548     }
549     return (DW_DLV_OK);
550 }
551 
552 
553 /* New for DWARF4, entries may have segment information.
554    *segment is only meaningful if *segment_entry_size is non-zero. */
555 int
556 dwarf_get_arange_info_b(Dwarf_Arange arange,
557     Dwarf_Unsigned*  segment,
558     Dwarf_Unsigned*  segment_entry_size,
559     Dwarf_Addr    * start,
560     Dwarf_Unsigned* length,
561     Dwarf_Off     * cu_die_offset,
562     Dwarf_Error   * error)
563 {
564     if (arange == NULL) {
565         _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
566         return (DW_DLV_ERROR);
567     }
568 
569     if(segment != NULL) {
570        *segment = arange->ar_segment_selector;
571     }
572     if(segment_entry_size != NULL) {
573        *segment_entry_size = arange->ar_segment_selector_size;
574     }
575     if (start != NULL)
576         *start = arange->ar_address;
577     if (length != NULL)
578         *length = arange->ar_length;
579     if (cu_die_offset != NULL) {
580         Dwarf_Debug dbg = arange->ar_dbg;
581         Dwarf_Off offset = arange->ar_info_offset;
582 
583         if (!dbg->de_debug_info.dss_data) {
584             int res = _dwarf_load_debug_info(dbg, error);
585             if (res != DW_DLV_OK) {
586                 return res;
587             }
588         }
589         *cu_die_offset =
590             offset + _dwarf_length_of_cu_header(dbg, offset);
591     }
592     return (DW_DLV_OK);
593 }
594