Files
clang-p2996/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
James Henderson ca05601cd2 [DebugInfo] Don't error for zero-length arange entries
Although the DWARF specification states that .debug_aranges entries
can't have length zero, these can occur in the wild. There's no
particular reason to enforce this part of the spec, since functionally
they have no impact. The patch removes the error and introduces a new
warning for premature terminator entries which does not stop parsing.

This is a relanding of cb3a598c87, adding the missing obj2yaml part
that was needed.

Fixes https://bugs.llvm.org/show_bug.cgi?id=46805. See also
https://reviews.llvm.org/D71932 which originally introduced the error.

Reviewed by: ikudrin, dblaikie, Higuoxing

Differential Revision: https://reviews.llvm.org/D85313
2020-08-10 14:57:52 +01:00

129 lines
4.1 KiB
C++

//===- DWARFDebugAranges.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
#include "llvm/Support/DataExtractor.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <set>
#include <vector>
using namespace llvm;
void DWARFDebugAranges::extract(
DWARFDataExtractor DebugArangesData,
function_ref<void(Error)> RecoverableErrorHandler) {
if (!DebugArangesData.isValidOffset(0))
return;
uint64_t Offset = 0;
DWARFDebugArangeSet Set;
while (DebugArangesData.isValidOffset(Offset)) {
if (Error E =
Set.extract(DebugArangesData, &Offset, RecoverableErrorHandler)) {
RecoverableErrorHandler(std::move(E));
return;
}
uint64_t CUOffset = Set.getCompileUnitDIEOffset();
for (const auto &Desc : Set.descriptors()) {
uint64_t LowPC = Desc.Address;
uint64_t HighPC = Desc.getEndAddress();
appendRange(CUOffset, LowPC, HighPC);
}
ParsedCUOffsets.insert(CUOffset);
}
}
void DWARFDebugAranges::generate(DWARFContext *CTX) {
clear();
if (!CTX)
return;
// Extract aranges from .debug_aranges section.
DWARFDataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(),
CTX->isLittleEndian(), 0);
extract(ArangesData, CTX->getRecoverableErrorHandler());
// Generate aranges from DIEs: even if .debug_aranges section is present,
// it may describe only a small subset of compilation units, so we need to
// manually build aranges for the rest of them.
for (const auto &CU : CTX->compile_units()) {
uint64_t CUOffset = CU->getOffset();
if (ParsedCUOffsets.insert(CUOffset).second) {
Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges();
if (!CURanges)
CTX->getRecoverableErrorHandler()(CURanges.takeError());
else
for (const auto &R : *CURanges)
appendRange(CUOffset, R.LowPC, R.HighPC);
}
}
construct();
}
void DWARFDebugAranges::clear() {
Endpoints.clear();
Aranges.clear();
ParsedCUOffsets.clear();
}
void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC,
uint64_t HighPC) {
if (LowPC >= HighPC)
return;
Endpoints.emplace_back(LowPC, CUOffset, true);
Endpoints.emplace_back(HighPC, CUOffset, false);
}
void DWARFDebugAranges::construct() {
std::multiset<uint64_t> ValidCUs; // Maintain the set of CUs describing
// a current address range.
llvm::sort(Endpoints);
uint64_t PrevAddress = -1ULL;
for (const auto &E : Endpoints) {
if (PrevAddress < E.Address && !ValidCUs.empty()) {
// If the address range between two endpoints is described by some
// CU, first try to extend the last range in Aranges. If we can't
// do it, start a new range.
if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress &&
ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) {
Aranges.back().setHighPC(E.Address);
} else {
Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin());
}
}
// Update the set of valid CUs.
if (E.IsRangeStart) {
ValidCUs.insert(E.CUOffset);
} else {
auto CUPos = ValidCUs.find(E.CUOffset);
assert(CUPos != ValidCUs.end());
ValidCUs.erase(CUPos);
}
PrevAddress = E.Address;
}
assert(ValidCUs.empty());
// Endpoints are not needed now.
Endpoints.clear();
Endpoints.shrink_to_fit();
}
uint64_t DWARFDebugAranges::findAddress(uint64_t Address) const {
RangeCollIterator It =
partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; });
if (It != Aranges.end() && It->LowPC <= Address)
return It->CUOffset;
return -1ULL;
}