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 "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 DWARFDebugRanges::~DWARFDebugRanges() {} 33 34 void DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data) { 35 DWARFRangeList range_list; 36 lldb::offset_t offset = 0; 37 dw_offset_t debug_ranges_offset = offset; 38 while (Extract(dwarf2Data, &offset, range_list)) { 39 range_list.Sort(); 40 m_range_map[debug_ranges_offset] = range_list; 41 debug_ranges_offset = offset; 42 } 43 } 44 45 bool DWARFDebugRanges::Extract(SymbolFileDWARF *dwarf2Data, 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_data = 52 dwarf2Data->get_debug_ranges_data(); 53 uint32_t addr_size = debug_ranges_data.GetAddressByteSize(); 54 dw_addr_t base_addr = 0; 55 dw_addr_t base_addr_marker = GetBaseAddressMarker(addr_size); 56 57 while ( 58 debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) { 59 dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); 60 dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); 61 62 if (!begin && !end) { 63 // End of range list 64 break; 65 } 66 67 if (begin == base_addr_marker) { 68 base_addr = end; 69 continue; 70 } 71 72 // Filter out empty ranges 73 if (begin < end) 74 range_list.Append(DWARFRangeList::Entry(begin + base_addr, end - begin)); 75 } 76 77 // Make sure we consumed at least something 78 return range_offset != *offset_ptr; 79 } 80 81 void DWARFDebugRanges::Dump(Stream &s, 82 const DWARFDataExtractor &debug_ranges_data, 83 lldb::offset_t *offset_ptr, 84 dw_addr_t cu_base_addr) { 85 uint32_t addr_size = s.GetAddressByteSize(); 86 87 dw_addr_t base_addr = cu_base_addr; 88 while ( 89 debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) { 90 dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); 91 dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); 92 // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of 93 // ones 94 if (begin == 0xFFFFFFFFull && addr_size == 4) 95 begin = LLDB_INVALID_ADDRESS; 96 97 s.Indent(); 98 if (begin == 0 && end == 0) { 99 s.PutCString(" End"); 100 break; 101 } else if (begin == LLDB_INVALID_ADDRESS) { 102 // A base address selection entry 103 base_addr = end; 104 s.Address(base_addr, sizeof(dw_addr_t), " Base address = "); 105 } else { 106 // Convert from offset to an address 107 dw_addr_t begin_addr = begin + base_addr; 108 dw_addr_t end_addr = end + base_addr; 109 110 s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), NULL); 111 } 112 } 113 } 114 115 bool DWARFDebugRanges::FindRanges(dw_addr_t debug_ranges_base, 116 dw_offset_t debug_ranges_offset, 117 DWARFRangeList &range_list) const { 118 dw_addr_t debug_ranges_address = debug_ranges_base + debug_ranges_offset; 119 range_map_const_iterator pos = m_range_map.find(debug_ranges_address); 120 if (pos != m_range_map.end()) { 121 range_list = pos->second; 122 return true; 123 } 124 return false; 125 } 126 127 bool DWARFDebugRngLists::ExtractRangeList(const DWARFDataExtractor &data, 128 uint8_t addrSize, 129 lldb::offset_t *offset_ptr, 130 DWARFRangeList &rangeList) { 131 rangeList.Clear(); 132 133 bool error = false; 134 while (!error) { 135 switch (data.GetU8(offset_ptr)) { 136 case DW_RLE_end_of_list: 137 return true; 138 139 case DW_RLE_start_length: { 140 dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); 141 dw_addr_t len = data.GetULEB128(offset_ptr); 142 rangeList.Append(DWARFRangeList::Entry(begin, len)); 143 break; 144 } 145 146 default: 147 // Next encodings are not yet supported: 148 // DW_RLE_base_addressx, DW_RLE_startx_endx, DW_RLE_startx_length, 149 // DW_RLE_offset_pair, DW_RLE_base_address, DW_RLE_start_end 150 lldbassert(0 && "unknown range list entry encoding"); 151 error = true; 152 } 153 } 154 155 return false; 156 } 157 158 void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) { 159 const DWARFDataExtractor &data = dwarf2Data->get_debug_rnglists_data(); 160 lldb::offset_t offset = 0; 161 162 uint64_t length = data.GetU32(&offset); 163 bool isDwarf64 = false; 164 if (length == 0xffffffff) { 165 length = data.GetU64(&offset); 166 isDwarf64 = true; 167 } 168 lldb::offset_t end = offset + length; 169 170 // Check version. 171 if (data.GetU16(&offset) < 5) 172 return; 173 174 uint8_t addrSize = data.GetU8(&offset); 175 176 // We do not support non-zero segment selector size. 177 if (data.GetU8(&offset) != 0) { 178 lldbassert(0 && "not implemented"); 179 return; 180 } 181 182 uint32_t offsetsAmount = data.GetU32(&offset); 183 for (uint32_t i = 0; i < offsetsAmount; ++i) 184 Offsets.push_back(data.GetPointer(&offset)); 185 186 lldb::offset_t listOffset = offset; 187 DWARFRangeList rangeList; 188 while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) { 189 rangeList.Sort(); 190 m_range_map[listOffset] = rangeList; 191 listOffset = offset; 192 } 193 } 194