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 bool DWARFDebugRngLists::ExtractRangeList( 127 const DWARFDataExtractor &data, uint8_t addrSize, 128 lldb::offset_t *offset_ptr, std::vector<RngListEntry> &rangeList) { 129 rangeList.clear(); 130 131 bool error = false; 132 while (!error) { 133 switch (data.GetU8(offset_ptr)) { 134 case DW_RLE_end_of_list: 135 return true; 136 137 case DW_RLE_start_length: { 138 dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); 139 dw_addr_t len = data.GetULEB128(offset_ptr); 140 rangeList.push_back({DW_RLE_start_length, begin, len}); 141 break; 142 } 143 144 case DW_RLE_start_end: { 145 dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); 146 dw_addr_t end = data.GetMaxU64(offset_ptr, addrSize); 147 rangeList.push_back({DW_RLE_start_end, begin, end}); 148 break; 149 } 150 151 case DW_RLE_base_address: { 152 dw_addr_t base = data.GetMaxU64(offset_ptr, addrSize); 153 rangeList.push_back({DW_RLE_base_address, base, 0}); 154 break; 155 } 156 157 case DW_RLE_offset_pair: { 158 dw_addr_t begin = data.GetULEB128(offset_ptr); 159 dw_addr_t end = data.GetULEB128(offset_ptr); 160 rangeList.push_back({DW_RLE_offset_pair, begin, end}); 161 break; 162 } 163 164 case DW_RLE_base_addressx: { 165 dw_addr_t base = data.GetULEB128(offset_ptr); 166 rangeList.push_back({DW_RLE_base_addressx, base, 0}); 167 break; 168 } 169 170 case DW_RLE_startx_endx: { 171 dw_addr_t start = data.GetULEB128(offset_ptr); 172 dw_addr_t end = data.GetULEB128(offset_ptr); 173 rangeList.push_back({DW_RLE_startx_endx, start, end}); 174 break; 175 } 176 177 case DW_RLE_startx_length: { 178 dw_addr_t start = data.GetULEB128(offset_ptr); 179 dw_addr_t length = data.GetULEB128(offset_ptr); 180 rangeList.push_back({DW_RLE_startx_length, start, length}); 181 break; 182 } 183 184 default: 185 lldbassert(0 && "unknown range list entry encoding"); 186 error = true; 187 } 188 } 189 190 return false; 191 } 192 193 static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu, 194 uint32_t index) { 195 uint32_t index_size = cu->GetAddressByteSize(); 196 dw_offset_t addr_base = cu->GetAddrBase(); 197 lldb::offset_t offset = addr_base + index * index_size; 198 return cu->GetSymbolFileDWARF() 199 .GetDWARFContext() 200 .getOrLoadAddrData() 201 .GetMaxU64(&offset, index_size); 202 } 203 204 bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu, 205 dw_offset_t debug_ranges_offset, 206 DWARFRangeList &range_list) const { 207 range_list.Clear(); 208 dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; 209 auto pos = m_range_map.find(debug_ranges_address); 210 if (pos != m_range_map.end()) { 211 dw_addr_t BaseAddr = cu->GetBaseAddress(); 212 for (const RngListEntry &E : pos->second) { 213 switch (E.encoding) { 214 case DW_RLE_start_length: 215 range_list.Append(DWARFRangeList::Entry(E.value0, E.value1)); 216 break; 217 case DW_RLE_base_address: 218 BaseAddr = E.value0; 219 break; 220 case DW_RLE_start_end: 221 range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0)); 222 break; 223 case DW_RLE_offset_pair: 224 range_list.Append( 225 DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0)); 226 break; 227 case DW_RLE_base_addressx: { 228 BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0); 229 break; 230 } 231 case DW_RLE_startx_endx: { 232 dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); 233 dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1); 234 range_list.Append(DWARFRangeList::Entry(start, end - start)); 235 break; 236 } 237 case DW_RLE_startx_length: { 238 dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); 239 range_list.Append(DWARFRangeList::Entry(start, E.value1)); 240 break; 241 } 242 default: 243 llvm_unreachable("unexpected encoding"); 244 } 245 } 246 return true; 247 } 248 return false; 249 } 250 251 void DWARFDebugRngLists::Extract(DWARFContext &context) { 252 const DWARFDataExtractor &data = context.getOrLoadRngListsData(); 253 lldb::offset_t offset = 0; 254 255 uint64_t length = data.GetU32(&offset); 256 // FIXME: Handle DWARF64. 257 lldb::offset_t end = offset + length; 258 259 // Check version. 260 if (data.GetU16(&offset) < 5) 261 return; 262 263 uint8_t addrSize = data.GetU8(&offset); 264 265 // We do not support non-zero segment selector size. 266 if (data.GetU8(&offset) != 0) { 267 lldbassert(0 && "not implemented"); 268 return; 269 } 270 271 uint32_t offsetsAmount = data.GetU32(&offset); 272 for (uint32_t i = 0; i < offsetsAmount; ++i) 273 Offsets.push_back(data.GetMaxU64(&offset, 4)); 274 275 lldb::offset_t listOffset = offset; 276 std::vector<RngListEntry> rangeList; 277 while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) { 278 m_range_map[listOffset] = rangeList; 279 listOffset = offset; 280 } 281 } 282 283 uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const { 284 return Offsets[Index]; 285 } 286