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