xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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