1*0b57cec5SDimitry Andric //===- DWARFDebugAranges.cpp ----------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" 10*0b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" 11*0b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 12*0b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" 13*0b57cec5SDimitry Andric #include "llvm/Support/DataExtractor.h" 14*0b57cec5SDimitry Andric #include "llvm/Support/WithColor.h" 15*0b57cec5SDimitry Andric #include <algorithm> 16*0b57cec5SDimitry Andric #include <cassert> 17*0b57cec5SDimitry Andric #include <cstdint> 18*0b57cec5SDimitry Andric #include <set> 19*0b57cec5SDimitry Andric #include <vector> 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric using namespace llvm; 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric void DWARFDebugAranges::extract(DataExtractor DebugArangesData) { 24*0b57cec5SDimitry Andric if (!DebugArangesData.isValidOffset(0)) 25*0b57cec5SDimitry Andric return; 26*0b57cec5SDimitry Andric uint32_t Offset = 0; 27*0b57cec5SDimitry Andric DWARFDebugArangeSet Set; 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric while (Set.extract(DebugArangesData, &Offset)) { 30*0b57cec5SDimitry Andric uint32_t CUOffset = Set.getCompileUnitDIEOffset(); 31*0b57cec5SDimitry Andric for (const auto &Desc : Set.descriptors()) { 32*0b57cec5SDimitry Andric uint64_t LowPC = Desc.Address; 33*0b57cec5SDimitry Andric uint64_t HighPC = Desc.getEndAddress(); 34*0b57cec5SDimitry Andric appendRange(CUOffset, LowPC, HighPC); 35*0b57cec5SDimitry Andric } 36*0b57cec5SDimitry Andric ParsedCUOffsets.insert(CUOffset); 37*0b57cec5SDimitry Andric } 38*0b57cec5SDimitry Andric } 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric void DWARFDebugAranges::generate(DWARFContext *CTX) { 41*0b57cec5SDimitry Andric clear(); 42*0b57cec5SDimitry Andric if (!CTX) 43*0b57cec5SDimitry Andric return; 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric // Extract aranges from .debug_aranges section. 46*0b57cec5SDimitry Andric DataExtractor ArangesData(CTX->getDWARFObj().getARangeSection(), 47*0b57cec5SDimitry Andric CTX->isLittleEndian(), 0); 48*0b57cec5SDimitry Andric extract(ArangesData); 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric // Generate aranges from DIEs: even if .debug_aranges section is present, 51*0b57cec5SDimitry Andric // it may describe only a small subset of compilation units, so we need to 52*0b57cec5SDimitry Andric // manually build aranges for the rest of them. 53*0b57cec5SDimitry Andric for (const auto &CU : CTX->compile_units()) { 54*0b57cec5SDimitry Andric uint32_t CUOffset = CU->getOffset(); 55*0b57cec5SDimitry Andric if (ParsedCUOffsets.insert(CUOffset).second) { 56*0b57cec5SDimitry Andric Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges(); 57*0b57cec5SDimitry Andric if (!CURanges) 58*0b57cec5SDimitry Andric WithColor::error() << toString(CURanges.takeError()) << '\n'; 59*0b57cec5SDimitry Andric else 60*0b57cec5SDimitry Andric for (const auto &R : *CURanges) 61*0b57cec5SDimitry Andric appendRange(CUOffset, R.LowPC, R.HighPC); 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric } 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric construct(); 66*0b57cec5SDimitry Andric } 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric void DWARFDebugAranges::clear() { 69*0b57cec5SDimitry Andric Endpoints.clear(); 70*0b57cec5SDimitry Andric Aranges.clear(); 71*0b57cec5SDimitry Andric ParsedCUOffsets.clear(); 72*0b57cec5SDimitry Andric } 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric void DWARFDebugAranges::appendRange(uint32_t CUOffset, uint64_t LowPC, 75*0b57cec5SDimitry Andric uint64_t HighPC) { 76*0b57cec5SDimitry Andric if (LowPC >= HighPC) 77*0b57cec5SDimitry Andric return; 78*0b57cec5SDimitry Andric Endpoints.emplace_back(LowPC, CUOffset, true); 79*0b57cec5SDimitry Andric Endpoints.emplace_back(HighPC, CUOffset, false); 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric void DWARFDebugAranges::construct() { 83*0b57cec5SDimitry Andric std::multiset<uint32_t> ValidCUs; // Maintain the set of CUs describing 84*0b57cec5SDimitry Andric // a current address range. 85*0b57cec5SDimitry Andric llvm::sort(Endpoints); 86*0b57cec5SDimitry Andric uint64_t PrevAddress = -1ULL; 87*0b57cec5SDimitry Andric for (const auto &E : Endpoints) { 88*0b57cec5SDimitry Andric if (PrevAddress < E.Address && !ValidCUs.empty()) { 89*0b57cec5SDimitry Andric // If the address range between two endpoints is described by some 90*0b57cec5SDimitry Andric // CU, first try to extend the last range in Aranges. If we can't 91*0b57cec5SDimitry Andric // do it, start a new range. 92*0b57cec5SDimitry Andric if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress && 93*0b57cec5SDimitry Andric ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) { 94*0b57cec5SDimitry Andric Aranges.back().setHighPC(E.Address); 95*0b57cec5SDimitry Andric } else { 96*0b57cec5SDimitry Andric Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin()); 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric } 99*0b57cec5SDimitry Andric // Update the set of valid CUs. 100*0b57cec5SDimitry Andric if (E.IsRangeStart) { 101*0b57cec5SDimitry Andric ValidCUs.insert(E.CUOffset); 102*0b57cec5SDimitry Andric } else { 103*0b57cec5SDimitry Andric auto CUPos = ValidCUs.find(E.CUOffset); 104*0b57cec5SDimitry Andric assert(CUPos != ValidCUs.end()); 105*0b57cec5SDimitry Andric ValidCUs.erase(CUPos); 106*0b57cec5SDimitry Andric } 107*0b57cec5SDimitry Andric PrevAddress = E.Address; 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric assert(ValidCUs.empty()); 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric // Endpoints are not needed now. 112*0b57cec5SDimitry Andric Endpoints.clear(); 113*0b57cec5SDimitry Andric Endpoints.shrink_to_fit(); 114*0b57cec5SDimitry Andric } 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const { 117*0b57cec5SDimitry Andric RangeCollIterator It = 118*0b57cec5SDimitry Andric partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; }); 119*0b57cec5SDimitry Andric if (It != Aranges.end() && It->LowPC <= Address) 120*0b57cec5SDimitry Andric return It->CUOffset; 121*0b57cec5SDimitry Andric return -1U; 122*0b57cec5SDimitry Andric } 123