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