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