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