1 //===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "DWARFDebugRanges.h"
11 #include "DWARFUnit.h"
12 #include "SymbolFileDWARF.h"
13 #include "lldb/Utility/Stream.h"
14 #include <assert.h>
15
16 using namespace lldb_private;
17 using namespace std;
18
GetBaseAddressMarker(uint32_t addr_size)19 static dw_addr_t GetBaseAddressMarker(uint32_t addr_size) {
20 switch(addr_size) {
21 case 2:
22 return 0xffff;
23 case 4:
24 return 0xffffffff;
25 case 8:
26 return 0xffffffffffffffff;
27 }
28 llvm_unreachable("GetBaseAddressMarker unsupported address size.");
29 }
30
DWARFDebugRanges()31 DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
32
Extract(SymbolFileDWARF * dwarf2Data)33 void DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data) {
34 DWARFRangeList range_list;
35 lldb::offset_t offset = 0;
36 dw_offset_t debug_ranges_offset = offset;
37 while (Extract(dwarf2Data, &offset, range_list)) {
38 range_list.Sort();
39 m_range_map[debug_ranges_offset] = range_list;
40 debug_ranges_offset = offset;
41 }
42 }
43
Extract(SymbolFileDWARF * dwarf2Data,lldb::offset_t * offset_ptr,DWARFRangeList & range_list)44 bool DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data,
45 lldb::offset_t *offset_ptr,
46 DWARFRangeList &range_list) {
47 range_list.Clear();
48
49 lldb::offset_t range_offset = *offset_ptr;
50 const DWARFDataExtractor &debug_ranges_data =
51 dwarf2Data->get_debug_ranges_data();
52 uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
53 dw_addr_t base_addr = 0;
54 dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size);
55
56 while (
57 debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
58 dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
59 dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
60
61 if (!begin && !end) {
62 // End of range list
63 break;
64 }
65
66 if (begin == base_addr_marker) {
67 base_addr = end;
68 continue;
69 }
70
71 // Filter out empty ranges
72 if (begin < end)
73 range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin));
74 }
75
76 // Make sure we consumed at least something
77 return range_offset != *offset_ptr;
78 }
79
Dump(Stream & s,const DWARFDataExtractor & debug_ranges_data,lldb::offset_t * offset_ptr,dw_addr_t cu_base_addr)80 void DWARFDebugRanges::Dump(Stream &s,
81 const DWARFDataExtractor &debug_ranges_data,
82 lldb::offset_t *offset_ptr,
83 dw_addr_t cu_base_addr) {
84 uint32_t addr_size = s.GetAddressByteSize();
85
86 dw_addr_t base_addr = cu_base_addr;
87 while (
88 debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
89 dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
90 dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
91 // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of
92 // ones
93 if (begin == 0xFFFFFFFFull && addr_size == 4)
94 begin = LLDB_INVALID_ADDRESS;
95
96 s.Indent();
97 if (begin == 0 && end == 0) {
98 s.PutCString(" End");
99 break;
100 } else if (begin == LLDB_INVALID_ADDRESS) {
101 // A base address selection entry
102 base_addr = end;
103 s.Address(base_addr, sizeof(dw_addr_t), " Base address = ");
104 } else {
105 // Convert from offset to an address
106 dw_addr_t begin_addr = begin + base_addr;
107 dw_addr_t end_addr = end + base_addr;
108
109 s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), NULL);
110 }
111 }
112 }
113
FindRanges(const DWARFUnit * cu,dw_offset_t debug_ranges_offset,DWARFRangeList & range_list) const114 bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu,
115 dw_offset_t debug_ranges_offset,
116 DWARFRangeList &range_list) const {
117 dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
118 range_map_const_iterator pos = m_range_map.find(debug_ranges_address);
119 if (pos != m_range_map.end()) {
120 range_list = pos->second;
121
122 // All DW_AT_ranges are relative to the base address of the compile
123 // unit. We add the compile unit base address to make sure all the
124 // addresses are properly fixed up.
125 range_list.Slide(cu->GetBaseAddress());
126 return true;
127 }
128 return false;
129 }
130
GetOffset(size_t Index) const131 uint64_t DWARFDebugRanges::GetOffset(size_t Index) const {
132 lldbassert(false && "DW_FORM_rnglistx is not present before DWARF5");
133 return 0;
134 }
135
ExtractRangeList(const DWARFDataExtractor & data,uint8_t addrSize,lldb::offset_t * offset_ptr,std::vector<RngListEntry> & rangeList)136 bool DWARFDebugRngLists::ExtractRangeList(
137 const DWARFDataExtractor &data, uint8_t addrSize,
138 lldb::offset_t *offset_ptr, std::vector<RngListEntry> &rangeList) {
139 rangeList.clear();
140
141 bool error = false;
142 while (!error) {
143 switch (data.GetU8(offset_ptr)) {
144 case DW_RLE_end_of_list:
145 return true;
146
147 case DW_RLE_start_length: {
148 dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize);
149 dw_addr_t len = data.GetULEB128(offset_ptr);
150 rangeList.push_back({DW_RLE_start_length, begin, len});
151 break;
152 }
153
154 case DW_RLE_start_end: {
155 dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize);
156 dw_addr_t end = data.GetMaxU64(offset_ptr, addrSize);
157 rangeList.push_back({DW_RLE_start_end, begin, end});
158 break;
159 }
160
161 case DW_RLE_base_address: {
162 dw_addr_t base = data.GetMaxU64(offset_ptr, addrSize);
163 rangeList.push_back({DW_RLE_base_address, base, 0});
164 break;
165 }
166
167 case DW_RLE_offset_pair: {
168 dw_addr_t begin = data.GetULEB128(offset_ptr);
169 dw_addr_t end = data.GetULEB128(offset_ptr);
170 rangeList.push_back({DW_RLE_offset_pair, begin, end});
171 break;
172 }
173
174 case DW_RLE_base_addressx: {
175 dw_addr_t base = data.GetULEB128(offset_ptr);
176 rangeList.push_back({DW_RLE_base_addressx, base, 0});
177 break;
178 }
179
180 case DW_RLE_startx_endx: {
181 dw_addr_t start = data.GetULEB128(offset_ptr);
182 dw_addr_t end = data.GetULEB128(offset_ptr);
183 rangeList.push_back({DW_RLE_startx_endx, start, end});
184 break;
185 }
186
187 case DW_RLE_startx_length: {
188 dw_addr_t start = data.GetULEB128(offset_ptr);
189 dw_addr_t length = data.GetULEB128(offset_ptr);
190 rangeList.push_back({DW_RLE_startx_length, start, length});
191 break;
192 }
193
194 default:
195 lldbassert(0 && "unknown range list entry encoding");
196 error = true;
197 }
198 }
199
200 return false;
201 }
202
ReadAddressFromDebugAddrSection(const DWARFUnit * cu,uint32_t index)203 static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu,
204 uint32_t index) {
205 uint32_t index_size = cu->GetAddressByteSize();
206 dw_offset_t addr_base = cu->GetAddrBase();
207 lldb::offset_t offset = addr_base + index * index_size;
208 return cu->GetSymbolFileDWARF()->get_debug_addr_data().GetMaxU64(&offset,
209 index_size);
210 }
211
FindRanges(const DWARFUnit * cu,dw_offset_t debug_ranges_offset,DWARFRangeList & range_list) const212 bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu,
213 dw_offset_t debug_ranges_offset,
214 DWARFRangeList &range_list) const {
215 range_list.Clear();
216 dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
217 auto pos = m_range_map.find(debug_ranges_address);
218 if (pos != m_range_map.end()) {
219 dw_addr_t BaseAddr = cu->GetBaseAddress();
220 for (const RngListEntry &E : pos->second) {
221 switch (E.encoding) {
222 case DW_RLE_start_length:
223 range_list.Append(DWARFRangeList::Entry(E.value0, E.value1));
224 break;
225 case DW_RLE_base_address:
226 BaseAddr = E.value0;
227 break;
228 case DW_RLE_start_end:
229 range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0));
230 break;
231 case DW_RLE_offset_pair:
232 range_list.Append(
233 DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0));
234 break;
235 case DW_RLE_base_addressx: {
236 BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0);
237 break;
238 }
239 case DW_RLE_startx_endx: {
240 dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0);
241 dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1);
242 range_list.Append(DWARFRangeList::Entry(start, end - start));
243 break;
244 }
245 case DW_RLE_startx_length: {
246 dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0);
247 range_list.Append(DWARFRangeList::Entry(start, E.value1));
248 break;
249 }
250 default:
251 llvm_unreachable("unexpected encoding");
252 }
253 }
254 return true;
255 }
256 return false;
257 }
258
Extract(SymbolFileDWARF * dwarf2Data)259 void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) {
260 const DWARFDataExtractor &data = dwarf2Data->get_debug_rnglists_data();
261 lldb::offset_t offset = 0;
262
263 uint64_t length = data.GetU32(&offset);
264 bool isDwarf64 = (length == 0xffffffff);
265 if (isDwarf64)
266 length = data.GetU64(&offset);
267 lldb::offset_t end = offset + length;
268
269 // Check version.
270 if (data.GetU16(&offset) < 5)
271 return;
272
273 uint8_t addrSize = data.GetU8(&offset);
274
275 // We do not support non-zero segment selector size.
276 if (data.GetU8(&offset) != 0) {
277 lldbassert(0 && "not implemented");
278 return;
279 }
280
281 uint32_t offsetsAmount = data.GetU32(&offset);
282 for (uint32_t i = 0; i < offsetsAmount; ++i)
283 Offsets.push_back(data.GetMaxU64(&offset, isDwarf64 ? 8 : 4));
284
285 lldb::offset_t listOffset = offset;
286 std::vector<RngListEntry> rangeList;
287 while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) {
288 m_range_map[listOffset] = rangeList;
289 listOffset = offset;
290 }
291 }
292
GetOffset(size_t Index) const293 uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const {
294 return Offsets[Index];
295 }
296