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