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 "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 DWARFDebugRanges::~DWARFDebugRanges() {}
33 
34 void DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data) {
35   DWARFRangeList range_list;
36   lldb::offset_t offset = 0;
37   dw_offset_t debug_ranges_offset = offset;
38   while (Extract(dwarf2Data, &offset, range_list)) {
39     range_list.Sort();
40     m_range_map[debug_ranges_offset] = range_list;
41     debug_ranges_offset = offset;
42   }
43 }
44 
45 bool DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data,
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_data =
52       dwarf2Data->get_debug_ranges_data();
53   uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
54   dw_addr_t base_addr = 0;
55   dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size);
56 
57   while (
58       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
59     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
60     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
61 
62     if (!begin && !end) {
63       // End of range list
64       break;
65     }
66 
67     if (begin == base_addr_marker) {
68       base_addr = end;
69       continue;
70     }
71 
72     // Filter out empty ranges
73     if (begin < end)
74       range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin));
75   }
76 
77   // Make sure we consumed at least something
78   return range_offset != *offset_ptr;
79 }
80 
81 void DWARFDebugRanges::Dump(Stream &s,
82                             const DWARFDataExtractor &debug_ranges_data,
83                             lldb::offset_t *offset_ptr,
84                             dw_addr_t cu_base_addr) {
85   uint32_t addr_size = s.GetAddressByteSize();
86 
87   dw_addr_t base_addr = cu_base_addr;
88   while (
89       debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) {
90     dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
91     dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
92     // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of
93     // ones
94     if (begin == 0xFFFFFFFFull && addr_size == 4)
95       begin = LLDB_INVALID_ADDRESS;
96 
97     s.Indent();
98     if (begin == 0 && end == 0) {
99       s.PutCString(" End");
100       break;
101     } else if (begin == LLDB_INVALID_ADDRESS) {
102       // A base address selection entry
103       base_addr = end;
104       s.Address(base_addr, sizeof(dw_addr_t), " Base address = ");
105     } else {
106       // Convert from offset to an address
107       dw_addr_t begin_addr = begin + base_addr;
108       dw_addr_t end_addr = end + base_addr;
109 
110       s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), NULL);
111     }
112   }
113 }
114 
115 bool DWARFDebugRanges::FindRanges(dw_addr_t debug_ranges_base,
116                                   dw_offset_t debug_ranges_offset,
117                                   DWARFRangeList &range_list) const {
118   dw_addr_t debug_ranges_address = debug_ranges_base + debug_ranges_offset;
119   range_map_const_iterator pos = m_range_map.find(debug_ranges_address);
120   if (pos != m_range_map.end()) {
121     range_list = pos->second;
122     return true;
123   }
124   return false;
125 }
126 
127 bool DWARFDebugRngLists::ExtractRangeList(const DWARFDataExtractor &data,
128                                           uint8_t addrSize,
129                                           lldb::offset_t *offset_ptr,
130                                           DWARFRangeList &rangeList) {
131   rangeList.Clear();
132 
133   bool error = false;
134   while (!error) {
135     switch (data.GetU8(offset_ptr)) {
136     case DW_RLE_end_of_list:
137       return true;
138 
139     case DW_RLE_start_length: {
140       dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize);
141       dw_addr_t len = data.GetULEB128(offset_ptr);
142       rangeList.Append(DWARFRangeList::Entry(begin, len));
143       break;
144     }
145 
146     default:
147       // Next encodings are not yet supported:
148       // DW_RLE_base_addressx, DW_RLE_startx_endx, DW_RLE_startx_length,
149       // DW_RLE_offset_pair, DW_RLE_base_address, DW_RLE_start_end
150       lldbassert(0 && "unknown range list entry encoding");
151       error = true;
152     }
153   }
154 
155   return false;
156 }
157 
158 void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) {
159   const DWARFDataExtractor &data = dwarf2Data->get_debug_rnglists_data();
160   lldb::offset_t offset = 0;
161 
162   uint64_t length = data.GetU32(&offset);
163   bool isDwarf64 = false;
164   if (length == 0xffffffff) {
165     length = data.GetU64(&offset);
166     isDwarf64 = true;
167   }
168   lldb::offset_t end = offset + length;
169 
170   // Check version.
171   if (data.GetU16(&offset) < 5)
172     return;
173 
174   uint8_t addrSize = data.GetU8(&offset);
175 
176   // We do not support non-zero segment selector size.
177   if (data.GetU8(&offset) != 0) {
178     lldbassert(0 && "not implemented");
179     return;
180   }
181 
182   uint32_t offsetsAmount = data.GetU32(&offset);
183   for (uint32_t i = 0; i < offsetsAmount; ++i)
184     Offsets.push_back(data.GetPointer(&offset));
185 
186   lldb::offset_t listOffset = offset;
187   DWARFRangeList rangeList;
188   while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) {
189     rangeList.Sort();
190     m_range_map[listOffset] = rangeList;
191     listOffset = offset;
192   }
193 }
194