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