mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 11:35:51 -04:00

This helps to detect and report parsing errors better. The patch follows the ideas of LLDB's patches D59370 and D59381. It adds tests for valid and some invalid cases. More checks and tests to come. Note that the patch fixes validation of the Length field because the value does not include the field itself. The existing users are updated to show the error messages. Differential Revision: https://reviews.llvm.org/D71875
127 lines
4.1 KiB
C++
127 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 "llvm/Support/WithColor.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
|
|
void DWARFDebugAranges::extract(DataExtractor DebugArangesData) {
|
|
if (!DebugArangesData.isValidOffset(0))
|
|
return;
|
|
uint64_t Offset = 0;
|
|
DWARFDebugArangeSet Set;
|
|
|
|
while (DebugArangesData.isValidOffset(Offset)) {
|
|
if (Error E = Set.extract(DebugArangesData, &Offset)) {
|
|
WithColor::error() << toString(std::move(E)) << '\n';
|
|
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.
|
|
DataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(),
|
|
CTX->isLittleEndian(), 0);
|
|
extract(ArangesData);
|
|
|
|
// 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)
|
|
WithColor::error() << toString(CURanges.takeError()) << '\n';
|
|
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;
|
|
}
|