10b57cec5SDimitry Andric //===- DWARFDebugAranges.cpp ----------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" 100b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" 110b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 120b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" 130b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h" 140b57cec5SDimitry Andric #include <algorithm> 150b57cec5SDimitry Andric #include <cassert> 160b57cec5SDimitry Andric #include <cstdint> 170b57cec5SDimitry Andric #include <set> 180b57cec5SDimitry Andric #include <vector> 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric using namespace llvm; 210b57cec5SDimitry Andric 22*5ffd83dbSDimitry Andric void DWARFDebugAranges::extract( 23*5ffd83dbSDimitry Andric DWARFDataExtractor DebugArangesData, 24*5ffd83dbSDimitry Andric function_ref<void(Error)> RecoverableErrorHandler) { 250b57cec5SDimitry Andric if (!DebugArangesData.isValidOffset(0)) 260b57cec5SDimitry Andric return; 278bcb0991SDimitry Andric uint64_t Offset = 0; 280b57cec5SDimitry Andric DWARFDebugArangeSet Set; 290b57cec5SDimitry Andric 30*5ffd83dbSDimitry Andric while (DebugArangesData.isValidOffset(Offset)) { 31*5ffd83dbSDimitry Andric if (Error E = Set.extract(DebugArangesData, &Offset)) { 32*5ffd83dbSDimitry Andric RecoverableErrorHandler(std::move(E)); 33*5ffd83dbSDimitry Andric return; 34*5ffd83dbSDimitry Andric } 358bcb0991SDimitry Andric uint64_t CUOffset = Set.getCompileUnitDIEOffset(); 360b57cec5SDimitry Andric for (const auto &Desc : Set.descriptors()) { 370b57cec5SDimitry Andric uint64_t LowPC = Desc.Address; 380b57cec5SDimitry Andric uint64_t HighPC = Desc.getEndAddress(); 390b57cec5SDimitry Andric appendRange(CUOffset, LowPC, HighPC); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric ParsedCUOffsets.insert(CUOffset); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric void DWARFDebugAranges::generate(DWARFContext *CTX) { 460b57cec5SDimitry Andric clear(); 470b57cec5SDimitry Andric if (!CTX) 480b57cec5SDimitry Andric return; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric // Extract aranges from .debug_aranges section. 51*5ffd83dbSDimitry Andric DWARFDataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(), 520b57cec5SDimitry Andric CTX->isLittleEndian(), 0); 53*5ffd83dbSDimitry Andric extract(ArangesData, CTX->getRecoverableErrorHandler()); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric // Generate aranges from DIEs: even if .debug_aranges section is present, 560b57cec5SDimitry Andric // it may describe only a small subset of compilation units, so we need to 570b57cec5SDimitry Andric // manually build aranges for the rest of them. 580b57cec5SDimitry Andric for (const auto &CU : CTX->compile_units()) { 598bcb0991SDimitry Andric uint64_t CUOffset = CU->getOffset(); 600b57cec5SDimitry Andric if (ParsedCUOffsets.insert(CUOffset).second) { 610b57cec5SDimitry Andric Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges(); 620b57cec5SDimitry Andric if (!CURanges) 63*5ffd83dbSDimitry Andric CTX->getRecoverableErrorHandler()(CURanges.takeError()); 640b57cec5SDimitry Andric else 650b57cec5SDimitry Andric for (const auto &R : *CURanges) 660b57cec5SDimitry Andric appendRange(CUOffset, R.LowPC, R.HighPC); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric construct(); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric void DWARFDebugAranges::clear() { 740b57cec5SDimitry Andric Endpoints.clear(); 750b57cec5SDimitry Andric Aranges.clear(); 760b57cec5SDimitry Andric ParsedCUOffsets.clear(); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 798bcb0991SDimitry Andric void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC, 800b57cec5SDimitry Andric uint64_t HighPC) { 810b57cec5SDimitry Andric if (LowPC >= HighPC) 820b57cec5SDimitry Andric return; 830b57cec5SDimitry Andric Endpoints.emplace_back(LowPC, CUOffset, true); 840b57cec5SDimitry Andric Endpoints.emplace_back(HighPC, CUOffset, false); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric void DWARFDebugAranges::construct() { 888bcb0991SDimitry Andric std::multiset<uint64_t> ValidCUs; // Maintain the set of CUs describing 890b57cec5SDimitry Andric // a current address range. 900b57cec5SDimitry Andric llvm::sort(Endpoints); 910b57cec5SDimitry Andric uint64_t PrevAddress = -1ULL; 920b57cec5SDimitry Andric for (const auto &E : Endpoints) { 930b57cec5SDimitry Andric if (PrevAddress < E.Address && !ValidCUs.empty()) { 940b57cec5SDimitry Andric // If the address range between two endpoints is described by some 950b57cec5SDimitry Andric // CU, first try to extend the last range in Aranges. If we can't 960b57cec5SDimitry Andric // do it, start a new range. 970b57cec5SDimitry Andric if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress && 980b57cec5SDimitry Andric ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) { 990b57cec5SDimitry Andric Aranges.back().setHighPC(E.Address); 1000b57cec5SDimitry Andric } else { 1010b57cec5SDimitry Andric Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin()); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric // Update the set of valid CUs. 1050b57cec5SDimitry Andric if (E.IsRangeStart) { 1060b57cec5SDimitry Andric ValidCUs.insert(E.CUOffset); 1070b57cec5SDimitry Andric } else { 1080b57cec5SDimitry Andric auto CUPos = ValidCUs.find(E.CUOffset); 1090b57cec5SDimitry Andric assert(CUPos != ValidCUs.end()); 1100b57cec5SDimitry Andric ValidCUs.erase(CUPos); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric PrevAddress = E.Address; 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric assert(ValidCUs.empty()); 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric // Endpoints are not needed now. 1170b57cec5SDimitry Andric Endpoints.clear(); 1180b57cec5SDimitry Andric Endpoints.shrink_to_fit(); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 121480093f4SDimitry Andric uint64_t DWARFDebugAranges::findAddress(uint64_t Address) const { 1220b57cec5SDimitry Andric RangeCollIterator It = 1230b57cec5SDimitry Andric partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; }); 1240b57cec5SDimitry Andric if (It != Aranges.end() && It->LowPC <= Address) 1250b57cec5SDimitry Andric return It->CUOffset; 126480093f4SDimitry Andric return -1ULL; 1270b57cec5SDimitry Andric } 128