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