Branch data Line data Source code
1 : : /* Enumerate the PC ranges covered by a DIE.
2 : : Copyright (C) 2005, 2007, 2009 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
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
11 : :
12 : : or
13 : :
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
17 : :
18 : : or both in parallel, as here.
19 : :
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.
24 : :
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/>. */
28 : :
29 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include "libdwP.h"
34 : : #include <dwarf.h>
35 : : #include <assert.h>
36 : :
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 base address selection record, set up `*basep' and return 1.
40 : : - If it's end of rangelist, don't set anything and return 2
41 : : - If an error occurs, don't set anything and return -1. */
42 : : internal_function int
43 : 0 : __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
44 : : unsigned char **addrp, int width,
45 : : Dwarf_Addr *beginp, Dwarf_Addr *endp,
46 : : Dwarf_Addr *basep)
47 : : {
48 : 0 : Dwarf_Addr escape = (width == 8 ? (Elf64_Addr) -1
49 [ # # ]: 0 : : (Elf64_Addr) (Elf32_Addr) -1);
50 : : Dwarf_Addr begin;
51 : : Dwarf_Addr end;
52 : :
53 : 0 : unsigned char *addr = *addrp;
54 [ # # ][ # # ]: 0 : bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address, begin);
[ # # ][ # # ]
[ # # ][ # # ]
55 [ # # ][ # # ]: 0 : bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address, end);
[ # # ][ # # ]
[ # # ][ # # ]
56 : 0 : *addrp = addr;
57 : :
58 : : /* Unrelocated escape for begin means base address selection. */
59 [ # # ]: 0 : if (begin == escape && !begin_relocated)
60 : : {
61 [ # # ]: 0 : if (unlikely (end == escape))
62 : : {
63 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
64 : : return -1;
65 : : }
66 : :
67 [ # # ]: 0 : if (basep != NULL)
68 : 0 : *basep = end;
69 : : return 1;
70 : : }
71 : :
72 : : /* Unrelocated pair of zeroes means end of range list. */
73 [ # # ][ # # ]: 0 : if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
74 : : return 2;
75 : :
76 : : /* Don't check for begin_relocated == end_relocated. Serve the data
77 : : to the client even though it may be buggy. */
78 : 0 : *beginp = begin;
79 : 0 : *endp = end;
80 : :
81 : : return 0;
82 : : }
83 : :
84 : : ptrdiff_t
85 : 46 : dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
86 : : Dwarf_Addr *startp, Dwarf_Addr *endp)
87 : : {
88 [ + - ]: 46 : if (die == NULL)
89 : : return -1;
90 : :
91 [ + - ]: 46 : if (offset == 0
92 : : /* Usually there is a single contiguous range. */
93 [ + + ]: 46 : && INTUSE(dwarf_highpc) (die, endp) == 0
94 [ - + ]: 38 : && INTUSE(dwarf_lowpc) (die, startp) == 0)
95 : : /* A offset into .debug_ranges will never be 1, it must be at least a
96 : : multiple of 4. So we can return 1 as a special case value to mark
97 : : there are no ranges to look for on the next call. */
98 : : return 1;
99 : :
100 [ + - ]: 8 : if (offset == 1)
101 : : return 0;
102 : :
103 : : /* We have to look for a noncontiguous range. */
104 : :
105 : 8 : const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
106 [ - + ]: 8 : if (d == NULL && offset != 0)
107 : : {
108 : 0 : __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
109 : : return -1;
110 : : }
111 : :
112 : : unsigned char *readp;
113 : : unsigned char *readendp;
114 [ + - ]: 8 : if (offset == 0)
115 : : {
116 : : Dwarf_Attribute attr_mem;
117 : 8 : Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
118 : : &attr_mem);
119 [ - + ]: 8 : if (attr == NULL)
120 : : /* No PC attributes in this DIE at all, so an empty range list. */
121 : : return 0;
122 : :
123 : : Dwarf_Word start_offset;
124 [ # # ]: 0 : if ((readp = __libdw_formptr (attr, IDX_debug_ranges,
125 : : DWARF_E_NO_DEBUG_RANGES,
126 : : &readendp, &start_offset)) == NULL)
127 : : return -1;
128 : :
129 : 0 : offset = start_offset;
130 : : assert ((Dwarf_Word) offset == start_offset);
131 : :
132 : : /* Fetch the CU's base address. */
133 [ # # ]: 0 : Dwarf_Die cudie = CUDIE (attr->cu);
134 : :
135 : : /* Find the base address of the compilation unit. It will
136 : : normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
137 : : the base address could be overridden by DW_AT_entry_pc. It's
138 : : been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
139 : : for compilation units with discontinuous ranges. */
140 [ # # ]: 0 : if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
141 [ # # ]: 0 : && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
142 : : DW_AT_entry_pc,
143 : : &attr_mem),
144 : : basep) != 0)
145 : : {
146 [ # # ]: 0 : if (INTUSE(dwarf_errno) () == 0)
147 : : {
148 : : invalid:
149 : 8 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
150 : : }
151 : : return -1;
152 : : }
153 : : }
154 : : else
155 : : {
156 [ # # ]: 0 : if (__libdw_offset_in_section (die->cu->dbg,
157 : : IDX_debug_ranges, offset, 1))
158 : : return -1l;
159 : :
160 : 0 : readp = d->d_buf + offset;
161 : 0 : readendp = d->d_buf + d->d_size;
162 : : }
163 : :
164 : : next:
165 [ # # ]: 0 : if (readendp - readp < die->cu->address_size * 2)
166 : : goto invalid;
167 : :
168 : : Dwarf_Addr begin;
169 : : Dwarf_Addr end;
170 : :
171 [ # # # # ]: 0 : switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
172 : : &readp, die->cu->address_size,
173 : : &begin, &end, basep))
174 : : {
175 : : case 0:
176 : : break;
177 : : case 1:
178 : : goto next;
179 : : case 2:
180 : : return 0;
181 : : default:
182 : : return -1l;
183 : : }
184 : :
185 : : /* We have an address range entry. */
186 : 0 : *startp = *basep + begin;
187 : 0 : *endp = *basep + end;
188 : 46 : return readp - (unsigned char *) d->d_buf;
189 : : }
190 : 0 : INTDEF (dwarf_ranges)
|