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