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