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 "llvm/Support/WithColor.h" 150b57cec5SDimitry Andric #include <algorithm> 160b57cec5SDimitry Andric #include <cassert> 170b57cec5SDimitry Andric #include <cstdint> 180b57cec5SDimitry Andric #include <set> 190b57cec5SDimitry Andric #include <vector> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric void DWARFDebugAranges::extract(DataExtractor DebugArangesData) { 240b57cec5SDimitry Andric if (!DebugArangesData.isValidOffset(0)) 250b57cec5SDimitry Andric return; 26*8bcb0991SDimitry Andric uint64_t Offset = 0; 270b57cec5SDimitry Andric DWARFDebugArangeSet Set; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric while (Set.extract(DebugArangesData, &Offset)) { 30*8bcb0991SDimitry Andric uint64_t CUOffset = Set.getCompileUnitDIEOffset(); 310b57cec5SDimitry Andric for (const auto &Desc : Set.descriptors()) { 320b57cec5SDimitry Andric uint64_t LowPC = Desc.Address; 330b57cec5SDimitry Andric uint64_t HighPC = Desc.getEndAddress(); 340b57cec5SDimitry Andric appendRange(CUOffset, LowPC, HighPC); 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric ParsedCUOffsets.insert(CUOffset); 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric void DWARFDebugAranges::generate(DWARFContext *CTX) { 410b57cec5SDimitry Andric clear(); 420b57cec5SDimitry Andric if (!CTX) 430b57cec5SDimitry Andric return; 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric // Extract aranges from .debug_aranges section. 46*8bcb0991SDimitry Andric DataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(), 470b57cec5SDimitry Andric CTX->isLittleEndian(), 0); 480b57cec5SDimitry Andric extract(ArangesData); 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric // Generate aranges from DIEs: even if .debug_aranges section is present, 510b57cec5SDimitry Andric // it may describe only a small subset of compilation units, so we need to 520b57cec5SDimitry Andric // manually build aranges for the rest of them. 530b57cec5SDimitry Andric for (const auto &CU : CTX->compile_units()) { 54*8bcb0991SDimitry Andric uint64_t CUOffset = CU->getOffset(); 550b57cec5SDimitry Andric if (ParsedCUOffsets.insert(CUOffset).second) { 560b57cec5SDimitry Andric Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges(); 570b57cec5SDimitry Andric if (!CURanges) 580b57cec5SDimitry Andric WithColor::error() << toString(CURanges.takeError()) << '\n'; 590b57cec5SDimitry Andric else 600b57cec5SDimitry Andric for (const auto &R : *CURanges) 610b57cec5SDimitry Andric appendRange(CUOffset, R.LowPC, R.HighPC); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric construct(); 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric void DWARFDebugAranges::clear() { 690b57cec5SDimitry Andric Endpoints.clear(); 700b57cec5SDimitry Andric Aranges.clear(); 710b57cec5SDimitry Andric ParsedCUOffsets.clear(); 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 74*8bcb0991SDimitry Andric void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC, 750b57cec5SDimitry Andric uint64_t HighPC) { 760b57cec5SDimitry Andric if (LowPC >= HighPC) 770b57cec5SDimitry Andric return; 780b57cec5SDimitry Andric Endpoints.emplace_back(LowPC, CUOffset, true); 790b57cec5SDimitry Andric Endpoints.emplace_back(HighPC, CUOffset, false); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric void DWARFDebugAranges::construct() { 83*8bcb0991SDimitry Andric std::multiset<uint64_t> ValidCUs; // Maintain the set of CUs describing 840b57cec5SDimitry Andric // a current address range. 850b57cec5SDimitry Andric llvm::sort(Endpoints); 860b57cec5SDimitry Andric uint64_t PrevAddress = -1ULL; 870b57cec5SDimitry Andric for (const auto &E : Endpoints) { 880b57cec5SDimitry Andric if (PrevAddress < E.Address && !ValidCUs.empty()) { 890b57cec5SDimitry Andric // If the address range between two endpoints is described by some 900b57cec5SDimitry Andric // CU, first try to extend the last range in Aranges. If we can't 910b57cec5SDimitry Andric // do it, start a new range. 920b57cec5SDimitry Andric if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress && 930b57cec5SDimitry Andric ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) { 940b57cec5SDimitry Andric Aranges.back().setHighPC(E.Address); 950b57cec5SDimitry Andric } else { 960b57cec5SDimitry Andric Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin()); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric // Update the set of valid CUs. 1000b57cec5SDimitry Andric if (E.IsRangeStart) { 1010b57cec5SDimitry Andric ValidCUs.insert(E.CUOffset); 1020b57cec5SDimitry Andric } else { 1030b57cec5SDimitry Andric auto CUPos = ValidCUs.find(E.CUOffset); 1040b57cec5SDimitry Andric assert(CUPos != ValidCUs.end()); 1050b57cec5SDimitry Andric ValidCUs.erase(CUPos); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric PrevAddress = E.Address; 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric assert(ValidCUs.empty()); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric // Endpoints are not needed now. 1120b57cec5SDimitry Andric Endpoints.clear(); 1130b57cec5SDimitry Andric Endpoints.shrink_to_fit(); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const { 1170b57cec5SDimitry Andric RangeCollIterator It = 1180b57cec5SDimitry Andric partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; }); 1190b57cec5SDimitry Andric if (It != Aranges.end() && It->LowPC <= Address) 1200b57cec5SDimitry Andric return It->CUOffset; 1210b57cec5SDimitry Andric return -1U; 1220b57cec5SDimitry Andric } 123