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