1 //===-- DWARFDebugRanges.cpp ----------------------------------------------===// 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 DumpAddress(s.AsRawOstream(), base_addr, sizeof(dw_addr_t), 99 " Base address = "); 100 } else { 101 // Convert from offset to an address 102 dw_addr_t begin_addr = begin + base_addr; 103 dw_addr_t end_addr = end + base_addr; 104 105 DumpAddressRange(s.AsRawOstream(), begin_addr, end_addr, 106 sizeof(dw_addr_t), nullptr); 107 } 108 } 109 } 110 111 bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu, 112 dw_offset_t debug_ranges_offset, 113 DWARFRangeList &range_list) const { 114 dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; 115 range_map_const_iterator pos = m_range_map.find(debug_ranges_address); 116 if (pos != m_range_map.end()) { 117 range_list = pos->second; 118 119 // All DW_AT_ranges are relative to the base address of the compile 120 // unit. We add the compile unit base address to make sure all the 121 // addresses are properly fixed up. 122 range_list.Slide(cu->GetBaseAddress()); 123 return true; 124 } 125 return false; 126 } 127