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), NULL);
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()->get_debug_addr_data().GetMaxU64(&offset,
208                                                                    index_size);
209 }
210 
211 bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu,
212                                     dw_offset_t debug_ranges_offset,
213                                     DWARFRangeList &range_list) const {
214   range_list.Clear();
215   dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
216   auto pos = m_range_map.find(debug_ranges_address);
217   if (pos != m_range_map.end()) {
218     dw_addr_t BaseAddr = cu->GetBaseAddress();
219     for (const RngListEntry &E : pos->second) {
220       switch (E.encoding) {
221       case DW_RLE_start_length:
222         range_list.Append(DWARFRangeList::Entry(E.value0, E.value1));
223         break;
224       case DW_RLE_base_address:
225         BaseAddr = E.value0;
226         break;
227       case DW_RLE_start_end:
228         range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0));
229         break;
230       case DW_RLE_offset_pair:
231         range_list.Append(
232             DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0));
233         break;
234       case DW_RLE_base_addressx: {
235         BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0);
236         break;
237       }
238       case DW_RLE_startx_endx: {
239         dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0);
240         dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1);
241         range_list.Append(DWARFRangeList::Entry(start, end - start));
242         break;
243       }
244       case DW_RLE_startx_length: {
245         dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0);
246         range_list.Append(DWARFRangeList::Entry(start, E.value1));
247         break;
248       }
249       default:
250         llvm_unreachable("unexpected encoding");
251       }
252     }
253     return true;
254   }
255   return false;
256 }
257 
258 void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) {
259   const DWARFDataExtractor &data = dwarf2Data->get_debug_rnglists_data();
260   lldb::offset_t offset = 0;
261 
262   uint64_t length = data.GetU32(&offset);
263   // FIXME: Handle DWARF64.
264   lldb::offset_t end = offset + length;
265 
266   // Check version.
267   if (data.GetU16(&offset) < 5)
268     return;
269 
270   uint8_t addrSize = data.GetU8(&offset);
271 
272   // We do not support non-zero segment selector size.
273   if (data.GetU8(&offset) != 0) {
274     lldbassert(0 && "not implemented");
275     return;
276   }
277 
278   uint32_t offsetsAmount = data.GetU32(&offset);
279   for (uint32_t i = 0; i < offsetsAmount; ++i)
280     Offsets.push_back(data.GetMaxU64(&offset, 4));
281 
282   lldb::offset_t listOffset = offset;
283   std::vector<RngListEntry> rangeList;
284   while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) {
285     m_range_map[listOffset] = rangeList;
286     listOffset = offset;
287   }
288 }
289 
290 uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const {
291   return Offsets[Index];
292 }
293