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