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