]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / SymbolFile / DWARF / DWARFDebugRanges.cpp
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
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
31 DWARFDebugRanges::DWARFDebugRanges() : m_range_map() {}
32
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
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
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
114 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
131 uint64_t DWARFDebugRanges::GetOffset(size_t Index) const {
132   lldbassert(false && "DW_FORM_rnglistx is not present before DWARF5");
133   return 0;
134 }
135
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
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
212 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
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
293 uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const {
294   return Offsets[Index];
295 }