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 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     default:
170       // Next encodings are not yet supported:
171       // DW_RLE_base_addressx, DW_RLE_startx_endx, DW_RLE_startx_length.
172       lldbassert(0 && "unknown range list entry encoding");
173       error = true;
174     }
175   }
176 
177   return false;
178 }
179 
180 bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu,
181                                     dw_offset_t debug_ranges_offset,
182                                     DWARFRangeList &range_list) const {
183   range_list.Clear();
184   dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset;
185   auto pos = m_range_map.find(debug_ranges_address);
186   if (pos != m_range_map.end()) {
187     dw_addr_t BaseAddr = cu->GetBaseAddress();
188     for (const RngListEntry &E : pos->second) {
189       switch (E.encoding) {
190       case DW_RLE_start_length:
191         range_list.Append(DWARFRangeList::Entry(E.value0, E.value1));
192         break;
193       case DW_RLE_base_address:
194         BaseAddr = E.value0;
195         break;
196       case DW_RLE_start_end:
197         range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0));
198         break;
199       case DW_RLE_offset_pair:
200         range_list.Append(
201             DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0));
202         break;
203       default:
204         llvm_unreachable("unexpected encoding");
205       }
206     }
207     return true;
208   }
209   return false;
210 }
211 
212 void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) {
213   const DWARFDataExtractor &data = dwarf2Data->get_debug_rnglists_data();
214   lldb::offset_t offset = 0;
215 
216   uint64_t length = data.GetU32(&offset);
217   bool isDwarf64 = false;
218   if (length == 0xffffffff) {
219     length = data.GetU64(&offset);
220     isDwarf64 = true;
221   }
222   lldb::offset_t end = offset + length;
223 
224   // Check version.
225   if (data.GetU16(&offset) < 5)
226     return;
227 
228   uint8_t addrSize = data.GetU8(&offset);
229 
230   // We do not support non-zero segment selector size.
231   if (data.GetU8(&offset) != 0) {
232     lldbassert(0 && "not implemented");
233     return;
234   }
235 
236   uint32_t offsetsAmount = data.GetU32(&offset);
237   for (uint32_t i = 0; i < offsetsAmount; ++i)
238     Offsets.push_back(data.GetPointer(&offset));
239 
240   lldb::offset_t listOffset = offset;
241   std::vector<RngListEntry> rangeList;
242   while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) {
243     m_range_map[listOffset] = rangeList;
244     listOffset = offset;
245   }
246 }
247