forked from OSchip/llvm-project
[Reland][DebugInfo][llvm-dwarfutil] Combine overlapped address ranges.
DWARF files may contain overlapping address ranges. f.e. it can happen if the two copies of the function have identical instruction sequences and they end up sharing. That looks incorrect from the point of view of DWARF spec. Current implementation of DWARFLinker does not combine overlapped address ranges. It would be good if such ranges would be handled in some useful way. Thus, this patch allows DWARFLinker to combine overlapped ranges in a single one. Depends on D86539 Reviewed By: aprantl Differential Revision: https://reviews.llvm.org/D123469
This commit is contained in:
parent
cd3d7bf15d
commit
8bb4451a65
|
@ -10,9 +10,10 @@
|
|||
#define LLVM_ADT_ADDRESSRANGES_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <cassert>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
@ -47,20 +48,29 @@ private:
|
|||
/// The AddressRanges class helps normalize address range collections.
|
||||
/// This class keeps a sorted vector of AddressRange objects and can perform
|
||||
/// insertions and searches efficiently. The address ranges are always sorted
|
||||
/// and never contain any invalid or empty address ranges. Intersecting
|
||||
/// and never contain any invalid or empty address ranges.
|
||||
/// Intersecting([100,200), [150,300)) and adjacent([100,200), [200,300))
|
||||
/// address ranges are combined during insertion.
|
||||
class AddressRanges {
|
||||
protected:
|
||||
using Collection = std::vector<AddressRange>;
|
||||
using Collection = SmallVector<AddressRange>;
|
||||
Collection Ranges;
|
||||
|
||||
public:
|
||||
void clear() { Ranges.clear(); }
|
||||
bool empty() const { return Ranges.empty(); }
|
||||
bool contains(uint64_t Addr) const;
|
||||
bool contains(AddressRange Range) const;
|
||||
Optional<AddressRange> getRangeThatContains(uint64_t Addr) const;
|
||||
void insert(AddressRange Range);
|
||||
bool contains(uint64_t Addr) const { return find(Addr) != Ranges.end(); }
|
||||
bool contains(AddressRange Range) const {
|
||||
return find(Range) != Ranges.end();
|
||||
}
|
||||
Optional<AddressRange> getRangeThatContains(uint64_t Addr) const {
|
||||
Collection::const_iterator It = find(Addr);
|
||||
if (It == Ranges.end())
|
||||
return None;
|
||||
|
||||
return *It;
|
||||
}
|
||||
Collection::const_iterator insert(AddressRange Range);
|
||||
void reserve(size_t Capacity) { Ranges.reserve(Capacity); }
|
||||
size_t size() const { return Ranges.size(); }
|
||||
bool operator==(const AddressRanges &RHS) const {
|
||||
|
@ -72,6 +82,64 @@ public:
|
|||
}
|
||||
Collection::const_iterator begin() const { return Ranges.begin(); }
|
||||
Collection::const_iterator end() const { return Ranges.end(); }
|
||||
|
||||
protected:
|
||||
Collection::const_iterator find(uint64_t Addr) const;
|
||||
Collection::const_iterator find(AddressRange Range) const;
|
||||
};
|
||||
|
||||
/// AddressRangesMap class maps values to the address ranges.
|
||||
/// It keeps address ranges and corresponding values. If ranges
|
||||
/// are combined during insertion, then combined range keeps
|
||||
/// newly inserted value.
|
||||
template <typename T> class AddressRangesMap : protected AddressRanges {
|
||||
public:
|
||||
void clear() {
|
||||
Ranges.clear();
|
||||
Values.clear();
|
||||
}
|
||||
bool empty() const { return AddressRanges::empty(); }
|
||||
bool contains(uint64_t Addr) const { return AddressRanges::contains(Addr); }
|
||||
bool contains(AddressRange Range) const {
|
||||
return AddressRanges::contains(Range);
|
||||
}
|
||||
void insert(AddressRange Range, T Value) {
|
||||
size_t InputSize = Ranges.size();
|
||||
Collection::const_iterator RangesIt = AddressRanges::insert(Range);
|
||||
if (RangesIt == Ranges.end())
|
||||
return;
|
||||
|
||||
// make Values match to Ranges.
|
||||
size_t Idx = RangesIt - Ranges.begin();
|
||||
typename ValuesCollection::iterator ValuesIt = Values.begin() + Idx;
|
||||
if (InputSize < Ranges.size())
|
||||
Values.insert(ValuesIt, T());
|
||||
else if (InputSize > Ranges.size())
|
||||
Values.erase(ValuesIt, ValuesIt + InputSize - Ranges.size());
|
||||
assert(Ranges.size() == Values.size());
|
||||
|
||||
// set value to the inserted or combined range.
|
||||
Values[Idx] = Value;
|
||||
}
|
||||
size_t size() const {
|
||||
assert(Ranges.size() == Values.size());
|
||||
return AddressRanges::size();
|
||||
}
|
||||
Optional<std::pair<AddressRange, T>>
|
||||
getRangeValueThatContains(uint64_t Addr) const {
|
||||
Collection::const_iterator It = find(Addr);
|
||||
if (It == Ranges.end())
|
||||
return None;
|
||||
|
||||
return std::make_pair(*It, Values[It - Ranges.begin()]);
|
||||
}
|
||||
std::pair<AddressRange, T> operator[](size_t Idx) const {
|
||||
return std::make_pair(Ranges[Idx], Values[Idx]);
|
||||
}
|
||||
|
||||
protected:
|
||||
using ValuesCollection = SmallVector<T>;
|
||||
ValuesCollection Values;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef LLVM_DWARFLINKER_DWARFLINKER_H
|
||||
#define LLVM_DWARFLINKER_DWARFLINKER_H
|
||||
|
||||
#include "llvm/ADT/AddressRanges.h"
|
||||
#include "llvm/CodeGen/AccelTable.h"
|
||||
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
||||
#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
|
||||
|
@ -37,25 +38,6 @@ enum class DwarfLinkerAccelTableKind : uint8_t {
|
|||
Pub, ///< .debug_pubnames, .debug_pubtypes
|
||||
};
|
||||
|
||||
/// Partial address range. Besides an offset, only the
|
||||
/// HighPC is stored. The structure is stored in a map where the LowPC is the
|
||||
/// key.
|
||||
struct ObjFileAddressRange {
|
||||
/// Function HighPC.
|
||||
uint64_t HighPC;
|
||||
/// Offset to apply to the linked address.
|
||||
/// should be 0 for not-linked object file.
|
||||
int64_t Offset;
|
||||
|
||||
ObjFileAddressRange(uint64_t EndPC, int64_t Offset)
|
||||
: HighPC(EndPC), Offset(Offset) {}
|
||||
|
||||
ObjFileAddressRange() : HighPC(0), Offset(0) {}
|
||||
};
|
||||
|
||||
/// Map LowPC to ObjFileAddressRange.
|
||||
using RangesTy = std::map<uint64_t, ObjFileAddressRange>;
|
||||
|
||||
/// AddressesMap represents information about valid addresses used
|
||||
/// by debug information. Valid addresses are those which points to
|
||||
/// live code sections. i.e. relocations for these addresses point
|
||||
|
@ -142,7 +124,7 @@ public:
|
|||
/// original \p Entries.
|
||||
virtual void emitRangesEntries(
|
||||
int64_t UnitPcOffset, uint64_t OrigLowPc,
|
||||
const FunctionIntervals::const_iterator &FuncRange,
|
||||
Optional<std::pair<AddressRange, int64_t>> FuncRange,
|
||||
const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
|
||||
unsigned AddressSize) = 0;
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#ifndef LLVM_DWARFLINKER_DWARFLINKERCOMPILEUNIT_H
|
||||
#define LLVM_DWARFLINKER_DWARFLINKERCOMPILEUNIT_H
|
||||
|
||||
#include "llvm/ADT/AddressRanges.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||
|
||||
|
@ -18,12 +18,9 @@ namespace llvm {
|
|||
|
||||
class DeclContext;
|
||||
|
||||
template <typename KeyT, typename ValT>
|
||||
using HalfOpenIntervalMap =
|
||||
IntervalMap<KeyT, ValT, IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize,
|
||||
IntervalMapHalfOpenInfo<KeyT>>;
|
||||
|
||||
using FunctionIntervals = HalfOpenIntervalMap<uint64_t, int64_t>;
|
||||
/// Mapped value in the address map is the offset to apply to the
|
||||
/// linked address.
|
||||
using RangesTy = AddressRangesMap<int64_t>;
|
||||
|
||||
// FIXME: Delete this structure.
|
||||
struct PatchLocation {
|
||||
|
@ -84,8 +81,7 @@ public:
|
|||
|
||||
CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR,
|
||||
StringRef ClangModuleName)
|
||||
: OrigUnit(OrigUnit), ID(ID), Ranges(RangeAlloc),
|
||||
ClangModuleName(ClangModuleName) {
|
||||
: OrigUnit(OrigUnit), ID(ID), ClangModuleName(ClangModuleName) {
|
||||
Info.resize(OrigUnit.getNumDIEs());
|
||||
|
||||
auto CUDie = OrigUnit.getUnitDIE(false);
|
||||
|
@ -143,7 +139,7 @@ public:
|
|||
return UnitRangeAttribute;
|
||||
}
|
||||
|
||||
const FunctionIntervals &getFunctionRanges() const { return Ranges; }
|
||||
const RangesTy &getFunctionRanges() const { return Ranges; }
|
||||
|
||||
const std::vector<PatchLocation> &getRangesAttributes() const {
|
||||
return RangeAttributes;
|
||||
|
@ -182,10 +178,6 @@ public:
|
|||
/// offset \p PCOffset.
|
||||
void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset);
|
||||
|
||||
/// Check whether specified address range \p LowPC \p HighPC
|
||||
/// overlaps with existing function ranges.
|
||||
bool overlapsWithFunctionRanges(uint64_t LowPC, uint64_t HighPC);
|
||||
|
||||
/// Keep track of a DW_AT_range attribute that we will need to patch up later.
|
||||
void noteRangeAttribute(const DIE &Die, PatchLocation Attr);
|
||||
|
||||
|
@ -270,12 +262,10 @@ private:
|
|||
std::tuple<DIE *, const CompileUnit *, DeclContext *, PatchLocation>>
|
||||
ForwardDIEReferences;
|
||||
|
||||
FunctionIntervals::Allocator RangeAlloc;
|
||||
|
||||
/// The ranges in that interval map are the PC ranges for
|
||||
/// functions in this unit, associated with the PC offset to apply
|
||||
/// to the addresses to get the linked address.
|
||||
FunctionIntervals Ranges;
|
||||
/// The ranges in that map are the PC ranges for functions in this unit,
|
||||
/// associated with the PC offset to apply to the addresses to get
|
||||
/// the linked address.
|
||||
RangesTy Ranges;
|
||||
|
||||
/// The DW_AT_low_pc of each DW_TAG_label.
|
||||
SmallDenseMap<uint64_t, uint64_t, 1> Labels;
|
||||
|
|
|
@ -96,7 +96,7 @@ public:
|
|||
/// original \p Entries.
|
||||
void emitRangesEntries(
|
||||
int64_t UnitPcOffset, uint64_t OrigLowPc,
|
||||
const FunctionIntervals::const_iterator &FuncRange,
|
||||
Optional<std::pair<AddressRange, int64_t>> FuncRange,
|
||||
const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
|
||||
unsigned AddressSize) override;
|
||||
|
||||
|
|
|
@ -504,22 +504,14 @@ unsigned DWARFLinker::shouldKeepSubprogramDIE(
|
|||
&DIE);
|
||||
return Flags;
|
||||
}
|
||||
|
||||
// TODO: Following check is a workaround for overlapping address ranges.
|
||||
// ELF binaries built with LTO might contain overlapping address
|
||||
// ranges. The better fix would be to combine such ranges. Following
|
||||
// is a workaround that should be removed when a good fix is done.
|
||||
if (Unit.overlapsWithFunctionRanges(*LowPc, *HighPc)) {
|
||||
reportWarning(
|
||||
formatv("Overlapping address range [{0:X}, {1:X}]. Range will "
|
||||
"be discarded.\n",
|
||||
*LowPc, *HighPc),
|
||||
File, &DIE);
|
||||
if (*LowPc > *HighPc) {
|
||||
reportWarning("low_pc greater than high_pc. Range will be discarded.\n",
|
||||
File, &DIE);
|
||||
return Flags;
|
||||
}
|
||||
|
||||
// Replace the debug map range with a more accurate one.
|
||||
Ranges[*LowPc] = ObjFileAddressRange(*HighPc, MyInfo.AddrAdjust);
|
||||
Ranges.insert({*LowPc, *HighPc}, MyInfo.AddrAdjust);
|
||||
Unit.addFunctionRange(*LowPc, *HighPc, MyInfo.AddrAdjust);
|
||||
return Flags;
|
||||
}
|
||||
|
@ -1588,7 +1580,7 @@ void DWARFLinker::patchRangesForUnit(const CompileUnit &Unit,
|
|||
DWARFDataExtractor RangeExtractor(OrigDwarf.getDWARFObj(),
|
||||
OrigDwarf.getDWARFObj().getRangesSection(),
|
||||
OrigDwarf.isLittleEndian(), AddressSize);
|
||||
auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
|
||||
Optional<std::pair<AddressRange, int64_t>> CurrRange;
|
||||
DWARFUnit &OrigUnit = Unit.getOrigUnit();
|
||||
auto OrigUnitDie = OrigUnit.getUnitDIE(false);
|
||||
uint64_t OrigLowPc =
|
||||
|
@ -1611,12 +1603,11 @@ void DWARFLinker::patchRangesForUnit(const CompileUnit &Unit,
|
|||
if (!Entries.empty()) {
|
||||
const DWARFDebugRangeList::RangeListEntry &First = Entries.front();
|
||||
|
||||
if (CurrRange == InvalidRange ||
|
||||
First.StartAddress + OrigLowPc < CurrRange.start() ||
|
||||
First.StartAddress + OrigLowPc >= CurrRange.stop()) {
|
||||
CurrRange = FunctionRanges.find(First.StartAddress + OrigLowPc);
|
||||
if (CurrRange == InvalidRange ||
|
||||
CurrRange.start() > First.StartAddress + OrigLowPc) {
|
||||
if (!CurrRange ||
|
||||
!CurrRange->first.contains(First.StartAddress + OrigLowPc)) {
|
||||
CurrRange = FunctionRanges.getRangeValueThatContains(
|
||||
First.StartAddress + OrigLowPc);
|
||||
if (!CurrRange) {
|
||||
reportWarning("no mapping for range.", File);
|
||||
continue;
|
||||
}
|
||||
|
@ -1723,7 +1714,7 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
|
|||
// in NewRows.
|
||||
std::vector<DWARFDebugLine::Row> Seq;
|
||||
const auto &FunctionRanges = Unit.getFunctionRanges();
|
||||
auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
|
||||
Optional<std::pair<AddressRange, int64_t>> CurrRange;
|
||||
|
||||
// FIXME: This logic is meant to generate exactly the same output as
|
||||
// Darwin's classic dsymutil. There is a nicer way to implement this
|
||||
|
@ -1742,19 +1733,14 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
|
|||
// it is marked as end_sequence in the input (because in that
|
||||
// case, the relocation offset is accurate and that entry won't
|
||||
// serve as the start of another function).
|
||||
if (CurrRange == InvalidRange || Row.Address.Address < CurrRange.start() ||
|
||||
Row.Address.Address > CurrRange.stop() ||
|
||||
(Row.Address.Address == CurrRange.stop() && !Row.EndSequence)) {
|
||||
if (!CurrRange || !CurrRange->first.contains(Row.Address.Address) ||
|
||||
(Row.Address.Address == CurrRange->first.end() && !Row.EndSequence)) {
|
||||
// We just stepped out of a known range. Insert a end_sequence
|
||||
// corresponding to the end of the range.
|
||||
uint64_t StopAddress = CurrRange != InvalidRange
|
||||
? CurrRange.stop() + CurrRange.value()
|
||||
: -1ULL;
|
||||
CurrRange = FunctionRanges.find(Row.Address.Address);
|
||||
bool CurrRangeValid =
|
||||
CurrRange != InvalidRange && CurrRange.start() <= Row.Address.Address;
|
||||
if (!CurrRangeValid) {
|
||||
CurrRange = InvalidRange;
|
||||
uint64_t StopAddress =
|
||||
CurrRange ? CurrRange->first.end() + CurrRange->second : -1ULL;
|
||||
CurrRange = FunctionRanges.getRangeValueThatContains(Row.Address.Address);
|
||||
if (!CurrRange) {
|
||||
if (StopAddress != -1ULL) {
|
||||
// Try harder by looking in the Address ranges map.
|
||||
// There are corner cases where this finds a
|
||||
|
@ -1762,14 +1748,9 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
|
|||
// for now do as dsymutil.
|
||||
// FIXME: Understand exactly what cases this addresses and
|
||||
// potentially remove it along with the Ranges map.
|
||||
auto Range = Ranges.lower_bound(Row.Address.Address);
|
||||
if (Range != Ranges.begin() && Range != Ranges.end())
|
||||
--Range;
|
||||
|
||||
if (Range != Ranges.end() && Range->first <= Row.Address.Address &&
|
||||
Range->second.HighPC >= Row.Address.Address) {
|
||||
StopAddress = Row.Address.Address + Range->second.Offset;
|
||||
}
|
||||
if (Optional<std::pair<AddressRange, int64_t>> Range =
|
||||
Ranges.getRangeValueThatContains(Row.Address.Address))
|
||||
StopAddress = Row.Address.Address + (*Range).second;
|
||||
}
|
||||
}
|
||||
if (StopAddress != -1ULL && !Seq.empty()) {
|
||||
|
@ -1785,7 +1766,7 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
|
|||
insertLineSequence(Seq, NewRows);
|
||||
}
|
||||
|
||||
if (!CurrRangeValid)
|
||||
if (!CurrRange)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1794,7 +1775,7 @@ void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
|
|||
continue;
|
||||
|
||||
// Relocate row address and add it to the current sequence.
|
||||
Row.Address.Address += CurrRange.value();
|
||||
Row.Address.Address += CurrRange->second;
|
||||
Seq.emplace_back(Row);
|
||||
|
||||
if (Row.EndSequence)
|
||||
|
@ -1934,11 +1915,9 @@ void DWARFLinker::patchFrameInfoForObject(const DWARFFile &File,
|
|||
// the function entry point, thus we can't just lookup the address
|
||||
// in the debug map. Use the AddressInfo's range map to see if the FDE
|
||||
// describes something that we can relocate.
|
||||
auto Range = Ranges.upper_bound(Loc);
|
||||
if (Range != Ranges.begin())
|
||||
--Range;
|
||||
if (Range == Ranges.end() || Range->first > Loc ||
|
||||
Range->second.HighPC <= Loc) {
|
||||
Optional<std::pair<AddressRange, int64_t>> Range =
|
||||
Ranges.getRangeValueThatContains(Loc);
|
||||
if (!Range) {
|
||||
// The +4 is to account for the size of the InitialLength field itself.
|
||||
InputOffset = EntryOffset + InitialLength + 4;
|
||||
continue;
|
||||
|
@ -1966,7 +1945,7 @@ void DWARFLinker::patchFrameInfoForObject(const DWARFFile &File,
|
|||
// fields that will get reconstructed by emitFDE().
|
||||
unsigned FDERemainingBytes = InitialLength - (4 + AddrSize);
|
||||
TheDwarfEmitter->emitFDE(IteratorInserted.first->getValue(), AddrSize,
|
||||
Loc + Range->second.Offset,
|
||||
Loc + Range->second,
|
||||
FrameData.substr(InputOffset, FDERemainingBytes));
|
||||
InputOffset += FDERemainingBytes;
|
||||
}
|
||||
|
|
|
@ -105,19 +105,11 @@ void CompileUnit::addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset) {
|
|||
|
||||
void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
|
||||
int64_t PcOffset) {
|
||||
// Don't add empty ranges to the interval map. They are a problem because
|
||||
// the interval map expects half open intervals. This is safe because they
|
||||
// are empty anyway.
|
||||
if (FuncHighPc != FuncLowPc)
|
||||
Ranges.insert(FuncLowPc, FuncHighPc, PcOffset);
|
||||
Ranges.insert({FuncLowPc, FuncHighPc}, PcOffset);
|
||||
this->LowPc = std::min(LowPc, FuncLowPc + PcOffset);
|
||||
this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
|
||||
}
|
||||
|
||||
bool CompileUnit::overlapsWithFunctionRanges(uint64_t LowPC, uint64_t HighPC) {
|
||||
return Ranges.overlaps(LowPC, HighPC);
|
||||
}
|
||||
|
||||
void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
|
||||
if (Die.getTag() != dwarf::DW_TAG_compile_unit)
|
||||
RangeAttributes.push_back(Attr);
|
||||
|
|
|
@ -321,13 +321,14 @@ void DwarfStreamer::emitSwiftReflectionSection(
|
|||
/// sized addresses describing the ranges.
|
||||
void DwarfStreamer::emitRangesEntries(
|
||||
int64_t UnitPcOffset, uint64_t OrigLowPc,
|
||||
const FunctionIntervals::const_iterator &FuncRange,
|
||||
Optional<std::pair<AddressRange, int64_t>> FuncRange,
|
||||
const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
|
||||
unsigned AddressSize) {
|
||||
MS->switchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
|
||||
|
||||
// Offset each range by the right amount.
|
||||
int64_t PcOffset = Entries.empty() ? 0 : FuncRange.value() + UnitPcOffset;
|
||||
int64_t PcOffset =
|
||||
(Entries.empty() || !FuncRange) ? 0 : FuncRange->second + UnitPcOffset;
|
||||
for (const auto &Range : Entries) {
|
||||
if (Range.isBaseAddressSelectionEntry(AddressSize)) {
|
||||
warn("unsupported base address selection operation",
|
||||
|
@ -339,8 +340,7 @@ void DwarfStreamer::emitRangesEntries(
|
|||
continue;
|
||||
|
||||
// All range entries should lie in the function range.
|
||||
if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() &&
|
||||
Range.EndAddress + OrigLowPc <= FuncRange.stop()))
|
||||
if (!FuncRange->first.contains(Range.StartAddress + OrigLowPc))
|
||||
warn("inconsistent range data.", "emitting debug_ranges");
|
||||
MS->emitIntValue(Range.StartAddress + PcOffset, AddressSize);
|
||||
MS->emitIntValue(Range.EndAddress + PcOffset, AddressSize);
|
||||
|
@ -365,11 +365,13 @@ void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
|
|||
// IntervalMap will have coalesced the non-linked ranges, but here
|
||||
// we want to coalesce the linked addresses.
|
||||
std::vector<std::pair<uint64_t, uint64_t>> Ranges;
|
||||
const auto &FunctionRanges = Unit.getFunctionRanges();
|
||||
for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end();
|
||||
Range != End; ++Range)
|
||||
Ranges.push_back(std::make_pair(Range.start() + Range.value(),
|
||||
Range.stop() + Range.value()));
|
||||
const RangesTy &FunctionRanges = Unit.getFunctionRanges();
|
||||
for (size_t Idx = 0; Idx < FunctionRanges.size(); Idx++) {
|
||||
std::pair<AddressRange, int64_t> CurRange = FunctionRanges[Idx];
|
||||
|
||||
Ranges.push_back(std::make_pair(CurRange.first.start() + CurRange.second,
|
||||
CurRange.first.end() + CurRange.second));
|
||||
}
|
||||
|
||||
// The object addresses where sorted, but again, the linked
|
||||
// addresses might end up in a different order.
|
||||
|
|
|
@ -12,48 +12,59 @@
|
|||
|
||||
using namespace llvm;
|
||||
|
||||
void AddressRanges::insert(AddressRange Range) {
|
||||
AddressRanges::Collection::const_iterator
|
||||
AddressRanges::insert(AddressRange Range) {
|
||||
if (Range.size() == 0)
|
||||
return;
|
||||
return Ranges.end();
|
||||
|
||||
auto It = llvm::upper_bound(Ranges, Range);
|
||||
auto It2 = It;
|
||||
while (It2 != Ranges.end() && It2->start() < Range.end())
|
||||
while (It2 != Ranges.end() && It2->start() <= Range.end())
|
||||
++It2;
|
||||
if (It != It2) {
|
||||
Range = {Range.start(), std::max(Range.end(), It2[-1].end())};
|
||||
Range = {Range.start(), std::max(Range.end(), std::prev(It2)->end())};
|
||||
It = Ranges.erase(It, It2);
|
||||
}
|
||||
if (It != Ranges.begin() && Range.start() < It[-1].end())
|
||||
It[-1] = {It[-1].start(), std::max(It[-1].end(), Range.end())};
|
||||
else
|
||||
Ranges.insert(It, Range);
|
||||
if (It != Ranges.begin() && Range.start() <= std::prev(It)->end()) {
|
||||
--It;
|
||||
*It = {It->start(), std::max(It->end(), Range.end())};
|
||||
return It;
|
||||
}
|
||||
|
||||
return Ranges.insert(It, Range);
|
||||
}
|
||||
|
||||
bool AddressRanges::contains(uint64_t Addr) const {
|
||||
AddressRanges::Collection::const_iterator
|
||||
AddressRanges::find(uint64_t Addr) const {
|
||||
auto It = std::partition_point(
|
||||
Ranges.begin(), Ranges.end(),
|
||||
[=](const AddressRange &R) { return R.start() <= Addr; });
|
||||
return It != Ranges.begin() && Addr < It[-1].end();
|
||||
|
||||
if (It == Ranges.begin())
|
||||
return Ranges.end();
|
||||
|
||||
--It;
|
||||
if (Addr >= It->end())
|
||||
return Ranges.end();
|
||||
|
||||
return It;
|
||||
}
|
||||
|
||||
bool AddressRanges::contains(AddressRange Range) const {
|
||||
AddressRanges::Collection::const_iterator
|
||||
AddressRanges::find(AddressRange Range) const {
|
||||
if (Range.size() == 0)
|
||||
return false;
|
||||
return Ranges.end();
|
||||
|
||||
auto It = std::partition_point(
|
||||
Ranges.begin(), Ranges.end(),
|
||||
[=](const AddressRange &R) { return R.start() <= Range.start(); });
|
||||
if (It == Ranges.begin())
|
||||
return false;
|
||||
return Range.end() <= It[-1].end();
|
||||
}
|
||||
|
||||
Optional<AddressRange>
|
||||
AddressRanges::getRangeThatContains(uint64_t Addr) const {
|
||||
auto It = std::partition_point(
|
||||
Ranges.begin(), Ranges.end(),
|
||||
[=](const AddressRange &R) { return R.start() <= Addr; });
|
||||
if (It != Ranges.begin() && Addr < It[-1].end())
|
||||
return It[-1];
|
||||
return llvm::None;
|
||||
if (It == Ranges.begin())
|
||||
return Ranges.end();
|
||||
|
||||
--It;
|
||||
if (Range.end() > It->end())
|
||||
return Ranges.end();
|
||||
|
||||
return It;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
## This test checks that overlapping function address ranges
|
||||
## are combined during --garbage-collection optimisation.
|
||||
|
||||
# RUN: yaml2obj %s -o %t.o
|
||||
# RUN: llvm-dwarfutil --garbage-collection %t.o %t1
|
||||
# RUN: llvm-dwarfdump -a %t1 | FileCheck %s
|
||||
|
||||
# CHECK: DW_TAG_compile_unit
|
||||
# CHECK: DW_AT_name{{.*}}"CU1"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0000000000001000
|
||||
# CHECK: DW_AT_ranges
|
||||
# CHECK: [0x0000000000001000, 0x000000000000102d)
|
||||
# CHECK: [0x0000000000002002, 0x000000000000200d)
|
||||
# CHECK: [0x000000000000201b, 0x000000000000202a)
|
||||
# CHECK: [0x0000000000003002, 0x0000000000003007)
|
||||
# CHECK: [0x0000000000003012, 0x0000000000003017)
|
||||
# CHECK: [0x0000000000003018, 0x000000000000301a)
|
||||
# CHECK: [0x0000000000003022, 0x0000000000003027
|
||||
# CHECK: DW_TAG_class_type
|
||||
# CHECK: DW_AT_name{{.*}}"class1"
|
||||
# CHECK: DW_TAG_class_type
|
||||
# CHECK: "class2"
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: DW_AT_name{{.*}}"foo1"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000001000
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000001010
|
||||
# CHECK: DW_AT_type{{.*}}"class1"
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo2"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000001004
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000001007
|
||||
# CHECK: DW_AT_type{{.*}}"class2"
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo3"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x000000000000100d
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x000000000000102d
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo4"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000002002
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x000000000000200d
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo5"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x000000000000201b
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x000000000000202a
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo6"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000003002
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000003007
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo7"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000003012
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000003017
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo8"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000003022
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000003027
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: "foo9"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000003012
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000003017
|
||||
# CHECK: "foo10"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000003018
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x000000000000301a
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
Address: 0x1000
|
||||
AddressAlign: 0x0000000000000010
|
||||
Content: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
- Name: .text2
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
Address: 0x2000
|
||||
AddressAlign: 0x0000000000000010
|
||||
Content: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
- Name: .text3
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
Address: 0x3000
|
||||
AddressAlign: 0x0000000000000010
|
||||
Content: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
DWARF:
|
||||
debug_abbrev:
|
||||
- Table:
|
||||
- Tag: DW_TAG_compile_unit
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_producer
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_language
|
||||
Form: DW_FORM_data2
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_ranges
|
||||
Form: DW_FORM_sec_offset
|
||||
- Tag: DW_TAG_subprogram
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data8
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Tag: DW_TAG_member
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_declaration
|
||||
Form: DW_FORM_flag_present
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_declaration
|
||||
Form: DW_FORM_flag_present
|
||||
- Tag: DW_TAG_template_type_parameter
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Tag: DW_TAG_base_type
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
debug_info:
|
||||
- Version: 4
|
||||
Entries:
|
||||
- AbbrCode: 1
|
||||
Values:
|
||||
- CStr: by_hand
|
||||
- Value: 0x04
|
||||
- CStr: CU1
|
||||
- Value: 0x00
|
||||
- Value: 0x00
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class1
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x00000052
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class2
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x00000052
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 8
|
||||
Values:
|
||||
- CStr: int
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo1
|
||||
- Value: 0x1000
|
||||
- Value: 0x10
|
||||
- Value: 0x00000026
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo2
|
||||
- Value: 0x1004
|
||||
- Value: 0x3
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo3
|
||||
- Value: 0x100d
|
||||
- Value: 0x20
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo4
|
||||
- Value: 0x2002
|
||||
- Value: 0xb
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo5
|
||||
- Value: 0x201b
|
||||
- Value: 0xf
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo6
|
||||
- Value: 0x3002
|
||||
- Value: 0x5
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo7
|
||||
- Value: 0x3012
|
||||
- Value: 0x5
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo8
|
||||
- Value: 0x3022
|
||||
- Value: 0x5
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo9
|
||||
- Value: 0x3012
|
||||
- Value: 0x5
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo10
|
||||
- Value: 0x3018
|
||||
- Value: 0x2
|
||||
- Value: 0x0000003c
|
||||
- AbbrCode: 0
|
||||
|
||||
debug_ranges:
|
||||
- Offset: 0x00000000
|
||||
AddrSize: 0x08
|
||||
Entries:
|
||||
- LowOffset: 0x0000000000001000
|
||||
HighOffset: 0x000000000000102d
|
||||
- LowOffset: 0x0000000000002000
|
||||
HighOffset: 0x000000000000202d
|
||||
- LowOffset: 0x0000000000000000
|
||||
HighOffset: 0x0000000000000000
|
||||
...
|
|
@ -0,0 +1,247 @@
|
|||
## This test checks that overlapping compile unit address ranges
|
||||
## are ignored (i.e. left unchanged) by --garbage-collection
|
||||
## optimisation.
|
||||
|
||||
# RUN: yaml2obj %s -o %t.o
|
||||
# RUN: llvm-dwarfutil --garbage-collection %t.o %t1
|
||||
# RUN: llvm-dwarfdump -a %t1 | FileCheck %s
|
||||
|
||||
# CHECK: DW_TAG_compile_unit
|
||||
# CHECK: DW_AT_name{{.*}}"CU1"
|
||||
# CHECK: DW_TAG_class_type
|
||||
# CHECK: DW_AT_name{{.*}}"class1"
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: DW_AT_name{{.*}}"foo1"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000001000
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000001010
|
||||
# CHECK: DW_TAG_subprogram
|
||||
# CHECK: DW_AT_name{{.*}}"foo2"
|
||||
# CHECK: DW_AT_low_pc{{.*}}0x0000000000001000
|
||||
# CHECK: DW_AT_high_pc{{.*}}0x0000000000001010
|
||||
# CHECK: DW_AT_type{{.*}}"class2"
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
Address: 0x1000
|
||||
AddressAlign: 0x0000000000000010
|
||||
Content: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
DWARF:
|
||||
debug_abbrev:
|
||||
- Table:
|
||||
- Tag: DW_TAG_compile_unit
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_producer
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_language
|
||||
Form: DW_FORM_data2
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data8
|
||||
- Tag: DW_TAG_subprogram
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data8
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Tag: DW_TAG_member
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_declaration
|
||||
Form: DW_FORM_flag_present
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_declaration
|
||||
Form: DW_FORM_flag_present
|
||||
- Tag: DW_TAG_template_type_parameter
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Tag: DW_TAG_base_type
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Table:
|
||||
- Tag: DW_TAG_compile_unit
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_producer
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_language
|
||||
Form: DW_FORM_data2
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data8
|
||||
- Tag: DW_TAG_subprogram
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_low_pc
|
||||
Form: DW_FORM_addr
|
||||
- Attribute: DW_AT_high_pc
|
||||
Form: DW_FORM_data8
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Tag: DW_TAG_member
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_declaration
|
||||
Form: DW_FORM_flag_present
|
||||
- Tag: DW_TAG_class_type
|
||||
Children: DW_CHILDREN_yes
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
- Attribute: DW_AT_declaration
|
||||
Form: DW_FORM_flag_present
|
||||
- Tag: DW_TAG_template_type_parameter
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_type
|
||||
Form: DW_FORM_ref4
|
||||
- Tag: DW_TAG_base_type
|
||||
Children: DW_CHILDREN_no
|
||||
Attributes:
|
||||
- Attribute: DW_AT_name
|
||||
Form: DW_FORM_string
|
||||
debug_info:
|
||||
- Version: 4
|
||||
Entries:
|
||||
- AbbrCode: 1
|
||||
Values:
|
||||
- CStr: by_hand
|
||||
- Value: 0x04
|
||||
- CStr: CU1
|
||||
- Value: 0x1000
|
||||
- Value: 0x1b
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class1
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x0000006c
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class2
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x0000006c
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class3
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x0000006c
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 8
|
||||
Values:
|
||||
- CStr: int
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo1
|
||||
- Value: 0x1000
|
||||
- Value: 0x10
|
||||
- Value: 0x0000002a
|
||||
- AbbrCode: 0
|
||||
- Version: 4
|
||||
Entries:
|
||||
- AbbrCode: 1
|
||||
Values:
|
||||
- CStr: by_hand
|
||||
- Value: 0x04
|
||||
- CStr: CU1
|
||||
- Value: 0x1000
|
||||
- Value: 0x1b
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class1
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x0000006c
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class2
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x0000006c
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 3
|
||||
Values:
|
||||
- CStr: class3
|
||||
- AbbrCode: 4
|
||||
Values:
|
||||
- Value: 0x0000006c
|
||||
- CStr: member1
|
||||
- AbbrCode: 0
|
||||
- AbbrCode: 8
|
||||
Values:
|
||||
- CStr: int
|
||||
- AbbrCode: 2
|
||||
Values:
|
||||
- CStr: foo2
|
||||
- Value: 0x1000
|
||||
- Value: 0x10
|
||||
- Value: 0x00000040
|
||||
- AbbrCode: 0
|
||||
...
|
|
@ -18,7 +18,6 @@
|
|||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
|
|
|
@ -132,8 +132,8 @@ private:
|
|||
for (const auto &Entry : DMO.symbols()) {
|
||||
const auto &Mapping = Entry.getValue();
|
||||
if (Mapping.Size && Mapping.ObjectAddress)
|
||||
AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange(
|
||||
*Mapping.ObjectAddress + Mapping.Size,
|
||||
AddressRanges.insert(
|
||||
{*Mapping.ObjectAddress, *Mapping.ObjectAddress + Mapping.Size},
|
||||
int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
if (Size == 0)
|
||||
continue;
|
||||
const uint64_t StartAddr = Sect.getAddress();
|
||||
TextAddressRanges[{StartAddr}] = {StartAddr + Size, 0};
|
||||
TextAddressRanges.insert({StartAddr, StartAddr + Size});
|
||||
}
|
||||
|
||||
// Check CU address ranges for tombstone value.
|
||||
|
@ -59,7 +59,7 @@ public:
|
|||
for (auto &Range : *ARanges) {
|
||||
if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
|
||||
Options.Tombstone, CU->getAddressByteSize()))
|
||||
DWARFAddressRanges[{Range.LowPC}] = {Range.HighPC, 0};
|
||||
DWARFAddressRanges.insert({Range.LowPC, Range.HighPC}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,17 +146,13 @@ protected:
|
|||
// of executable sections.
|
||||
bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
|
||||
Optional<uint64_t> HighPC) {
|
||||
auto Range = TextAddressRanges.lower_bound(LowPC);
|
||||
if ((Range == TextAddressRanges.end() || Range->first != LowPC) &&
|
||||
Range != TextAddressRanges.begin())
|
||||
--Range;
|
||||
Optional<AddressRange> Range =
|
||||
TextAddressRanges.getRangeThatContains(LowPC);
|
||||
|
||||
if (Range != TextAddressRanges.end() && Range->first <= LowPC &&
|
||||
(HighPC ? Range->second.HighPC >= HighPC
|
||||
: Range->second.HighPC >= LowPC))
|
||||
return true;
|
||||
if (HighPC)
|
||||
return Range.hasValue() && Range->end() >= *HighPC;
|
||||
|
||||
return false;
|
||||
return Range.hasValue();
|
||||
}
|
||||
|
||||
uint64_t isBFDDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
|
||||
|
@ -210,7 +206,7 @@ protected:
|
|||
|
||||
private:
|
||||
RangesTy DWARFAddressRanges;
|
||||
RangesTy TextAddressRanges;
|
||||
AddressRanges TextAddressRanges;
|
||||
const Options &Opts;
|
||||
};
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ TEST(AddressRangeTest, TestRanges) {
|
|||
EXPECT_FALSE(Ranges.contains(AddressRange(0x1000, 0x1000)));
|
||||
EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x1000 + 1)));
|
||||
EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x2000)));
|
||||
EXPECT_FALSE(Ranges.contains(AddressRange(0x1000, 0x2001)));
|
||||
EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x2001)));
|
||||
EXPECT_TRUE(Ranges.contains(AddressRange(0x2000, 0x3000)));
|
||||
EXPECT_FALSE(Ranges.contains(AddressRange(0x2000, 0x3001)));
|
||||
EXPECT_FALSE(Ranges.contains(AddressRange(0x3000, 0x3001)));
|
||||
|
@ -125,16 +125,22 @@ TEST(AddressRangeTest, TestRanges) {
|
|||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2000));
|
||||
|
||||
// Verify that adjacent ranges don't get combined
|
||||
Ranges.insert(AddressRange(0x2000, 0x3000));
|
||||
// Verify that adjacent ranges get combined
|
||||
Ranges.insert(AddressRange(0x2000, 0x2fff));
|
||||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2fff));
|
||||
|
||||
// Verify that ranges having 1 byte gap do not get combined
|
||||
Ranges.insert(AddressRange(0x3000, 0x4000));
|
||||
EXPECT_EQ(Ranges.size(), 2u);
|
||||
EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2000));
|
||||
EXPECT_EQ(Ranges[1], AddressRange(0x2000, 0x3000));
|
||||
EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2fff));
|
||||
EXPECT_EQ(Ranges[1], AddressRange(0x3000, 0x4000));
|
||||
|
||||
// Verify if we add an address range that intersects two ranges
|
||||
// that they get combined
|
||||
Ranges.insert(AddressRange(Ranges[0].end() - 1, Ranges[1].start() + 1));
|
||||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x3000));
|
||||
EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x4000));
|
||||
|
||||
Ranges.insert(AddressRange(0x3000, 0x4000));
|
||||
Ranges.insert(AddressRange(0x4000, 0x5000));
|
||||
|
@ -142,3 +148,87 @@ TEST(AddressRangeTest, TestRanges) {
|
|||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x5000));
|
||||
}
|
||||
|
||||
TEST(AddressRangeTest, TestRangesMap) {
|
||||
AddressRangesMap<int> Ranges;
|
||||
|
||||
EXPECT_EQ(Ranges.size(), 0u);
|
||||
EXPECT_TRUE(Ranges.empty());
|
||||
|
||||
// Add single range.
|
||||
Ranges.insert(AddressRange(0x1000, 0x2000), 0xfe);
|
||||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_FALSE(Ranges.empty());
|
||||
EXPECT_TRUE(Ranges.contains(0x1500));
|
||||
EXPECT_TRUE(Ranges.contains(AddressRange(0x1000, 0x2000)));
|
||||
|
||||
// Clear ranges.
|
||||
Ranges.clear();
|
||||
EXPECT_EQ(Ranges.size(), 0u);
|
||||
EXPECT_TRUE(Ranges.empty());
|
||||
|
||||
// Add range and check value.
|
||||
Ranges.insert(AddressRange(0x1000, 0x2000), 0xfe);
|
||||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xfe);
|
||||
|
||||
// Add adjacent range and check value.
|
||||
Ranges.insert(AddressRange(0x2000, 0x3000), 0xfc);
|
||||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xfc);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x2000)->second, 0xfc);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x2900)->second, 0xfc);
|
||||
EXPECT_FALSE(Ranges.getRangeValueThatContains(0x3000));
|
||||
|
||||
// Add intersecting range and check value.
|
||||
Ranges.insert(AddressRange(0x2000, 0x3000), 0xff);
|
||||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xff);
|
||||
|
||||
// Add second range and check values.
|
||||
Ranges.insert(AddressRange(0x4000, 0x5000), 0x0);
|
||||
EXPECT_EQ(Ranges.size(), 2u);
|
||||
EXPECT_EQ(Ranges[0].second, 0xff);
|
||||
EXPECT_EQ(Ranges[1].second, 0x0);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0xff);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x4000)->second, 0x0);
|
||||
|
||||
// Add intersecting range and check value.
|
||||
Ranges.insert(AddressRange(0x0, 0x6000), 0x1);
|
||||
EXPECT_EQ(Ranges.size(), 1u);
|
||||
EXPECT_EQ(Ranges.getRangeValueThatContains(0x1000)->second, 0x1);
|
||||
|
||||
// Check that values are correctly preserved for combined ranges.
|
||||
Ranges.clear();
|
||||
Ranges.insert(AddressRange(0x0, 0xff), 0x1);
|
||||
Ranges.insert(AddressRange(0x100, 0x1ff), 0x2);
|
||||
Ranges.insert(AddressRange(0x200, 0x2ff), 0x3);
|
||||
Ranges.insert(AddressRange(0x300, 0x3ff), 0x4);
|
||||
Ranges.insert(AddressRange(0x400, 0x4ff), 0x5);
|
||||
Ranges.insert(AddressRange(0x500, 0x5ff), 0x6);
|
||||
Ranges.insert(AddressRange(0x600, 0x6ff), 0x7);
|
||||
|
||||
Ranges.insert(AddressRange(0x150, 0x350), 0xff);
|
||||
EXPECT_EQ(Ranges.size(), 5u);
|
||||
EXPECT_EQ(Ranges[0].first, AddressRange(0x0, 0xff));
|
||||
EXPECT_EQ(Ranges[0].second, 0x1);
|
||||
EXPECT_EQ(Ranges[1].first, AddressRange(0x100, 0x3ff));
|
||||
EXPECT_EQ(Ranges[1].second, 0xff);
|
||||
EXPECT_EQ(Ranges[2].first, AddressRange(0x400, 0x4ff));
|
||||
EXPECT_EQ(Ranges[2].second, 0x5);
|
||||
EXPECT_EQ(Ranges[3].first, AddressRange(0x500, 0x5ff));
|
||||
EXPECT_EQ(Ranges[3].second, 0x6);
|
||||
EXPECT_EQ(Ranges[4].first, AddressRange(0x600, 0x6ff));
|
||||
EXPECT_EQ(Ranges[4].second, 0x7);
|
||||
|
||||
Ranges.insert(AddressRange(0x3ff, 0x400), 0x5);
|
||||
EXPECT_EQ(Ranges.size(), 4u);
|
||||
EXPECT_EQ(Ranges[0].first, AddressRange(0x0, 0xff));
|
||||
EXPECT_EQ(Ranges[0].second, 0x1);
|
||||
EXPECT_EQ(Ranges[1].first, AddressRange(0x100, 0x4ff));
|
||||
EXPECT_EQ(Ranges[1].second, 0x5);
|
||||
EXPECT_EQ(Ranges[2].first, AddressRange(0x500, 0x5ff));
|
||||
EXPECT_EQ(Ranges[2].second, 0x6);
|
||||
EXPECT_EQ(Ranges[3].first, AddressRange(0x600, 0x6ff));
|
||||
EXPECT_EQ(Ranges[3].second, 0x7);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue