1 /* Enumerate the PC ranges covered by a DIE.
2 Copyright (C) 2005, 2007, 2009, 2018 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
8 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
18 or both in parallel, as here.
20 elfutils is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
37 /* Read up begin/end pair and increment read pointer.
38 - If it's normal range record, set up `*beginp' and `*endp' and return 0.
39 - If it's a default location, set `*beginp' (0), `*endp' (-1) and return 0.
40 - If it's base address selection record, set up `*basep' and return 1.
41 - If it's end of rangelist, don't set anything and return 2
42 - If an error occurs, don't set anything and return -1. */
44 __libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
45 const unsigned char **addrp,
46 const unsigned char *addrend,
48 Dwarf_Addr *beginp, Dwarf_Addr *endp,
52 if (sec_index == IDX_debug_loc
54 && cu->unit_type == DW_UT_split_compile)
56 /* GNU DebugFission. */
57 const unsigned char *addr = *addrp;
58 if (addrend - addr < 1)
61 const char code = *addr++;
62 uint64_t begin = 0, end = 0, base = *basep, addr_idx;
65 case DW_LLE_GNU_end_of_list_entry:
69 case DW_LLE_GNU_base_address_selection_entry:
70 if (addrend - addr < 1)
72 get_uleb128 (addr_idx, addr, addrend);
73 if (__libdw_addrx (cu, addr_idx, &base) != 0)
79 case DW_LLE_GNU_start_end_entry:
80 if (addrend - addr < 1)
82 get_uleb128 (addr_idx, addr, addrend);
83 if (__libdw_addrx (cu, addr_idx, &begin) != 0)
85 if (addrend - addr < 1)
87 get_uleb128 (addr_idx, addr, addrend);
88 if (__libdw_addrx (cu, addr_idx, &end) != 0)
96 case DW_LLE_GNU_start_length_entry:
97 if (addrend - addr < 1)
99 get_uleb128 (addr_idx, addr, addrend);
100 if (__libdw_addrx (cu, addr_idx, &begin) != 0)
102 if (addrend - addr < 4)
104 end = read_4ubyte_unaligned_inc (dbg, addr);
115 else if (sec_index == IDX_debug_ranges || sec_index == IDX_debug_loc)
117 Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
118 : (Elf64_Addr) (Elf32_Addr) -1);
122 const unsigned char *addr = *addrp;
123 if (addrend - addr < width * 2)
126 __libdw_seterrno (DWARF_E_INVALID_DWARF);
130 bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
132 bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address,
136 /* Unrelocated escape for begin means base address selection. */
137 if (begin == escape && !begin_relocated)
139 if (unlikely (end == escape))
146 /* Unrelocated pair of zeroes means end of range list. */
147 if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
150 /* Don't check for begin_relocated == end_relocated. Serve the data
151 to the client even though it may be buggy. */
152 *beginp = begin + *basep;
153 *endp = end + *basep;
157 else if (sec_index == IDX_debug_rnglists)
159 const unsigned char *addr = *addrp;
160 if (addrend - addr < 1)
163 const char code = *addr++;
164 uint64_t begin = 0, end = 0, base = *basep, addr_idx;
167 case DW_RLE_end_of_list:
171 case DW_RLE_base_addressx:
172 if (addrend - addr < 1)
174 get_uleb128 (addr_idx, addr, addrend);
175 if (__libdw_addrx (cu, addr_idx, &base) != 0)
182 case DW_RLE_startx_endx:
183 if (addrend - addr < 1)
185 get_uleb128 (addr_idx, addr, addrend);
186 if (__libdw_addrx (cu, addr_idx, &begin) != 0)
188 if (addrend - addr < 1)
190 get_uleb128 (addr_idx, addr, addrend);
191 if (__libdw_addrx (cu, addr_idx, &end) != 0)
199 case DW_RLE_startx_length:
200 if (addrend - addr < 1)
202 get_uleb128 (addr_idx, addr, addrend);
203 if (__libdw_addrx (cu, addr_idx, &begin) != 0)
205 if (addrend - addr < 1)
207 get_uleb128 (end, addr, addrend);
214 case DW_RLE_offset_pair:
215 if (addrend - addr < 1)
217 get_uleb128 (begin, addr, addrend);
218 if (addrend - addr < 1)
220 get_uleb128 (end, addr, addrend);
222 *beginp = begin + base;
227 case DW_RLE_base_address:
228 if (addrend - addr < width)
230 __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
236 case DW_RLE_start_end:
237 if (addrend - addr < 2 * width)
239 __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
240 __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
247 case DW_RLE_start_length:
248 if (addrend - addr < width)
250 __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
251 if (addrend - addr < 1)
253 get_uleb128 (end, addr, addrend);
264 else if (sec_index == IDX_debug_loclists)
266 const unsigned char *addr = *addrp;
267 if (addrend - addr < 1)
270 const char code = *addr++;
271 uint64_t begin = 0, end = 0, base = *basep, addr_idx;
274 case DW_LLE_end_of_list:
278 case DW_LLE_base_addressx:
279 if (addrend - addr < 1)
281 get_uleb128 (addr_idx, addr, addrend);
282 if (__libdw_addrx (cu, addr_idx, &base) != 0)
289 case DW_LLE_startx_endx:
290 if (addrend - addr < 1)
292 get_uleb128 (addr_idx, addr, addrend);
293 if (__libdw_addrx (cu, addr_idx, &begin) != 0)
295 if (addrend - addr < 1)
297 get_uleb128 (addr_idx, addr, addrend);
298 if (__libdw_addrx (cu, addr_idx, &end) != 0)
306 case DW_LLE_startx_length:
307 if (addrend - addr < 1)
309 get_uleb128 (addr_idx, addr, addrend);
310 if (__libdw_addrx (cu, addr_idx, &begin) != 0)
312 if (addrend - addr < 1)
314 get_uleb128 (end, addr, addrend);
321 case DW_LLE_offset_pair:
322 if (addrend - addr < 1)
324 get_uleb128 (begin, addr, addrend);
325 if (addrend - addr < 1)
327 get_uleb128 (end, addr, addrend);
329 *beginp = begin + base;
334 case DW_LLE_default_location:
336 *endp = (Dwarf_Addr) -1;
340 case DW_LLE_base_address:
341 if (addrend - addr < width)
343 __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
349 case DW_LLE_start_end:
350 if (addrend - addr < 2 * width)
352 __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
353 __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
360 case DW_LLE_start_length:
361 if (addrend - addr < width)
363 __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
364 if (addrend - addr < 1)
366 get_uleb128 (end, addr, addrend);
379 __libdw_seterrno (DWARF_E_INVALID_DWARF);
385 initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
387 size_t secidx = (attr->cu->version < 5
388 ? IDX_debug_ranges : IDX_debug_rnglists);
390 Dwarf_Word start_offset;
391 if (attr->form == DW_FORM_rnglistx)
394 Dwarf_CU *cu = attr->cu;
395 const unsigned char *datap = attr->valp;
396 const unsigned char *endp = cu->endp;
399 __libdw_seterrno (DWARF_E_INVALID_DWARF);
402 get_uleb128 (idx, datap, endp);
404 Elf_Data *data = cu->dbg->sectiondata[secidx];
405 if (data == NULL && cu->unit_type == DW_UT_split_compile)
407 cu = __libdw_find_split_unit (cu);
409 data = cu->dbg->sectiondata[secidx];
414 __libdw_seterrno (secidx == IDX_debug_ranges
415 ? DWARF_E_NO_DEBUG_RANGES
416 : DWARF_E_NO_DEBUG_RNGLISTS);
420 Dwarf_Off range_base_off = __libdw_cu_ranges_base (cu);
422 /* The section should at least contain room for one offset. */
423 size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
424 size_t offset_size = cu->offset_size;
425 if (offset_size > sec_size)
428 __libdw_seterrno (DWARF_E_INVALID_OFFSET);
432 /* And the base offset should be at least inside the section. */
433 if (range_base_off > (sec_size - offset_size))
436 size_t max_idx = (sec_size - offset_size - range_base_off) / offset_size;
440 datap = (cu->dbg->sectiondata[secidx]->d_buf
441 + range_base_off + (idx * offset_size));
442 if (offset_size == 4)
443 start_offset = read_4ubyte_unaligned (cu->dbg, datap);
445 start_offset = read_8ubyte_unaligned (cu->dbg, datap);
447 start_offset += range_base_off;
451 if (__libdw_formptr (attr, secidx,
452 (secidx == IDX_debug_ranges
453 ? DWARF_E_NO_DEBUG_RANGES
454 : DWARF_E_NO_DEBUG_RNGLISTS),
455 NULL, &start_offset) == NULL)
459 *offset = start_offset;
464 dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
465 Dwarf_Addr *startp, Dwarf_Addr *endp)
471 /* Usually there is a single contiguous range. */
472 && INTUSE(dwarf_highpc) (die, endp) == 0
473 && INTUSE(dwarf_lowpc) (die, startp) == 0)
474 /* A offset into .debug_ranges will never be 1, it must be at least a
475 multiple of 4. So we can return 1 as a special case value to mark
476 there are no ranges to look for on the next call. */
482 /* We have to look for a noncontiguous range. */
483 Dwarf_CU *cu = die->cu;
486 __libdw_seterrno (DWARF_E_INVALID_DWARF);
490 size_t secidx = (cu->version < 5 ? IDX_debug_ranges : IDX_debug_rnglists);
491 const Elf_Data *d = cu->dbg->sectiondata[secidx];
492 if (d == NULL && cu->unit_type == DW_UT_split_compile)
494 Dwarf_CU *skel = __libdw_find_split_unit (cu);
498 d = cu->dbg->sectiondata[secidx];
502 const unsigned char *readp;
503 const unsigned char *readendp;
506 Dwarf_Attribute attr_mem;
507 Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
509 /* Note that above we use dwarf_attr, not dwarf_attr_integrate.
510 The only case where the ranges can come from another DIE
511 attribute are the split CU case. In that case we also have a
512 different CU to check against. But that is already set up
513 above using __libdw_find_split_unit. */
516 && die->cu->unit_type == DW_UT_split_compile)
517 attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_ranges, &attr_mem);
519 /* No PC attributes in this DIE at all, so an empty range list. */
522 *basep = __libdw_cu_base_address (attr->cu);
523 if (*basep == (Dwarf_Addr) -1)
526 if (initial_offset (attr, &offset) != 0)
531 if (__libdw_offset_in_section (cu->dbg,
536 readp = d->d_buf + offset;
537 readendp = d->d_buf + d->d_size;
543 switch (__libdw_read_begin_end_pair_inc (cu, secidx,
546 &begin, &end, basep))
560 return readp - (unsigned char *) d->d_buf;
562 INTDEF (dwarf_ranges)